POST and PATCH endpoints accept an Idempotency-Key header. If the
same key arrives twice within 24 hours, the second request returns the
cached response instead of running the operation again.
How it works
POST /api/v1/organizations/{org}/forms/{form}/records
Idempotency-Key: a96b7e7f-9c4a-4e3d-9e6a-9c8b... <- any unique string you generate
Content-Type: application/json
{ "created_by": "...", "field_values": { ... } }
If you retry the same request (network blip, redeploy mid-flight, queue
re-drive), send the same Idempotency-Key. The second response will be:
- Identical body to the first response
X-Idempotent-Replay: trueheader attached so you can detect it- Same status code (success only — see below)
What gets cached
- Successful responses (2xx) only. A failed
POSTis NOT cached; retry with the same key triggers the real operation again, which is what you want — the first attempt didn't take effect. - The response body is cached verbatim.
- Cache is scoped per-API-key. Two integrators can reuse the same opaque key string without colliding.
What rejects
If you send the same Idempotency-Key with a different request
body, you get 409 conflict. The server hashes the body bytes — even
whitespace differences trigger the conflict guard.
What to use as the key
- Anything opaque, ≤ 255 characters.
- A UUID is the canonical choice (
uuidgen,crypto.randomUUID()). - Tie it to your internal job/request id so retries from your queue carry the same value.
When to use it
- POSTs that create resources (records, report templates, webhook subscriptions, org members) — to avoid duplicate rows on retry.
- POSTs to action endpoints that have observable side effects
(
publish,merge,retry) — to avoid double-firing. - PATCHes — usually safe to retry, but adding the header gives you a guaranteed-stable response body.
For pure GET reads, idempotency keys are ignored.
Lifetime
At least 24 hours from the first request. A periodic cleanup job clears expired keys, so a key can keep replaying for a few hours past the 24-hour mark before a fresh POST with the same value runs the operation again.