Most SaaS founders set up Stripe, turn on Smart Retries, and never look at decline codes again.
That's leaving a lot of money on the table.
Here's what's actually in those codes - and what each one is telling you to do.
Every failed payment falls into one of two buckets.
The customer has money. The card is valid. Something temporary got in the way.
No retry will ever fix these. The customer needs to do something.
For these, you need to send a message. The right message, for the exact reason.
Some codes are genuinely ambiguous - and this is where most dunning logic breaks down.
do_not_honor is the classic example. It looks temporary. It often isn't. Issuers use it as a catch-all for a dozen different situations, and retry logic handles it poorly.
The practical fix: treat do_not_honor as a soft Bucket 2. Send a gentle message first, retry once, then escalate communication if unresolved.
card_velocity_exceeded is similar - looks like a fraud flag, but often the customer just hit their daily limit. Day 1 outreach with a clear explanation converts well here.
fraudulent - do not send anything. Ever.
If Stripe has flagged a payment as fraudulent, reaching out to that customer can cause more harm than the lost revenue. This is the one case where silence is the right answer.
Most dunning setups apply the same retry cadence to everything. That's why recovery rates stay low.
The founders who crack this treat each decline code as a different diagnosis — not just a failed payment.
Do you actually look at your decline code breakdown? Or is it mostly set-and-forget?
(Building DunnAI — it reads every decline code and sends the right response automatically. Free diagnostic at getdunnai.com)