Idempotency and retries

Play this lesson

Did it go through?

A player taps Buy for 500 gems. The network drops before the answer arrives. Did it work? If the app simply tries again, the player might pay twice, and Theo would find two charges in the payment report.

An operation is idempotent if doing it twice has the same effect as doing it once.

Idempotency keys

Stripe's API lets the app send a unique key with a request, in an Idempotency-Key header. Stripe saves the result of the first request with that key, and "Retries with the same key return the saved response".

Stripe suggests random IDs (version 4 UUIDs), and never personal details, as keys.

Quick check

The app retries a purchase with the same idempotency key. What does Stripe do?

  1. Returns the first request's saved result instead of charging again
  2. Charges the player again
  3. Refuses every retry
Show the answer

Returns the first request's saved result instead of charging again

The key tells Stripe this is the same request. It answers with what happened the first time.

Some requests already are

Stripe's docs say GET and DELETE requests "are idempotent by definition", so keys are for POST requests. Reading a garden twice changes nothing, and deleting it twice still leaves it deleted.

Keys do not last forever: Stripe can remove them once they are at least 24 hours old.

Retry politely

Marc Brooker at AWS describes exponential backoff: wait longer after each failed try, multiplying the wait each time. Adding jitter, a random amount, spreads the retries out.

Without it, thousands of phones that failed at the same moment retry at the same moment, and fail again.

Quick check

Stripe keeps every idempotency key forever.

Show the answer

False

Keys can be removed once they are at least 24 hours old. A reused key after that counts as a new request.

Bug hunt

shop.js
async function buy(item) {  let tries = 3;  while (tries--) {    const key =      crypto.randomUUID();    const r = await      api.buy(item, key);    if (r.ok) return r;  }}

A slow purchase may charge the player up to three times. Which line of Remy's code is the bug?

  1. Line 4: a new key for every try, so each retry looks like a new purchase
  2. Line 3
  3. Line 8
Show the answer

Line 4: a new key for every try, so each retry looks like a new purchase

Make the key once, before the loop, and send the same key on every try.

Too many retries

Retries are good until one broken app sends a thousand a second. Then the server needs a way to say "slow down".

Bolt says: Next: rate limiting.

Fact-checked 12 October 2026