Duplicate requests aren’t edge cases - they’re normal behavior in distributed systems.
A client times out, retries, and suddenly your API creates:
two payments
two orders
two subscriptions
Idempotency keys exist to prevent that. But many implementations still fail under real conditions.
The Problem
Consider POST /payments :
Server processes the payment
Response is lost (timeout, network issue)
Client retries
Without idempotency, the retry looks like a new request → duplicate charge.
The Assumption That Breaks
A common approach is:
“Store the idempotency key and reject duplicates.”
This sounds correct—but it’s not.
Two concurrent requests can both:
check for the key
see nothing
execute the side effect
Result: duplicates still happen.
What Actually Works
Idempotency is not just storing keys - it’s about ownership of execution .
The critical rule:
Only one request must be allowed to perform the operation.
This requires an atomic reservation , typically:
SQL: unique constraint + INSERT…