← Stackzilla Blog

Idempotency Keys: Making Retries Safe for Important Actions

Published October 25, 2026 · 3 min read · API design, distributed systems, payments, reliability

Prevent duplicate orders and repeated side effects by treating retries as part of your API contract rather than an exceptional case.

A customer clicks once, the server creates an order, and the response disappears on the network. The client cannot tell whether the operation succeeded. Retrying may create a second order; refusing to retry may leave the customer unsure whether anything happened. This is not an unusual failure. It is a normal consequence of communicating across a network. An idempotency key gives the client and server a shared identity for one intended operation. ## One intent gets one stable key The client creates a key before sending the action and reuses it for retries of that same action. A new purchase or a deliberately repeated task needs a new key. Generating a fresh key for every retry defeats the mechanism. Scope the key to the authenticated account and operation. Store a fingerprint of the validated request alongside it. If the client reuses a key with a different payload, return a clear conflict rather than silently treating a new action as the old one. The server also needs a documented retention policy. A key that expired last week cannot necessarily protect a request retried today. Clients should understand how long replay protection lasts. ## Coordinate the key and the side effect A simple check-then-insert is vulnerable to concurrent requests. Two servers can both observe that a key is absent before either records it. Use a database uniqueness constraint and a transaction or another atomic coordination mechanism. For work contained in one database, record the operation and its business changes together. Track whether the request is in progress, completed, or recoverably failed. Define what a concurrent retry receives instead of making it guess. External effects require more care. A local transaction cannot atomically commit a payment provider's database. Pass an appropriate idempotency key to the provider where supported, persist the provider reference, and reconcile uncertain outcomes. Sending an email and then crashing before marking completion can otherwise produce duplicates. ## Return the outcome consistently Store enough response information to give a retry the original result or a stable reference to it. Do not turn a successfully created order into an unrelated error simply because the client needed to ask twice. Test simultaneous requests, a lost response after commit, a worker crash, key expiration, and mismatched payloads. These cases reveal flaws that happy-path tests miss. Idempotency does not mean every line of code executes exactly once. It means repeated attempts at the same business intent do not create repeated business effects. That is the guarantee users actually need. ## Further reading - [Stripe: Idempotent requests](https://docs.stripe.com/api/idempotent_requests) - [AWS Builders' Library: Making retries safe](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/)

Read the full article on Stackzilla →