Idempotency definition
Idempotency is the property of an operation that produces the same result no matter how many times it is performed with the same input. In APIs and distributed systems, idempotent operations let clients safely retry after timeouts or network failures without causing duplicate effects, such as charging a customer twice or creating two identical orders.
Why idempotency matters
Networks fail in ambiguous ways. A mobile app sends a payment request, the server charges the card, and the response is lost when the phone switches from Wi-Fi to mobile data. The app cannot tell whether the charge happened, so it retries. Without idempotency, the customer pays twice. With it, the server recognizes the retry and returns the original result instead of charging again.
The same problem appears wherever messages are retried: webhooks delivered twice, queue consumers restarting mid-task, users double-clicking a submit button and background jobs rerun after a crash. In distributed systems retries are unavoidable, so the only safe design is to make repeated operations harmless.
Idempotent HTTP methods
HTTP defines GET, HEAD, PUT, DELETE and OPTIONS as idempotent. Reading a resource twice changes nothing, putting the same full representation twice leaves the same state, and deleting something already deleted leaves it deleted, even if the second call returns 404. POST is not idempotent by default, because each call usually creates something new, and PATCH may or may not be, depending on the change it applies.
Idempotent is not the same as safe. GET is safe because it should not change anything; DELETE is idempotent but clearly not safe. Designing REST APIs that respect these semantics lets caches, proxies and client libraries retry correctly without special knowledge of your endpoints.
How idempotency keys work
For operations such as payments and order creation, APIs accept an idempotency key: a unique value, typically a UUID like those from our UUID generator, created by the client and sent in a header. The server stores the key with the result, and if the same key arrives again it returns the stored result instead of repeating the work. Stripe popularized the pattern, and many payment and messaging APIs now support it.
- Generate the key once per user action on the client and reuse it for every retry of that action
- Store the key, a hash of the request body and the response in a durable table with a unique constraint
- Handle concurrent duplicates with a lock or the unique constraint so only one request does the work
- Reject a reused key that arrives with a different request body
- Expire keys after a sensible period, such as 24 hours or a few days
Idempotent consumers and background jobs
Queue consumers and background jobs need the same discipline. Record processed message or event IDs, use database upserts instead of blind inserts, and express state changes as set the status to shipped rather than add one shipment. Natural business keys, such as an invoice number or an external payment ID with a unique index, often provide idempotency without extra tables.
Nexzem builds payment and order flows with idempotency keys and idempotent consumers from the start, because retrofitting them after the first double charge or duplicate shipment is far more expensive, and far more embarrassing, than designing them in.