Send an Idempotency-Key header on writes. Retrying with the same key replays the first response instead of acting a second time.
bash
curl -X POST https://your-site.awrora.app/api/v1/bookings \
-H "Authorization: Bearer aur_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c1e0a-9c2b-4a10-8f7e-3f0b5d1c2a44" \
-d '{ … }'The key is any string of 8–200 characters; a UUID per logical operation is the right choice. It is scoped to the organisation and the API key, and bound to the route and the exact request body for 24 hours. Another key reusing the same string is treated as a different body.
Where it is required#
| Endpoint | Idempotency-Key |
|---|---|
POST /v1/bookings | Required |
POST /v1/bookings/{id}/cancel | Required |
Every other POST and PATCH | Optional, honoured when sent |
GET, DELETE | Ignored |
It is required on the two that spend something real — a duplicated booking takes a seat from a guest who could have had it, and there is no way for us to tell a retry from a genuine second booking without the key. Missing the header where it is required is 400 idempotency_key_required.
Replays#
A replayed response is byte-for-byte the first response, including its status code, plus one header:
http
Idempotent-Replayed: trueSo a client that timed out on a 201 gets that same 201 and the same booking — not a second booking, and not an error it has to special-case.
The four outcomes#
| Situation | Response |
|---|---|
| First request with this key | Runs normally |
| Same key, same body, first one finished | The stored response + Idempotent-Replayed: true |
| Same key, different body, first one finished | 422 idempotency_key_reused |
| Same key, first one still running — whatever the body | 409 idempotency_in_progress — retry shortly |
It is not a transient error. Reusing a key for a different request would make the second one silently disappear. Generate a new key per operation.
What is not stored#
A 5xx, or a request that crashed, releases the key — otherwise a transient failure would burn it for 24 hours and every retry would replay the same error. Retry a 5xx with the same key.
A 4xx is stored. 409 insufficient_capacity is an answer to your question, and a retry should get the same answer rather than suddenly succeeding because somebody else cancelled. To try again after a 4xx, fix the request and use a new key.