Idempotency
Retries are a fact of life in distributed systems. Idempotency keys let you retry POST and PATCH without risking double-writes.
How to use it
Send an Idempotency-Key header on any POST or PATCH. Any opaque string up to 255 characters works; a v4 UUID is the conventional choice.
curl -sS -X POST https://alltogether.giving/api/v1/donors \
-H "Authorization: Bearer pc_your_key_here" \
-H "Idempotency-Key: 8f3b1c0a-1d5e-4c9a-9b3f-2d0e1a4b5c6d" \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com","first_name":"Alice"}'Generate one key per logical operation. Reuse the same key when you retry after a network error, a 5xx, or a timeout.
Replay semantics
Same key, same request body, within 24 hours:
- We serve the original response, byte for byte.
- Replays carry an
Idempotent-Replayed: trueheader so you can tell them apart from fresh writes. - The handler does not run a second time.
Same key, different body:
409 idempotency_conflict. Pick a new key for the new operation.
Same key, while the original is still running:
409 conflictwith the message "Idempotency-Key is still being processed by a concurrent request". Wait and retry.
What gets replayed
- Only 2xx, 3xx, and 4xx responses are cached.
- 5xx responses are not cached. The reservation is released so the next retry runs fresh.
- If the handler throws unexpectedly, the reservation is also released.
- Response bodies over 256KB are not cached; the reservation is released and a retry runs fresh. Request bodies over 1MB get
400 invalid_request.
Scope of a key
Each Idempotency-Key record is scoped to the tuple of:
- organisation,
- the API key making the request,
- endpoint (
METHOD path, e.g.POST /donors).
Reusing the same string across different API keys or different endpoints is not a conflict: each tuple has its own record. Reusing within the same tuple is what triggers the replay or conflict path.
TTL
Records live for 24 hoursfrom first use. After that, the slot is reclaimed and the same key can be used again. Expired records are deleted lazily on access, so you don't need to do anything to free them.
Endpoints that benefit most
POST /recommendation-sets: avoid creating duplicate sets when a retry follows a timeout.- Any future
POSTorPATCHthat writes a record or fires an external side effect. Add the header pre-emptively; read-only endpoints ignore it harmlessly.
Related
- Error envelope and codes: the shape of
conflictandidempotency_conflict. - Rate limits: handle
429and retry with the sameIdempotency-Key.