The Recovery Ledger · 2026-07-11 · 6 min
Stripe decline codes, explained for recovery (not just debugging)
Decline codes usually get read by engineers debugging checkout. Read them as a revenue operator instead: each code tells you whether a retry can work and what the recovery email should say.
expired_card
Retries: pointless the number fails forever. Recovery: guaranteed possible; the customer has a newer card. Email should say exactly that ('your card on file expired') with the update link. Better: warn before expiry and skip the failure.
insufficient_funds
Retries: often work Smart Retries time them around paydays. Recovery email: gentle, no-blame, 'the invoice link retries whenever you're ready.' Most of these self-heal; the email is there for the ones that don't.
do_not_honor
The bank's 'no, and we won't say why.' Retries sometimes work (it can be a temporary risk flag). Email: generic-decline copy suggesting the customer try the card again or use another and to call the bank if it persists. Never guess at the reason in your copy.
card_declined / generic_decline
The catch-all. Treat like do_not_honor: one retry cycle, then human email with the hosted invoice link. If the same customer hits this repeatedly across months, the card is effectively dead say so kindly.
Why per-code copy is worth it
One-size dunning copy reads wrong for somebody: 'your bank declined the charge' insults the expired-card customer; 'your card expired' confuses the insufficient-funds one. Recoupe generates a variant per decline reason automatically (AI-drafted, cached, fully editable), so every email matches reality.
Recoupe recovers the revenue your processor's retries leave behind $29/mo, honest attribution.
Run my free failed-payment audit →