Stripe idempotency key reuse: the capture that came back for the wrong amount because a key outlived its request
Problem
A payment reconciliation report flags captures for half the authorized amount — on orders where the full amount was authorized, held, and captured days later:
succeeded (but wrong): capture pi_3Pabc captured 2500 (expected 12500)
idempotent_replay: request matched Idempotency-Key idem_7f3a... from 2026-08-14T10:22:31ZNo exception was ever thrown. The capture succeeded. It just captured the wrong request's money.
Root cause
An idempotency key does not mean "this order" — it means "return the stored response of the first request that used this key," for 24 hours, regardless of what the body says. The code derived the key from the order id alone (idem_${orderId}), so a capture of $25.00 that used the key at 10:22 was followed, after a crash-restart, by a capture of $125.00 with the same key: Stripe matched the key, skipped the new request, and returned the stored response of the first one. The $125 capture never happened; the logs show two green API calls and one wrong amount.
This is the inverse of the more famous duplicate-charge bug (a key generated per retry attempt creating two charges): here the key is too stable, reused across semantically different requests. Both directions break; the rule that prevents both is the same.
import { createHash } from 'node:crypto';
function idempotencyKeyFor(order, action) {
… 13 more lines in the fix🔒 the fix — including 2 code blocks — is members-only. $1/mo unlocks everything.