Skip to content

Workspace API

Batch Writes

Write up to 100 workspace records per call with the /batch sibling endpoints.

Every workspace write has a batch sibling that applies up to 100 records in one call:

Endpoints
POST /workspace/accounts/upsert/batch
POST /workspace/accounts/delete/batch
POST /workspace/projects/upsert/batch
POST /workspace/projects/delete/batch
POST /workspace/contacts/upsert/batch
POST /workspace/contacts/delete/batch
POST /workspace/views/upsert/batch
POST /workspace/views/delete/batch
POST /workspace/views/{id}/records/add/batch
POST /workspace/views/{id}/records/delete/batch
POST /workspace/favorite-views/upsert/batch
POST /workspace/favorite-views/delete/batch

All of these cost 0 credits. Favorite batch routes require a user JWT.

Request body

Upsert batches take inputs, an array of 1-100 elements, where each element is exactly the corresponding single endpoint’s request body (same identifiers, same partial-update semantics):

POST /workspace/accounts/upsert/batch
{
"inputs": [
{ "account_id": "1c9e...", "icp_tier": "disqualified" },
{ "match": { "domain": "acme.example" }, "icp_tier": "tier_1", "tags": ["hot"] }
]
}

Delete batches take ids, an array of 1-100 record UUIDs (note the verb: batch deletes are POST with a body, unlike the single DELETE /{id}):

POST /workspace/accounts/delete/batch
{ "ids": ["1c9e...", "2d0f..."] }

Response: per-item results

Batch writes are never all-or-nothing. Valid records apply; each failed record reports its own error. Results come back in input order:

{
"data": {
"results": [
{ "index": 0, "status": "ok", "record": { "account_id": "1c9e...", "icp_tier": "disqualified" } },
{ "index": 1, "status": "error", "error": { "code": "ambiguous_match", "message": "Domain 'acme.example' matches more than one account; pass account_id instead." } }
]
},
"metadata": { "credits": 0, "succeeded": 1, "failed": 1 }
}

Item errors reuse the single-endpoint codes: bad_request (malformed record or missing identifier), not_found (a match that resolves to nothing), ambiguous_match (a match that resolves to more than one record). Retry just the failed indexes.

A batch-level 400 occurs only for envelope problems: an empty array, more than 100 elements, or a malformed body. In that case nothing is applied. Envelope failures are rejected by request validation, so the response carries the request-validation error shape described in Errors, not the { "error": { "code", "message" } } envelope.

Semantics

  • Records apply sequentially in input order. If one batch targets the same record twice, the later element wins, exactly as two single calls would.
  • Batch deletes are idempotent per item: an id that is not in your book still reports ok.
  • Setting icp_tier in an account batch schedules one atlas recompute covering every touched account.
  • An upsert item that writes successfully but whose row cannot be read back (a narrow concurrent-delete window) still reports status: "ok", with a minimal record carrying just the resolved id. The single-record endpoints return data: null in the same situation.