Back to Notes
API Design• Updated: 2026-05-14
Designing Idempotent APIs
The Network is Unreliable
In distributed systems, a network timeout does not mean the request failed. If a client sends a POST /charge request and the connection drops, the client doesn't know if the server charged the credit card or not. If the client retries, the user might be double-charged. This is why financial and state-mutating APIs must be Idempotent.
Idempotency Keys
The standard solution (popularized by Stripe) is for the client to generate a unique UUID for every operation and pass it in a header, e.g., Idempotency-Key: <UUID>.
The server flow looks like this:
- Extract the Idempotency Key from the request header.
- Check the database (or Redis) to see if this key has already been processed.
- If YES: Return the cached HTTP response from the original successful request.
- If NO: Acquire a distributed lock on the Idempotency Key to prevent concurrent retries from processing simultaneously.
- Process the business logic (e.g., charge the card).
- Save the result to the database mapped to the Idempotency Key, and return the response.
Always enforce an expiry (e.g., 24 hours) on Idempotency Keys so your cache does not grow infinitely.