Idempotency Key
An idempotency key is a client-supplied unique value that lets a server dedupe retried requests so an operation applies exactly once. It makes state-changing endpoints like payments safe to retry, but requires atomic key storage and careful concurrency handling.
An idempotency key is a unique value a client attaches to a request so the server can recognize retries of the same operation and apply it only once. It solves a core problem of unreliable networks: when a client does not receive a response, it cannot tell whether the request succeeded, and a naive retry might create a duplicate — a second charge, a duplicate order, a doubled transfer.
How It Works
The client generates a unique key (commonly a UUID) per logical operation and sends it, typically in an Idempotency-Key header. On first receipt the server processes the request, stores the key together with the result, and returns the response. If a request arrives with a key the server has seen, it skips reprocessing and returns the stored response instead of executing the side effect again. Keys are scoped per endpoint/account and expire after a window (often 24 hours).
Implementation requires care: the server must record the key and result atomically with the operation (often in the same database transaction) to avoid races where two concurrent retries both execute. A status field (in-progress/completed) and a lock prevent concurrent duplicates. The key should map to a specific request payload; reusing a key with a different body should be rejected.
When to Use It
Use idempotency keys on any non-idempotent, state-changing endpoint that clients may retry — payments, order creation, money transfers, account provisioning. They are essential when delivery guarantees are at-least-once (message queues, webhooks) or when mobile/flaky clients auto-retry. Stripe, PayPal, and most payment APIs require them. Naturally idempotent operations (PUT replacing a resource, GET) do not need them.
Trade-offs
The server must persist keys and results, adding storage and a lookup on every request, plus a retention/expiry policy. Concurrency handling is subtle — getting the atomicity wrong reintroduces the very duplicates the pattern prevents. Clients must generate stable keys per operation (not per retry) and reuse the same key across retries, which requires discipline. The pattern guards a single endpoint; multi-step workflows still need sagas for end-to-end consistency.
Related Patterns
Idempotency keys complement the retry pattern by making retries safe, and the circuit breaker by allowing aggressive client retries. The outbox pattern ensures reliable event publishing alongside the idempotent write. In distributed workflows, sagas coordinate multiple idempotent steps and their compensations.
Example
POST /v1/charges
Idempotency-Key: 8f2b1c9e-1d2a-4e6f-9a7b-7c5d3e1f0a42
Content-Type: application/json
{ "amount": 5990, "currency": "usd", "source": "tok_visa" }
If the client times out and resends the same key, the server returns the original charge result instead of charging the card twice.