Idempotency keys
Make retries safe with the Idempotency-Key header.
Send an Idempotency-Key header on any non-GET request you might retry. If the network drops a reply, you resend the same request with the same key and get the stored response back instead of a second write.
The key is fingerprinted against the method, path and body. Same key, same request, the api replays the stored response. Same key, different body, it answers 422 idempotency_key_reused.
curl -X POST http://127.0.0.1/api/conversations \
-H 'content-type: application/json' \
-H 'authorization: Bearer fk_<key>' \
-H 'idempotency-key: 9a1c2b3e-4d5f-4a6b-8c7d-9e0f1a2b3c4d' \
-d '{"channel_id":"<channel-id>","body":"Where is my order?"}'What the header does
| Situation | Answer |
|---|---|
| Same key, same fingerprint, already completed | The stored response body and status, replayed. |
| Same key, different body | 422 idempotency_key_reused. |
| Same key, first request still running | 409 idempotency_key_in_flight with Retry-After: 1. |
| The request answered 5xx | The reservation is released, so a retry runs the work again. |
The reservation commits in its own transaction, so a concurrent retry sees the in-flight row rather than both requests winning. Keys are scoped to the tenant and the caller, so two callers who pick the same value do not collide. A completed row expires after 24 hours and the sweep reaps it.