System Design + Reliability
What are idempotency keys and why are they important?
Idempotency keys prevent duplicate side effects when clients retry requests. They are critical for payments, order creation, purchases, booking systems, and any API where running the same operation twice would be dangerous.
The Short Answer
An idempotency key is a unique value sent with a request so the server can tell whether this operation has already been processed.
If the same request is retried with the same key, the server should not perform the side effect again. It should return the previously stored result.
idempotent: Describing an action which, when performed multiple times, has no further effect on its subject after the first time it is performed.
The Real Problem
Distributed systems fail in annoying ways. A client may send a request, the server may process it successfully, but the response may never make it back to the client.
From the client's point of view, it looks like a failure. But from the server's point of view, the operation already happened.
Since the client thinks the request failed, it retries the request. Without protection, the server may process the operation again. In a payment system, that could mean double-charging the customer.
The solution is to attach an idempotency key to the operation. When the retry arrives with the same key, the server recognizes that the request was already processed and returns the original result instead of performing the operation again.
Without Idempotency
Client sends payment request
Server charges card
Network timeout hides response
Client retries and card is charged again
Payment Example
Imagine this request:
POST /payments
Idempotency-Key: pay_8f7a9c2
{
"customerId": "cust_123",
"amount": 100,
"currency": "USD"
}The server should store something like:
idempotency_key: pay_8f7a9c2
request_hash: hash(customerId + amount + currency)
status: SUCCESS
response: { "paymentId": "pmt_456", "status": "charged" }If the client retries with the same key, the server does not charge the card again. It returns the stored response.
With Idempotency
Client sends request with key
Server processes payment once
Response is stored with key
Retry returns same result, no double charge
Order Creation Example
Idempotency is not only for payments. It is also useful for order creation.
POST /orders
Idempotency-Key: order_abc123
{
"userId": "u1",
"sku": "laptop-13",
"quantity": 1
}Without idempotency, a retry could create two orders, reserve inventory twice, send two confirmation emails, and confuse customer support.
With idempotency, the server can say: “I have already processed order_abc123, so I will return the original order instead of creating another one.”
When It Is Absolutely Critical
Idempotency becomes critical when repeating an operation causes a real-world side effect.
Payments
Without it: Customer gets charged twice.
With it: Retry returns the original payment result.
Orders
Without it: Two orders are created for one checkout.
With it: Retry returns the original order.
Ticket or hotel booking
Without it: Seat or room may be reserved twice.
With it: Retry confirms the original reservation.
Stock purchase
Without it: A stock order may execute twice, causing duplicate purchases and double deduction from available trading funds.
With it: Retry returns the original purchase result instead of placing a second order.
Money transfer
Without it: Sender may lose money twice.
With it: Retry returns the original transfer status.
How the Server Usually Handles It
A common implementation is to store the idempotency key before or during request processing.
1. Receive request with Idempotency-Key
2. Check if key already exists
3. If key exists, return stored response
4. If key does not exist, reserve/store the key
5. Process the operation
6. Store final status and response
7. Return response to clientThe important part is that checking and reserving the key must be atomic. Otherwise, two duplicate requests could race each other and both get processed.
In many systems, idempotency keys are stored in a fast shared data store such as Redis or a database table. In a Spring Boot application, this logic is often implemented using a service layer together with distributed caching or persistent storage.
The important part is not just storing the key. The check-and-store operation must be atomic. Otherwise, duplicate requests could race each other and both get processed.
Important Design Detail: Same Key, Different Payload
A client should not reuse the same idempotency key for a different operation.
For example, this should be treated as suspicious:
First request:
Idempotency-Key: abc123
amount: 100
Second request:
Idempotency-Key: abc123
amount: 500A good system stores a hash of the original request payload. If the same key is reused with different parameters, the server should reject it instead of guessing what the client meant.
Where Idempotency Keys Are Useful
- Payment APIs
- Order creation
- Money transfers
- Inventory reservation
- Ticket booking and hotel booking
- Webhook processing
- Message consumers that may receive duplicate events
- Account creation or subscription creation
- Cloud resource provisioning
Common Interview Follow-Ups
Is an idempotency key the same as a request ID?
Not exactly. A request ID usually identifies one attempt. An idempotency key identifies the logical operation across retries.
Should the client or server generate the key?
Usually the client generates it for the operation it wants to retry safely. The server stores and enforces it.
How long should keys be stored?
It depends on the business. Payment systems may keep them long enough to cover realistic retry windows. Other APIs may use shorter TTLs.
Does idempotency mean no failures happen?
No. It means retries do not accidentally repeat the side effect.