Idempotency #
HTTP clients and agent frameworks retry on timeout by default. A retried POST /transaction/{id}/post must not post the same entry twice to a ledger that can only be corrected with a contra document. Send an Idempotency-Key header with any write, and the API answers a retry with the original response instead of doing the work again.
curl -X POST https://api.microbooks.io/books/v1/transaction/42/post \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: 6b0f6c1e-3f6c-4b8e-9a1d-7d2f0f3a9c11"
Generate a new key, such as a UUID, for every distinct operation, and reuse it only when retrying that same operation.
Behaviour #
| Situation | Result |
|---|---|
| First request with a key | Runs normally; a successful response is stored |
| Retry with the same key and the same body | The stored status and body are returned unchanged, with Idempotent-Replayed: true. Nothing is done again |
| Same key, different body | 422 with errors.idempotency_key. Use a new key for a new request |
The first request failed (4xx/5xx) | Nothing is stored, so a corrected retry under the same key runs normally |
Dry run (rollback header) | Never stored or replayed |
| Concurrent duplicates | The second waits for the first to finish, then receives its response |
- Scope. A key is scoped to your user, the HTTP method and the path. The same key on two different routes is two independent requests.
- Lifetime. Keys are kept for 24 hours (
conventions.idempotency_ttl_hoursin/meta). A retry after that runs as a new request. - Format. 1 to 255 visible ASCII characters. Anything else is a
422. - Reads.
GETrequests ignore the header.
A retry recipe #
- Create a key before the first attempt and keep it with the operation.
- On a timeout, a connection error or a
5xx, retry with the same key and the same body. - On
Idempotent-Replayed: true, treat the response as the outcome of the first attempt. - On a
4xx, fix the request. You may keep the key, since failed attempts are not stored.