Mutations & Idempotency
Every write accepts an Idempotency-Key. Replay semantics, response shapes, bulk thresholds.
The Idempotency-Key header
Every write endpoint accepts an Idempotency-Key header.
POST /v2/partner/contacts
Authorization: Bearer <token>
Idempotency-Key: 47f8e2c0-4f9e-4f9c-9d2b-1a2b3c4d5e6f
Content-Type: application/json
{ "email": "...", "phone": "..." }
→ 201 Created
{ "id": "...", "email": "...", ... } Semantics
- Key is client-generated. UUID v4 recommended; any opaque string ≤ 128 chars accepted.
- Server stores
(endpoint, idempotency_key, request_body_hash, response)for 24 hours. - Replay with same key + same endpoint + same body hash → returns the cached response (201/200, with
X-Idempotent-Replay: trueheader). - Replay with same key + same endpoint + DIFFERENT body →
409 idempotency_conflictwith the diff. - Same key on different endpoint → no collision; key is scoped per-endpoint.
- Key with no prior store → fresh execution.
Mutation response shapes
| Status | Meaning | Body |
|---|---|---|
201 Created | New resource | Full created resource |
200 OK | Update succeeded | Full updated resource |
202 Accepted | Async operation (bulk, batch) | Operation-tracking ID |
204 No Content | Delete succeeded | (no body) |
Bulk mutations
Bulk mutations land on POST /v2/<surface>/<resource>/batch and return 202 Accepted with a Batch reference. See Batch Lifecycle for the full contract.
Operations that affect more rows than an endpoint's bulk threshold also require the bulk override flag. See Override Flags.
Validation errors — multiple per response
Validation failures return multiple errors entries, one per field:
{
"errors": [
{
"code": "validation_failed",
"title": "Field is required",
"detail": "name must be present",
"source": { "pointer": "/data/attributes/name" }
},
{
"code": "validation_failed",
"title": "Invalid format",
"detail": "email must be a valid email address",
"source": { "pointer": "/data/attributes/email" }
}
]
} Cross-cutting: when to use Batch instead
Use a single mutation endpoint when you have one row and want a synchronous typed response. Use the Batch surface when you have many rows, want async processing, and need a per-row error report. The POST /v2/<surface>/<resource>/batch endpoint is the synchronous shortcut for ≤1000 rows; for larger workloads pass a signed_url, s3, or sftp source via POST /v2/batch/operations.