I recommend idempotency for every path where retries can create real damage. Payments, orders, emails, and inventory reservations should survive duplicate requests without duplicate business effects.
The key is part of the contract
When I talk about "The key is part of the contract", I am really asking what Idempotency does when a message is late, duplicated, or missing.
An idempotency key lets the server recognize that a retry is the same business attempt. The server stores the first result and returns it again instead of performing the action twice.
Payment request example
I use "Payment request example" to keep Idempotency grounded in a real system, because abstract patterns are too easy to agree with and too hard to operate.
A mobile app sends a payment request and loses the response. It retries with the same idempotency key. The payment service finds the original result and returns the receipt.
Idempotent write code
When I show "Idempotent write code", I want the code in Idempotency to reveal the production decision, not just the syntax.
Store the first result and return it for the same business attempt:
Receipt charge(String idempotencyKey, ChargeRequest request) {
return receipts.computeIfAbsent(
idempotencyKey,
key -> paymentGateway.charge(request));
}
The idempotency key makes retries safe: the first request creates the charge, and later requests with the same key return the saved receipt instead of charging again.
Sequence diagram: retry without double charging
The retry is safe because the server recognizes the business attempt, not just the network request.
The duplicate policy
- Choose keys from the client workflow, not random server calls.
- Store enough response data to answer retries consistently.
- Expire keys only after the business risk window is closed.