The Complete Guide to Stripe Dunning: How to Recover Failed Payments Before They Become Lost Revenue
Your Stripe account is probably recovering fewer failed payments than you think.
Not because Stripe is bad at retries. But because dunning — the process of recovering failed payments — is more than automatic retries. It's the right communication, at the right time, for the right reason. And Stripe's built-in tools only get you part of the way there.
This guide covers everything: what dunning is, how Stripe's native tools work, where they fall short, and how to build a process that consistently recovers 60–75% of failed payments instead of 20–30%.
What Is Dunning?
Dunning is the process of communicating with customers whose payments have failed, with the goal of recovering the payment and keeping the subscription active.
The term comes from 17th-century English — a "dun" was a creditor's agent sent to collect debts. The modern SaaS version is considerably less dramatic: it's usually a sequence of emails timed to payment failures, with a clear call to action (update your card, contact your bank, retry the payment).
Done well, dunning recovers the majority of failed payments before the customer ever realizes their subscription was at risk. Done poorly — or not done at all — it's the invisible tax on your MRR that compounds every month.
How Stripe's Built-In Dunning Works
Stripe provides two native tools for recovering failed payments: Smart Retries and automated billing emails.
Smart Retries
Smart Retries (part of Stripe's Revenue Recovery feature) uses machine learning to determine the optimal time to retry a failed charge. Instead of retrying on a fixed schedule, Stripe analyzes signals like time of day, card network patterns, and historical success rates to pick retry moments most likely to succeed.
How to enable it: Stripe Dashboard → Settings → Billing → Revenue Recovery → Smart Retries
By default, Stripe will attempt up to 4 charges over a configurable period (typically 7–28 days depending on your settings). After the final retry fails, the subscription moves to past_due or canceled status depending on your configuration.
Smart Retries recover a meaningful portion of failed payments — particularly for insufficient_funds failures where the customer's balance may recover within a few days. For other failure types (expired cards, do_not_honor), retries alone are less effective because the underlying issue hasn't changed.
Automated Billing Emails
Stripe can automatically send emails to customers when:
- A payment fails
- A payment is about to be retried
- A card is about to expire
- A subscription is cancelled due to non-payment
How to enable them: Stripe Dashboard → Settings → Billing → Customer emails
These emails are sent from Stripe, are Stripe-branded by default, and contain a hosted link for the customer to update their payment method.
They work. But they have significant limitations.
The Limits of Stripe's Default Dunning
Stripe's native tools are a good baseline. For most early-stage SaaS products, they're worth enabling. But they have three fundamental limitations that cap your recovery rate.
1. One message for all failure reasons
Stripe's automated billing emails are generic. They don't know — or at least don't act on — why the payment failed.
A customer whose card expired gets the same email as a customer whose bank blocked the charge. A customer who had a temporary insufficient funds issue gets the same email as someone who needs to update to a new card.
This matters because the right action is completely different depending on the failure code:
- card_expired → The customer needs to update their card. A friendly, friction-free update link is the right response.
- insufficient_funds → The customer's card works fine. They had a rough week. An urgent "update your payment method" email is tone-deaf — and might cause more damage than no email at all.
- do_not_honor → The bank blocked the transaction, often as fraud prevention. The customer needs to either call their bank or use a different card. Without that explanation, they have no idea what to do.
- card_declined → Generic decline. Could be several causes. A calm, clear email with two options (update card / contact support) is the right approach.
Sending the same message to all four of these customers guarantees you're doing the right thing for some and the wrong thing for others.
2. Stripe branding reduces trust
Stripe's default billing emails are sent from billing@stripe.com and are clearly Stripe-branded. For many customers — especially those who aren't particularly technical — receiving a payment email from "Stripe" rather than from the company they're paying creates confusion.
"Did I sign up with Stripe? Is this spam? Why isn't this from [product name]?"
You can customize Stripe emails with your logo and brand colors, and you can configure a reply-to address. But the sender remains Stripe, and the template is constrained.
An email from you — using your product's domain, in your product's voice, referencing the customer's specific situation — will always outperform a generic billing notification from Stripe.
3. No escalation for high-value accounts
Stripe's automated tools treat a $9/month customer the same as a $900/month customer. For most failed payments, automation is the right approach. But for your top accounts, a personal email from the founder recovers at dramatically higher rates than any template.
Stripe gives you no native way to identify which failed payments warrant a personal touch, draft a contextual message, or flag them for founder review.
Building a Better Dunning Process
Here's what a complete dunning process looks like for a bootstrapped SaaS founder.
Step 1: Understand the failure code
Every failed payment in Stripe comes with a decline_code or failure_code. This is the most important data point in your entire dunning process — it tells you exactly what went wrong and what the customer needs to do.
The four codes you'll see most often:
| Code | Cause | Right action |
|---|---|---|
card_expired | Card expiry date passed | Send update link immediately, friendly tone |
insufficient_funds | Temporary balance issue | Wait 3 days, send calm non-judgmental email |
do_not_honor | Bank blocked the charge | Explain why, give two options (call bank / new card) |
card_declined | Generic decline | Same-day email, offer help, conservative tone |
Access failure codes in Stripe via invoice.payment_failed webhook events, or in the Dashboard under Payments → Failed.
Step 2: Set up failure-code-specific email sequences
For each failure code, you want a distinct email sequence with different timing and different messaging.
card_expired sequence:
- D+0: "Your card expired — here's a one-click update link" (friendly, zero friction)
- D+3: Gentle reminder if no action taken
- D+7: Final notice with slightly higher urgency
insufficient_funds sequence:
- D+3: "Just a heads up about your recent payment" (calm, no pressure, no card update link)
- D+6: Second attempt notification
- D+10: Final notice
do_not_honor sequence:
- D+0: Explanation email — "Your bank blocked this charge. Here's what to do." (two options: call bank or use different card)
- D+4: Follow-up if no action
- D+8: Final notice
card_declined sequence:
- D+1: "We had trouble with your payment — can we help?" (offer two options)
- D+5: Second reminder
- D+10: Final notice
The key insight: the first email timing matters as much as the content. For card_expired and do_not_honor, send immediately — the customer needs to take action and can do so right now. For insufficient_funds, waiting 3 days before emailing avoids piling on when the customer is already stressed.
Step 3: Write emails that don't read like dunning emails
The best recovery emails don't feel like debt collection. They feel like a helpful nudge from a company that noticed something and wanted to let you know.
What to avoid:
- Threatening language ("Your account will be suspended")
- Vague urgency ("Action required immediately")
- Generic subject lines ("Payment failed")
- Asking the customer to do more work than necessary
What works:
- Specific subject lines that explain the situation: "Quick note about your card, [name]"
- One clear action, not multiple options
- Empathetic tone: "Happens to everyone" for expired cards; "Just a heads up" for declined charges
- A single prominent link or button
Example — card_expired, first email:
Subject: Quick note about your [Product] subscription, [Name]
Hey [Name],
The card we have on file for your [Product] subscription expired at the end of last month — happens to everyone.
Here's a one-click link to update it: [Update payment method]
Takes about 30 seconds. Once you update it, your subscription continues without any interruption.
Let me know if you have any questions.
[Your name]
Simple. Personal. One action. No threats. This outperforms any Stripe default template.
Step 4: Escalate high-value accounts personally
Define a threshold — say, any monthly payment above $200, or any account in your top 20% by MRR — and flag those failed payments for personal outreach.
For these accounts, don't rely on automated emails alone. Write a short, personal message that:
- References the customer by name and company
- Acknowledges the specific situation (payment issue, not a product problem)
- Makes it easy to resolve without making it awkward
"Hi [Name], I noticed that the payment for [Company]'s [Product] subscription didn't go through this month. I wanted to reach out personally rather than just sending an automated reminder — if there's anything on our end that needs sorting, just let me know. Otherwise, here's a link to update your payment details: [link]."
This takes 3 minutes to write and recovers high-value accounts at significantly higher rates than templates.
Step 5: Track and optimize
Once your dunning process is running, track:
- Recovery rate by failure code — which codes are you recovering well? Which are you losing?
- Recovery rate by email in sequence — are most recoveries happening at D+0 or D+7?
- Time to recovery — how long does it typically take after the first email?
- Unsubscribe/complaint rate — are your emails too aggressive?
Most bootstrapped founders discover that 70–80% of recoveries happen within the first email. If your D+0 recovery rate is low, the email content is the problem. If recovery drops off after D+3, the timing may be off.
Dunning Approaches: Manual vs. Automated vs. Dedicated Tool
Depending on your stage and volume, you have three realistic options.
Manual (< $5k MRR, < 10 failed payments/month)
Monitor invoice.payment_failed webhooks, maintain a spreadsheet, send emails manually. Time-consuming but viable at low volume. The main risk: it's easy to let failed payments slip through when you're busy building.
Best for: Very early stage, low volume, founders who want to stay close to every customer interaction.
Stripe + custom automation (engineering-heavy approach)
Build webhook listeners for invoice.payment_failed, parse the failure code, trigger your email provider (Resend, Postmark, etc.) with the right template based on the code. Manageable with a day or two of development work.
Best for: Founders comfortable building and maintaining the infrastructure, who want full control over the logic.
Dedicated dunning tool
Tools like Dunlo handle the entire process — Stripe webhook integration, failure code detection, email sequences timed to each code, and founder escalation for high-value accounts. Setup takes minutes rather than days.
The case for a dedicated tool: the ongoing maintenance cost of a custom solution is easy to underestimate. Stripe updates their webhook payloads. Email deliverability needs monitoring. Edge cases accumulate. A tool built specifically for this handles it so you don't have to.
Best for: Founders who want the recovery without the infrastructure overhead.
Dunning Checklist for Bootstrapped SaaS
Before you consider your dunning process complete, check these off:
- Stripe Smart Retries is enabled (Revenue Recovery settings)
- Stripe card expiry emails are enabled (Customer emails settings)
- You have a way to read
decline_codefrominvoice.payment_failedwebhook events - You have at least one email per major failure code (
card_expired,insufficient_funds,do_not_honor,card_declined) - Your emails come from your domain, not Stripe
- You have a threshold defined for personal founder escalation
- You're tracking recovery rate by failure code
- Your final dunning email includes a clear consequence (what happens if no action is taken)
The Bottom Line
Stripe's built-in dunning is a starting point, not a complete solution. Smart Retries and automated emails recover 25–40% of failed payments. A properly built dunning process — failure-code-specific emails, right timing, personal escalation for high-value accounts — recovers 60–75%.
On a $15k MRR business, that difference is worth $300–500/month in recovered revenue. Every month. Without acquiring a single new customer.
The investment required to build it properly is a few hours. The cost of not building it is a permanent, compounding revenue leak.
Already using Stripe? See what Dunlo recovers for your account — connect in 2 minutes, no credit card required. Free during beta.