Every SaaS business on Stripe already has a dunning system. It is called Smart Retries, and it is free. For a business at €5k MRR with a handful of payment failures per month, it is probably sufficient. For a business at €50k MRR losing 2% of subscribers per month to billing failures, it is leaving significant money on the table.

The gap between Stripe's default behaviour and an optimised dunning setup is approximately 15–20 percentage points of recovery rate. On a business with 500 customers and 10 payment failures per month, moving from 25% to 42% recovery means 1.7 additional customers retained per month. Over a year, that is 20 additional retained customers at essentially zero marginal cost beyond a few hours of one-time setup.

This guide covers every layer of Stripe dunning optimisation: understanding Smart Retries' limits, reading decline codes correctly, building the right retry logic, writing recovery emails that work, proactive prevention, and when to move beyond Stripe to a dedicated tool.

What you will learn

  • How Stripe Smart Retries works and exactly where its limits are
  • What each decline code means and the optimal response to each
  • How to build decline-code-specific retry logic using webhooks
  • The three-email recovery sequence that doubles completion rates
  • The proactive expiry outreach strategy that prevents failures before they happen
  • When Stripe dunning is enough and when to upgrade

📋 In this article

How Stripe Smart Retries works — and where it stops

Stripe Smart Retries uses machine learning across billions of payment attempts on the Stripe network to time retries optimally. Rather than retrying on a fixed day-3 / day-7 / day-14 schedule, Smart Retries analyses patterns in successful recoveries and schedules the next attempt when success probability is highest based on network-wide signals.

This is genuinely useful. Stripe has access to more payment data than any independent tool can match, and that timing advantage produces a meaningful improvement over naive fixed schedules. Enabling Smart Retries — and doing nothing else — is the highest-ROI single change available to a business currently using Stripe's basic retry behaviour.

What Smart Retries does What Smart Retries does not do
Optimises retry timing using network-wide payment dataVary strategy based on decline code type
Automatic card updater (participating banks)Send custom branded recovery emails
Basic payment failure notification emailsProvide direct update links without customer login
Included free with Stripe BillingProactive card expiry outreach before failure

The ceiling: Smart Retries achieves roughly 40–50% success rate on retried payments — but that is only the retry dimension. Of all failed payments, many require the customer to actively update their card (expired cards cannot be retried at all). The overall recovery rate from retry alone is 20–25% of all payment failures. The remaining 15–25% gap requires recovery emails with direct update links.

Decline codes: the most underused data in your billing stack

Every failed Stripe payment returns a decline_code in the API response. Most businesses log it and ignore it. This is a significant mistake — the decline code is the most actionable signal in your entire dunning process. It tells you why the payment failed, which determines what the right response is.

Decline code Root cause Retry strategy Email approach Recovery rate
insufficient_fundsBalance too low right nowWait for payday — retry 1st or 15thSoft, no alarm language55–70% with payday timing
expired_cardCard past expiry dateZero retries — skip straight to card update emailImmediate, direct, helpful40–60% with fast outreach
card_declinedBank temporary restrictionRetry at 24h, then day 7Moderate urgency35–50%
do_not_honorBank blanket declineRetry in 48 hoursSoft notification50–65% on second attempt
processing_errorTechnical failure — self-resolvingRetry within 24 hoursUsually none needed85–95% on first retry
card_velocity_exceedSpending limit hit (corporate cards)Retry end of month when limits resetHeads-up with expected retry date40–55%
fraudulent / stolenCard reported compromisedNo retries — wait for customerCareful — not standard dunning20–35%

🚨 Never retry an expired card

Retrying an expired card is not just useless — it can trigger fraud flags at the issuing bank, making it harder for the customer to add their new card later. The moment you see expired_card in the decline code, stop all retries immediately and send a card update email. This is the most common and most expensive misconfiguration in standard Stripe dunning setups.

Building decline-code-specific logic with Stripe webhooks

Stripe's dashboard settings apply retry behaviour universally — you cannot configure different schedules per decline code without code. To implement the right strategy for each failure type, you need to listen to the invoice.payment_failed webhook event and read the last_payment_error.decline_code field.

// Stripe webhook handler — invoice.payment_failed
export async function POST(req: Request) {
  const event = stripe.webhooks.constructEvent(
    await req.text(), req.headers.get('stripe-signature')!, secret
  );

  if (event.type === 'invoice.payment_failed') {
    const invoice = event.data.object as Stripe.Invoice;
    const code = invoice.last_payment_error?.decline_code ?? 'unknown';

    switch (code) {
      case 'expired_card':
        // No retry — card is dead. Send update email immediately.
        await cancelScheduledRetries(invoice.id);
        await sendCardUpdateEmail(invoice.customer_email!, 'expired');
        break;

      case 'insufficient_funds':
        // Retry near payday (1st or 15th of next month)
        await schedulePaydayRetry(invoice.id);
        await sendSoftPaymentEmail(invoice.customer_email!);
        break;

      case 'processing_error':
        // Technical issue — retry in 24h, usually self-resolves
        await scheduleRetry(invoice.id, 24 * 60 * 60 * 1000);
        break;

      default:
        // card_declined, do_not_honor, etc.
        await scheduleRetry(invoice.id, 48 * 60 * 60 * 1000);
        await sendModerateUrgencyEmail(invoice.customer_email!);
    }
  }
}

This implementation takes one to two hours to build and delivers a step-change improvement in recovery rate that persists indefinitely. It is the single most impactful technical investment in your billing infrastructure for any SaaS doing meaningful payment failure volume.

The payday timing strategy

Insufficient funds is the most common decline code for consumer-facing and lower-price-point B2B SaaS. The key insight: people get paid on predictable schedules. A payment that fails on the 23rd because the account is running low near the end of the pay cycle will almost certainly succeed if retried on the 1st or 2nd of the following month, when the paycheck has cleared.

A retry scheduled for the 1st or 15th of the month — the two most common payday dates across most markets — consistently outperforms a day-3 or day-7 retry by 20–30 percentage points for this specific decline code. The implementation is simple: when you detect insufficient_funds, calculate the next payday date and schedule the retry for that date rather than a fixed interval.

Failure date Generic retry (day 3) Payday-optimised retry Why
January 22January 25February 1Account likely low end-of-month. Payday just cleared.
March 8March 11March 15Mid-month payday approaching. Wait for it.
November 29December 2December 1First of month — strongest payday signal.

Writing recovery emails that convert

Three emails over twelve days is the established best practice for payment recovery. Fewer leaves recovery rate on the table. More tips into harassment and starts damaging your sender reputation.

Email 1 — Day 1: Low urgency, direct action. Subject: "Action needed: payment issue on your account." Body: one sentence saying the payment failed, one direct link to update the card. No alarm language. No consequences mentioned yet. Many customers update immediately when they see a clear, frictionless path.

Email 2 — Day 5–7: Moderate urgency with a specific date. "Your account will be affected on [specific date] if we cannot process your payment." The specific date — not "soon" or "shortly" — consistently outperforms vague urgency. Customers respond to a concrete deadline in a way they do not respond to abstract warnings.

Email 3 — Day 10–12: Final warning, loss framing. "Your data and [X months] of history are at risk." Loss aversion is more motivating than the equivalent gain — the prospect of losing something already possessed outweighs the prospect of gaining something equivalent in value. This is the email that converts the customers who ignored the first two.

💡 The single technical requirement that doubles completion rates

Every recovery email must link to a payment update page that works without login. On mobile — where most payment failure emails are read — a login screen eliminates 50–70% of customers before they reach the update form. Use Stripe's hosted invoice update pages or build a tokenised direct-update URL. The login requirement is the most common and most damaging friction point in standard dunning email setups.

Proactive prevention: outreach before failure

The highest-ROI dunning action is one that prevents the payment from failing at all. Stripe provides card expiration data — you can identify customers whose cards expire in the next 30–60 days before any failure occurs.

A "your card on file expires next month" email sent 30 days before expiry prevents 30–50% of expiry-related failures. This is permanently one of your highest-performing automated emails: low drama, clear action, immediate benefit. Setup is one-time. It runs forever.

For annual billing: send a renewal reminder 14 days before the charge. Annual amounts are large enough to trigger bank fraud flags or customer surprise. A simple heads-up email — "your annual subscription renews on [date] for €[amount]" — prevents most of these issues and dramatically reduces dispute rates on annual charges.

Proactive touchpoint When to send Impact Effort
Card expiry warning30 days before card expiresPrevents 30–50% of expiry failuresOne-time setup
Card expiry final reminder7 days before card expiresCatches customers who missed the 30-day emailOne-time setup
Annual renewal reminder14 days before annual chargeReduces large-charge bank declines and disputesOne-time setup

Measuring dunning performance

Three metrics tell you whether your dunning system is working:

Overall payment recovery rate: failed payments that are eventually collected divided by total failed payments. Target above 40%. Below 25% means the current setup is leaving significant recoverable revenue unused.

Recovery rate by decline code: the overall rate hides important variation. Expired card recovery should be 40–60% with good email outreach. Insufficient funds with payday timing should hit 55–70%. If any code is significantly below benchmark, the strategy for that code needs adjustment.

Email engagement by sequence step: which email in the three-email sequence generates most of the card updates? If Email 1 drives 50%+ of completions, your Email 2 and 3 timing and copy may be improvable. If Email 3 drives most completions, consider whether earlier urgency would help.

When to upgrade beyond Stripe dunning

Situation Recommendation
Under €10k MRR, under 5 failures/monthStripe Smart Retries + manual expiry emails. Dollar impact too low to justify tool cost.
€10k–€100k MRR, 5–30 failures/monthImplement webhook decline-code logic + three-email sequence. Or use Retainly to handle it automatically.
€100k+ MRR, 30+ failures/monthDedicated tool. Recovery improvement at this scale easily justifies the cost.
Also need cancel flowsFull-stack tool (Retainly) rather than separate dunning + cancel flow tools.

Retainly automates all of this

Decline-code-specific retry logic, payday timing, three-email sequences, proactive expiry outreach. All automatic after a one-time setup of under 10 minutes. Free to start.

Start for free →

Frequently asked questions

What recovery rate does Stripe Smart Retries achieve?

Stripe Smart Retries achieves roughly 40–50% success on retried payments, but the overall payment recovery rate — including payments that require card updates and cannot be retried — is typically 20–25% of all failures. With decline-code-specific logic and a three-email sequence with direct update links, overall recovery rates of 40–50% are achievable.

Should I use Stripe Smart Retries or build my own retry logic?

Start with Smart Retries — it is free and meaningfully better than a naive fixed schedule. Build custom webhook-based decline-code logic on top once you are above €10k MRR and have 5+ failures per month where the improvement in recovery rate has meaningful dollar value. The two approaches are complementary, not competing.

What Stripe webhook should I use for dunning?

Listen to the invoice.payment_failed event. It fires each time Stripe attempts and fails a subscription payment. The event contains the invoice object, which includes last_payment_error.decline_code — the field that tells you what specific action to take.

How many dunning emails should I send?

Three emails over twelve days: day 1 (soft notification), day 5–7 (moderate urgency with specific date), day 10–12 (final warning with loss framing). Fewer leaves recovery potential unused. More than three starts generating spam complaints that damage your domain's deliverability for all outgoing email, not just dunning.

What is the difference between hard and soft decline codes?

Soft declines are temporary — the payment may succeed on retry. Insufficient_funds, do_not_honor, and processing_error are typically soft. Hard declines are permanent — the card cannot be charged again and requires replacement. Expired_card and fraudulent/stolen are hard declines. Never retry a hard decline: the retry wastes an attempt and can trigger fraud flags at the issuing bank.

Corporate card failures: a different challenge

B2B SaaS has a payment failure pattern that consumer-facing products largely do not encounter: corporate card lifecycle events. When an employee whose corporate card is on file for a company subscription leaves the organisation, the card is typically deactivated within 24–48 hours of their departure. When a company changes its banking provider or switches corporate card issuers, every card is cancelled simultaneously — potentially taking down multiple SaaS subscriptions at the same moment.

These failures appear in your Stripe logs as card_declined or do_not_honor, indistinguishable from other temporary bank declines at the code level. But the underlying cause is different: no retry will succeed because the card is permanently deactivated. The right response is the same as for expired_card — skip retries and go directly to a card update email — but nothing in the standard decline code tells you this is the reason.

A signal that can help: corporate card failures often cluster. If you see multiple failures from the same company domain within a short window, it is likely a card replacement event. Route those to immediate billing contact outreach rather than the standard dunning sequence.

Measuring dunning effectiveness over time

The metrics that actually tell you whether your dunning system is working — and where to improve it — go beyond the headline recovery rate:

Metric What it reveals Target If below target
Overall recovery rateTotal failed payments recovered> 40%Check email deliverability and direct link usage
Email 1 resolution rate% resolved from first email alone35–45%Speed of first send (within 1–2 hours?)
Retry success by codeWhich decline codes recover via retry vs emailVaries by codeCheck if expired_card is still being retried
Time to recoveryAverage days from failure to collected payment< 7 daysEarlier first email? Better CTA on Email 1?

Email deliverability: the hidden factor in stripe dunning

Dunning emails have a structural deliverability challenge that marketing emails do not. They are transactional in nature — triggered by billing events, sent to a specific customer about a specific account action — but they are often sent from the same domain and infrastructure as marketing emails. If your marketing email sending has generated spam complaints or bounces, those reputation signals can affect the deliverability of your dunning emails.

The most common deliverability mistakes in dunning sequences:

Sending from a shared IP pool. If your email provider uses shared sending infrastructure, a bad sender on the same pool can affect your deliverability. For dunning emails — which generate their most value when they arrive immediately — a dedicated IP or a high-reputation sending service is worth the cost.

Missing SPF and DKIM records. Emails sent without proper authentication are more likely to land in spam. Every domain used for sending dunning emails needs correctly configured SPF and DKIM records. This is a one-time setup that takes 15 minutes and permanently improves deliverability.

Subject line spam triggers. Words like "URGENT," "ACT NOW," and excessive exclamation points are flag words for spam filters. Dunning subject lines should be calm and factual — "Action needed: payment issue on your account" rather than "URGENT: Your account will be deleted!!" The latter pattern gets spam-filtered and never seen.


Related: What Is Dunning? · Failed Payment Recovery Guide · How to Reduce SaaS Churn · Churnkey Alternatives