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: true header).
  • Replay with same key + same endpoint + DIFFERENT body409 idempotency_conflict with the diff.
  • Same key on different endpoint → no collision; key is scoped per-endpoint.
  • Key with no prior store → fresh execution.

Mutation response shapes

StatusMeaningBody
201 CreatedNew resourceFull created resource
200 OKUpdate succeededFull updated resource
202 AcceptedAsync operation (bulk, batch)Operation-tracking ID
204 No ContentDelete 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.