A reference table for sizing what's actually recoverable in your failed-payment data. Recovery rates are aggregate estimates; absolute numbers vary 20–30% based on customer geography, card-issuer mix, and plan tier.
Stripe returns hundreds of distinct decline codes. The ten below cover ~90% of the volume on a typical B2B SaaS Stripe account. The others are either rare or genuinely unrecoverable (e.g. fraudulent when the issuer flags real fraud).
| Code | Frequency | Retry rate | + Customer flow | Best action |
|---|---|---|---|---|
insufficient_funds |
~25–35% | ~70% | ~75% | Retry at 24h + 72h. Email if still failing. |
expired_card |
~20–30% | ~5% | ~85% | Card-update email immediately. Don't waste retries. |
generic_decline |
~10–15% | ~25% | ~40% | Retry once at 24h. Then email customer to contact issuer. |
do_not_honor |
~8–12% | ~30% | ~50% | Issuer-side block. Retry at 24h + 7d. Customer needs to call issuer. |
card_velocity_exceeded |
~3–6% | ~10% | ~55% | Issuer rate-limit. Wait 24h, retry once. |
incorrect_cvc |
~2–4% | ~5% | ~70% | Prompt customer to re-enter CVC. Don't retry without input. |
fraudulent |
~2–4% | ~5% | ~30% | Manual review. Don't auto-retry — increases fraud signal at issuer. |
processing_error |
~1–3% | ~80% | ~85% | Stripe-side transient. Retry at 1h. |
card_not_supported |
~1–2% | ~10% | ~60% | Customer needs different card type. Email with PayPal/ACH alternative. |
currency_not_supported |
<1% | ~5% | ~40% | Customer's card can't pay your currency. Offer regional payment method. |
The "Retry rate" column shows what percentage of failures recover with retries only — no customer email, no card-update flow. For codes like expired_card, that's ~5% (a card occasionally un-expires when the customer's issuer renewed it without them noticing). The "+ Customer flow" column shows the recovery rate when you ALSO email the customer with a card-update link.
The gap between "Retry rate" and "+ Customer flow" is the dunning opportunity. For a Stripe account with $20k/month of failed charges:
This is why dunning tools that include customer-facing flows charge $99–$299/month — the math works at almost any scale above $10k/month of failed charges.
Beyond "retry yes/no," the timing of the retry matters more than most teams realise. Three rules of thumb that show up consistently in the recovery data:
card_velocity_exceeded) which actively hurt your recovery on subsequent attempts.Stripe Dashboard → Payments → filter by Status: Failed → Export to CSV. Run the DunningKit CLI on the export:
$ pip install dunningkit
$ dunningkit analyze stripe-failed-charges.csv
Period: 2026-04-01 to 2026-04-30
Failed charges: 142 totalling $14,820
Decline-code breakdown:
insufficient_funds 38 charges $3,940 ~$2,955 recoverable
expired_card 31 charges $3,210 ~$2,729 recoverable (with card-update flow)
...
Total recoverable potential: ~$8,400 (57%)
The free CLI returns the breakdown above for any CSV. If the recoverable number looks meaningful, the rest of the toolkit (retry sequences, customer flows, SMS escalation) is on the way.