Back to Blog
stripepayment recoverydunningfailed paymentssubscription recoverySaaS billinginvoluntary churn

How to Set Up a Payment Recovery Flow in Stripe (Step by Step)

John Joubert
February 15, 2026
11 min read
How to Set Up a Payment Recovery Flow in Stripe (Step by Step)

Why Payment Recovery Flows Matter for SaaS Revenue

Every month, subscription businesses lose 5-10% of their revenue to failed payments. Most of these failures aren't intentional cancellations. They're expired cards, insufficient funds, or temporary billing issues that customers would happily resolve if given the chance.

The problem? Without a proper payment recovery flow, these customers just disappear. Stripe won't chase them. Your billing system won't nudge them. And you'll watch MRR evaporate because of preventable technical hiccups.

A payment recovery flow is your automated system for catching failed payments and bringing customers back before they churn. When set up correctly, it can recover 20-40% of failed payments with minimal manual effort.

This guide walks through setting up a complete stripe payment recovery system, step by step, using Stripe's native tools plus a few proven strategies that actually work.

What You'll Need Before Starting

Before building your recovery flow, make sure you have:

  • Active Stripe account with at least a few subscriptions running
  • Access to Stripe Billing (available on all Stripe accounts)
  • Email sending capability (Stripe's built-in emails, SendGrid, Postmark, or similar)
  • Basic understanding of webhooks (optional but helpful for advanced setups)
  • Decision on recovery timeline (how many attempts, over what period)

You don't need to be a developer to set up the basics, but having technical support helps for custom flows.

Stripe payment recovery flow diagram showing retry logic and customer notifications
A complete payment recovery flow includes automated retries, dunning emails, and self-service payment updates.

Step 1: Enable Stripe's Smart Retries

Stripe's Smart Retries are your first line of defense. They automatically retry failed payments at optimal times based on millions of transaction patterns.

How to Turn On Smart Retries

  1. Log into your Stripe Dashboard
  2. Go to Settings → Billing → Subscriptions and emails
  3. Scroll to Payment retry rules
  4. Toggle Smart retries to ON

That's it. Stripe will now automatically retry failed payments over a 3-week period, choosing the best times based on:

  • Card issuer patterns
  • Historical success rates
  • Time of day/week factors
  • Customer payment behavior

What Smart Retries Do (and Don't Do)

Smart retries handle the payment retry logic, but they don't communicate with customers. You still need dunning emails to tell customers about failed payments and prompt them to update their card details.

For most SaaS businesses, Smart Retries recover 15-25% of failed payments without any customer intervention. But to hit 40%+ recovery, you need the full flow.

Step 2: Configure Subscription Lifecycle Settings

Stripe needs to know how long to keep trying before giving up. This is your subscription's "grace period."

Setting the Retry Window

  1. In Stripe Dashboard → Settings → Billing
  2. Find Subscription settings
  3. Set Unpaid subscription handling:
    • Mark subscription as past due: Keeps trying without canceling
    • Automatically cancel after X days: Hard deadline (typically 14-21 days)

Most SaaS companies use:

  • 3-7 days for low-touch products ($10-50/mo)
  • 14-21 days for mid-market products ($100-500/mo)
  • 30+ days for enterprise (custom handling)

Longer windows give more recovery chances but risk accumulating unpaid invoices.

Pro Tip: Pause vs Cancel

Consider pausing subscriptions instead of canceling them. Paused subscriptions:

  • Keep customer data and history intact
  • Make reactivation frictionless
  • Show customers you're not writing them off

Stripe supports this via the API, though it requires custom logic.

Step 3: Set Up Dunning Emails

Dunning emails are automated messages that notify customers about failed payments and guide them to update their payment method.

Using Stripe's Built-In Dunning Emails

Stripe provides basic dunning emails out of the box:

  1. Go to Settings → Billing → Emails
  2. Enable Failed payment emails
  3. Customize the email template:
    • Add your branding
    • Write a friendly, non-threatening message
    • Include a direct link to update payment method
    • Mention the retry schedule

Stripe's default emails are functional but limited. For better control, use a dedicated email service.

Building a Custom Dunning Flow

For more sophisticated recovery, set up a multi-touch email sequence:

Email 1 (Day 0): Immediate notification

  • Subject: "Payment failed for [Your Product] – update now"
  • Tone: Helpful, not accusatory
  • Action: One-click link to payment settings

Email 2 (Day 3): Gentle reminder

  • Subject: "Quick reminder: update your payment method"
  • Tone: Friendly nudge
  • Action: Same link, plus customer support contact

Email 3 (Day 7): Urgency without panic

  • Subject: "Your [Product] access is about to pause"
  • Tone: Direct but respectful
  • Action: Clear deadline, support offer

Email 4 (Day 14): Final notice

  • Subject: "Last chance to keep your [Product] account active"
  • Tone: Regretful but firm
  • Action: Reactivation path, cancellation date
Dunning email sequence timeline showing 4 touchpoints over 14 days
A well-timed dunning sequence gives customers multiple chances to resolve payment issues without feeling harassed.

This sequence gives customers multiple opportunities to fix the issue without feeling harassed. Studies show 3-4 touch points recover significantly more than a single email.

For proven dunning email templates and strategies, check out our guide on dunning email strategies.

Step 4: Create a Self-Service Payment Update Flow

Customers need an easy way to update their payment method without contacting support.

Stripe Customer Portal

The fastest solution is Stripe's hosted Customer Portal:

  1. Go to Settings → Billing → Customer portal
  2. Enable the portal
  3. Configure allowed actions:
    • Update payment method ✓
    • Update billing info ✓
    • View invoices ✓
    • Cancel subscription (optional, risky during recovery)
  4. Customize branding to match your product
  5. Copy the portal URL

Include this URL in all dunning emails and in-app notifications.

In-App Payment Update (Advanced)

For better UX, embed payment updates directly in your app:

  1. Use Stripe Elements to create a card update form
  2. Call stripe.customers.update() to replace the payment method
  3. Trigger immediate retry via stripe.invoices.pay()
  4. Show success confirmation

This keeps customers in your product and reduces friction significantly.

Step 5: Add In-App Notifications

Email alone isn't enough. Customers might miss emails or mark them as spam. In-app notifications catch them when they're already engaged.

Where to Show Notifications

  • Dashboard banner: Persistent until resolved
  • Login modal: Can't miss, but use sparingly
  • Billing page indicator: Always visible on account settings
  • Feature gates: Block new actions until payment updated (nuclear option)

Most effective: a non-blocking banner at the top of your app that links directly to payment settings.

What to Say

❌ Don't: "Your payment failed. Update your card."

✓ Do: "We couldn't process your payment. Update your card to keep using [Product]."

Include:

  • What happened
  • What they need to do
  • How to do it (one-click link)
  • When access will be suspended

Step 6: Monitor Decline Codes

Not all failed payments are equal. Some are retryable (insufficient funds), others aren't (stolen card).

Stripe provides decline codes that tell you exactly why a payment failed. Use these to customize your recovery approach:

Retryable failures (keep trying):

  • insufficient_funds → Retry in 3-5 days
  • expired_card → Send card update email immediately
  • do_not_honor → Retry once, then prompt customer

Non-retryable failures (don't waste time):

  • fraudulent → Block immediately
  • lost_card → Require new payment method
  • card_declined (generic) → One retry, then manual intervention
Decision tree for handling different Stripe decline codes
Different decline codes require different recovery strategies to maximize recovery rate.

You can access decline codes via the Stripe Dashboard or API response:

const charge = await stripe.charges.retrieve('ch_xxx');
const declineCode = charge.outcome.reason;

For a complete breakdown of what each code means and how to handle it, see our guide on Stripe decline codes explained.

Step 7: Set Up Webhooks for Real-Time Response

Webhooks let you react instantly to payment events instead of waiting for scheduled jobs.

Key Webhooks for Payment Recovery

  • invoice.payment_failed → Trigger dunning email, show in-app alert
  • invoice.payment_succeeded → Clear notifications, send confirmation
  • customer.subscription.updated → Track status changes
  • charge.failed → Log decline code, route to appropriate flow

How to Set Up a Webhook

  1. Go to Developers → Webhooks
  2. Click Add endpoint
  3. Enter your endpoint URL (e.g., https://yourapp.com/stripe/webhooks)
  4. Select events to listen for
  5. Copy the signing secret
  6. Verify webhook signatures in your code:
const event = stripe.webhooks.constructEvent(
  request.body,
  request.headers['stripe-signature'],
  webhookSecret
);

if (event.type === 'invoice.payment_failed') {
  // Handle failed payment
  const invoice = event.data.object;
  await sendDunningEmail(invoice.customer);
}

Webhooks enable immediate response, better customer experience, and higher recovery rates.

Step 8: Add Card Expiry Monitoring

Many failed payments happen because cards expire. Catch these proactively:

How to Monitor Card Expiry

1. Pull customer payment methods via API:

const paymentMethods = await stripe.paymentMethods.list({
  customer: 'cus_xxx',
  type: 'card',
});

const card = paymentMethods.data[0].card;
if (card.exp_year === currentYear && card.exp_month === currentMonth) {
  // Card expires this month
  await sendExpiryReminder(customer);
}

2. Send reminder emails 30 days before expiry
3. Follow up 7 days before expiry
4. Final reminder 1 day before expiry

Proactive expiry management prevents 10-15% of would-be failures before they happen.

Step 9: Track Recovery Metrics

You can't improve what you don't measure. Key metrics to track:

Payment Recovery Rate

Recovery Rate = (Recovered Payments / Total Failed Payments) × 100

Good: 30-40%
Great: 40-50%
Excellent: 50%+

Time to Recovery

How long does it take to recover a failed payment? Faster is better. Most recovered payments come within 7 days.

Recovery by Channel

Which method works best?

  • Smart Retries alone: 15-25%
  • Email prompts: +10-15%
  • In-app notifications: +5-10%
  • SMS (if you use it): +3-5%

Test and optimize each channel.

Revenue at Risk

At-Risk MRR = Sum of all past-due subscriptions

Monitor this daily. A sudden spike indicates a systemic issue (payment gateway problem, bank restrictions, etc.).

For more on tracking churn and recovery metrics, see our breakdown of how failed payments destroy MRR.

Step 10: Test Your Flow

Before going live, test every step:

Using Stripe Test Mode

  1. Switch to Test mode in Stripe Dashboard
  2. Create a test subscription with a test customer
  3. Use Stripe's test card numbers to trigger failures:
    • 4000000000000341 → Attaching fails (card declined)
    • 4000000000009995 → Charge fails (insufficient funds)
    • 4000000000000069 → Charge fails (expired card)
  4. Verify that:
    • Smart Retries trigger
    • Dunning emails send
    • In-app notifications appear
    • Webhooks fire correctly
    • Payment updates work

Test the Customer Experience

Walk through the flow as a customer:

  1. Receive dunning email
  2. Click payment update link
  3. Update card details
  4. See success confirmation
  5. Verify access restored

Fix any friction points before launching.

Common Mistakes to Avoid

Mistake #1: Too Aggressive Retry Logic

Retrying every hour annoys customers and racks up fees. Use Stripe's Smart Retries or space manual retries 3-5 days apart.

Mistake #2: Passive Dunning Emails

Emails that say "your payment failed" without a clear action button get ignored. Always include a one-click update link.

Mistake #3: Canceling Too Quickly

Canceling after 3 days leaves money on the table. Most recovered payments happen between day 3-14.

Mistake #4: No In-App Alerts

Customers who are actively using your product shouldn't find out via email that their access is ending. In-app notifications are critical.

Mistake #5: Not Monitoring Decline Codes

Treating all failures the same wastes time. Customize your response based on whether the failure is retryable.

Mistake #6: Forgetting Card Expiry

This is the lowest-hanging fruit. Monitor and remind customers before cards expire.

What Good Recovery Looks Like

A well-configured payment recovery flow recovers 40-50% of failed payments and reduces involuntary churn by 30-60%.

Here's what it looks like in practice:

Day 0: Payment fails at 2am (card expired)

  • Smart Retry attempts at 9am (fails)
  • Dunning email #1 sent at 9:05am
  • In-app banner appears on next login

Day 1: Customer logs in, sees banner, clicks "Update Payment"

  • Customer Portal opens
  • New card added in 30 seconds
  • Stripe immediately retries and succeeds
  • Banner disappears, confirmation email sent

Result: Customer recovered in 24 hours with zero manual intervention.

That's the goal. Automate the entire process so customers can fix issues instantly and your team never touches manual recovery.

Next Steps: Automate and Optimize

Once your basic flow is live, focus on optimization:

  1. A/B test email subject lines and copy — small changes can boost open rates by 20%+
  2. Experiment with retry timing — track which retry attempts convert best
  3. Segment by customer value — give high-LTV customers longer grace periods
  4. Add SMS for high-value accounts — 90%+ open rate for urgent nudges
  5. Monitor recovery by cohort — new customers vs long-term, plan tier, geography

Payment recovery is not a set-it-and-forget-it system. Plan to review and tweak quarterly based on data.

The Bottom Line

Setting up a stripe payment recovery flow takes a few hours but pays back immediately. For a SaaS business doing $50k MRR with a typical 5% monthly payment failure rate, recovering even 30% of failures saves $750/month or $9k/year.

At scale, this becomes tens or hundreds of thousands in recovered revenue, all from automated systems that run in the background.

If you want to see exactly how much revenue you're losing to failed payments right now, run a free churn audit at churnbot.co/audit. It'll scan your Stripe account and show you where the leaks are.

Related Posts

How healthy is your Stripe account?

Get a free churn health report. Find pending cancellations, failed payments, and expiring cards putting your MRR at risk.

Run Free Audit