Skip to main content

Idempotency

Written by Support

Every POST, PATCH, and DELETE requires an Idempotency-Key header. PUT accepts the header too: with a key it follows the rules on this page, and without one the request runs every time it is sent.

Idempotency-Key: order-create-2026-04-30-abc123

Format: 1 to 64 chars, [A-Za-z0-9_-:.].

Use a stable, unique value per logical operation (e.g., a UUID generated client-side).

Where replay actually happens

Replay happens on the platform itself, so https://api.dzbuild.app/v1 and the dzbuild.com/api/v1 alias behave the same. A stored response is kept for 24 hours and replays come back with Idempotency-Replay: 1.

A retried POST /v1/orders with the same key and the same body gets the first response back instead of creating a second order, whichever host you call.

The cache is scoped to your key_id plus the Idempotency-Key: the same value sent under a different API key does not deduplicate.

POST /v1/signups and POST /v1/events still require the header, but they are accepted asynchronously and their responses are never stored: no replay cache protects those two routes.

POST /v1/keys and POST /v1/webhooks return a secret that is shown only once, so their responses are never stored either. A retry with the same key runs the call again and can create a second key or a second webhook. Check GET /v1/keys or GET /v1/webhooks before you retry one of them.

⚠️ Warning — Idempotency protects against retries, not races

The response is stored only once the first request has finished, so two genuinely simultaneous duplicate requests can still both execute. Serialize duplicate-prone writes on your side.

Keys are bound to the request body

A key belongs to the first request that used it: its method, its path and its body. The query string is not part of the comparison. Reusing a key with a different body, path or method answers 422 with the code idempotency_key_reuse and runs nothing. The body is compared byte for byte, so a retry must resend the exact bytes of the first attempt, not a copy rebuilt with a different field order or spacing. Generate one key per logical operation (a fresh UUID), never one per endpoint, per session or per day.

Errors are cached too

A 4xx returned for a write is stored and replayed for 24 hours. After fixing a validation error, send the corrected request with a new Idempotency-Key: the old key answers 422 idempotency_key_reuse for the changed body. Refusals that happen before your request reaches its handler are never stored, for example 401, the 403 answers for pilot enrollment, plan and app status, every 429, and a missing or malformed Idempotency-Key. A 403 for a missing scope comes from the handler, so it is stored like any other 4xx. 5xx responses are not cached and may be retried with the same key. See Errors.

Telling a replay apart from a fresh call

Branch on Idempotency-Replay: 1. A replay means no new side effect occurred, so skip any local post-processing you would run after a genuine write.

Don't confuse it with X-Cache, a separate GET-only header that always reads MISS.

Did this answer your question?