Glossary Term
Idempotency Key (Safe POST Retries)
An Idempotency-Key header lets a client safely retry a POST: the server stores the first result and replays it. Learn the protocol, edge cases and conflicts.
TL;DR:
POSTis not idempotent, so a retry after a timeout can create a duplicate. An idempotency key makes it safe: the client sends a unique key, the server stores the first result under it and replays that result on repeats.
An idempotency key is a unique identifier, sent in an Idempotency-Key header, that lets a server recognize repeated attempts at the same logical operation and execute it only once. It gives non-idempotent methods like POST the retry safety that idempotent methods like PUT have by definition.
The exchange
POST /v1/payments HTTP/1.1
Host: api.example.com
Idempotency-Key: 8e03978e-40d5-43e8-bc93-6894a57f9324
Content-Type: application/json
{"amount": 4200, "currency": "usd"}
The connection drops before the response arrives. The client retries with the same key and the server returns the stored response, not a second charge:
HTTP/1.1 201 Created
Content-Type: application/json
Idempotent-Replayed: true
{"id": "pay_123", "status": "succeeded"}
The Idempotent-Replayed header is a convention some APIs use, not part of the draft.
What the server has to do
- Look up the key before doing any work.
- If it is new, record the key with a fingerprint of the request, process it, and store the status and body.
- If it exists and the request matches, return the stored response.
- If it exists but the payload differs, reject it (the draft suggests
422). - If the first request is still running, reject with
409 Conflictrather than running twice.
Non-obvious facts
- Store the result, including failures. Stripe saves the status and body of the first request for a key, even if it was a 500. Re-running a failed operation under the same key would defeat the point.
- Keys expire. Stripe prunes keys after at least 24 hours; document your own retention so clients know how long a retry is safe.
- The check and the write must be atomic. A unique database constraint on the key, not a read-then-write, is what stops two concurrent retries from both proceeding.
- Scope keys per client. Otherwise one tenant’s key can collide with another’s or leak a stored response.
- The key identifies the operation, not the attempt. Generating a new key on every retry silently disables the protection.
Go deeper
Frequently asked questions
What is an idempotency key?
A unique value the client generates for one logical operation and sends in an Idempotency-Key header, so the server can recognize a retry and return the original result instead of doing the work twice.
Is Idempotency-Key a standard?
Not yet. It is an IETF Internet-Draft from the HTTPAPI working group and widely used in practice, with Stripe as the best-known implementation. RFC 9110 does not define it.
What should the server return if the same key arrives with a different body?
An error. The draft recommends 422 for a key reused with a different payload and 409 when the original request is still being processed.
Should I use a UUID?
A random UUID v4 is the usual choice. It must be unique per operation, not per attempt, and the client must reuse the same value on every retry of that operation.
Sources
Related
Idempotent
Learn what idempotent means in HTTP. Understand why GET, PUT, and DELETE are idempotent, why POST is not, and how idempotency affects API design.
HTTP POST Method: Complete Guide with Examples
Learn how the HTTP POST method works. Understand when to use POST requests, request bodies, form submissions, and API calls with practical examples.
HTTP PUT Method: Update Resources
Learn how the HTTP PUT method works, when to use PUT vs POST vs PATCH, and best practices for updating resources in REST APIs.
409 Conflict
409 Conflict means the request clashes with the resource's current state: duplicates, stale versions, locks. Use ETags and If-Match, and handle retries.