A single dropped connection can leave a payment request in an ambiguous state. Stripe's 2017 engineering post on API design lays out the mechanism it uses to keep that ambiguity from ever turning into a duplicate charge, and the mechanism that actually enforces it sits one layer below the header most developers read about.
Three ways a single charge request can fail
In a post published February 22, 2017, Stripe engineer Brandur Leach described three distinct failure points in any networked request: the client can fail to connect at all, the connection can drop while the server is mid-operation, or the operation can succeed while the response back to the client is lost. Each leaves the client uncertain about what happened, and that uncertainty is the entire problem idempotency exists to solve.
HTTP already handles part of this. Leach's post points out that PUT and DELETE are idempotent by definition under RFC 7231: calling them twice has the same effect as calling them once. A charge-creation endpoint is a POST, though, and POST carries no such guarantee. Retrying it blindly could mean charging a customer twice for the same order.
What the Idempotency-Key header actually does
Stripe's answer is a client-generated Idempotency-Key header attached to any mutating POST call. The client picks a unique value for one logical operation and sends it with the request. On the first attempt, Stripe processes the charge and stores the outcome, success or failure, against that key. On any retry with the same key, Stripe returns the stored result instead of running the charge again, including a stored 500 error if that's what happened the first time. The retry doesn't need to know which of the three failure modes occurred. It only needs to know that resending the same key is safe.
Retrying blindly still has a cost, though, which is why Leach's post also recommends exponential backoff, waiting roughly 2^n seconds after n failures, mixed with random jitter so that a large batch of clients recovering from the same outage doesn't retry in the same instant and re-trigger the outage. Stripe's own Ruby library implements this backoff-and-jitter retry loop automatically when a call carries an idempotency key.
Where the guarantee actually lives
Stripe's own post describes the header and the client contract but doesn't publish the database schema behind it. For that layer, the clearest public explanation comes from Leach's own follow-up personal writeup rather than an official Stripe disclosure: a Postgres pattern built around a unique constraint on the idempotency-key column. That distinction matters. What follows describes a widely used pattern inspired by Stripe's public design, not a confirmed detail of Stripe's production system.
The pattern works because a unique constraint gives the database, not the application code, the final word on which of two near-simultaneous requests wins. A technical breakdown of the mechanics describes the race concretely: two servers receive retries of the same request within milliseconds of each other and both attempt to insert a row for the same key. Only one INSERT can succeed. The other is rejected for violating the constraint, and that losing server then reads the winner's stored row and returns it instead of processing the charge a second time. The retry-safe behavior a client experiences at the API layer is really a write conflict resolved once, deterministically, at the storage layer.
What this means for anyone building on top of it
The practical upshot for integrators is that the API contract and the storage guarantee are two separate layers, and both matter. Sending an idempotency key with every mutating request is necessary but not sufficient on its own; it depends on the server enforcing that key with a constraint the database itself polices, not with an application-level check-then-write sequence that leaves its own gap for two requests to slip through at once. The two secondary writeups on this pattern independently flag the same two mistakes to avoid: don't build a key from a timestamp, since clock skew can produce collisions, and don't store the entire request body as the dedup record, since a normalized hash plus the minimum response state needed to replay is enough. Stripe's public documentation and Leach's own follow-up writing describe the shape of a reliable answer to a problem every payments integration eventually runs into: over an unreliable network, the only way to guarantee an operation ran exactly once is to make retrying it safe, then let one system, not the client, decide when it has already happened. Stripe's subsequent moves into adjacent infrastructure suggest the same reliability discipline extends well past card payments as the company's product surface grows.





Comments (0)
Please sign in to join the discussion.
No comments yet.
Be the first to share your perspective on this topic.