STANDARDwalkthrough
Idempotency Keys
A customer clicks 'Pay' and their browser hangs. They click again.
The payment service checks a PostgreSQL UNIQUE constraint on (merchant_id, idempotency_key) before processing. If the key exists, we return the original response without re-charging.
“Without protection, we just charged their card twice. Idempotency keys solve this: the client generates a UUID and attaches it to every charge request via the Idempotency-Key header.”
Why PostgreSQL UNIQUE instead of Redis dedup? Because the idempotency check and the transaction INSERT must be in the same ACID transaction.
If we checked Redis and then inserted into PostgreSQL, a crash between the two steps would either lose the idempotency record (double charge) or lose the transaction (phantom dedup). Stripe stores idempotency keys for 24 hours, long enough to cover client retries and short enough to bound storage growth.
At 10K TPS, that is of idempotency records, purged daily. The UNIQUE constraint lookup adds ~2ms per request via B-tree index scan.
Trade-off: 2ms extra latency per request, but zero double charges. At $50 average transaction, a single double charge costs more than a year of the 2ms overhead.