A failed payment doesn't have to mean a lost customer. But whether you recover that payment depends entirely on what happens in the minutes, hours, and days after the failure. Most SaaS companies either do nothing (relying solely on Stripe's built-in retries) or do too little (one generic email, hope for the best).
This guide walks through building a complete payment recovery workflow, from the moment a payment fails to final resolution.
The six-step workflow
Here's the full recovery workflow at a glance:
Step 1: DETECT → Webhook receives failure event
Step 2: CLASSIFY → Soft decline vs hard decline
Step 3: COMMUNICATE → Email + SMS sequence
Step 4: FACILITATE → Payment link for easy update
Step 5: MONITOR → Track status and outcomes
Step 6: ESCALATE → Suspend or cancel if unresolved
Each step feeds into the next. Skip one, and the whole workflow weakens. Let's go through each.
Step 1: Detect the failure
Recovery starts with knowing a payment failed. If you're on Stripe, this means handling the invoice.payment_failed webhook event.
What triggers this event:
- A subscription renewal charge is declined
- An invoice payment attempt fails
- A manual payment attempt on an open invoice fails
What you capture:
- Customer details (ID, email, name)
- Invoice amount and currency
- Subscription ID
- Attempt count (first failure vs retry)
- Next scheduled retry timestamp
- Decline code and reason
The speed of detection matters. Your first outreach should happen within an hour of the failure, not the next day. Customers are more likely to act on a fresh problem than a stale one.
How to set this up:
Create a webhook endpoint in your application. Register it in your Stripe Dashboard under Developers > Webhooks. Select the invoice.payment_failed event. Verify every incoming event using the Stripe signature header to prevent spoofed requests.
Process events asynchronously. Accept the webhook, return a 200 response immediately, and enqueue the actual processing in a background job. This keeps your webhook handler fast and prevents timeouts.
Store every failed payment in your database with a unique record per invoice. This becomes your source of truth for the rest of the workflow.
Step 2: Classify the failure
Not all payment failures are the same. The decline type determines your strategy.
Soft declines
These are temporary. The card is valid but the charge didn't go through this time.
Common reasons:
- Insufficient funds
- Temporary hold on the account
- Card issuer is temporarily unavailable
- Processing error on the bank's side
Recovery strategy: Retry + notify. There's a reasonable chance the next attempt will succeed, especially if you retry at a different time of day or a few days later when the customer's balance has replenished.
Soft declines account for roughly 80% of all payment failures. The good news: they also have the highest recovery rate, often 50-60% on retry alone.
Hard declines
These are permanent (or semi-permanent). The card itself is the problem.
Common reasons:
- Card expired
- Card reported lost or stolen
- Invalid card number
- Card not supported for this transaction type
- Suspected fraud
Recovery strategy: Don't retry the same card. It won't work. Instead, notify the customer immediately that they need to update their payment method. Be specific about the problem ("Your card ending in 4242 has expired") so they know exactly what to do.
Hard declines have lower recovery rates (30-40%), but that's still significant revenue worth pursuing.
How to classify
The decline code from the charge object tells you everything. Map known codes to soft or hard categories:
SOFT DECLINE CODES:
insufficient_funds
processing_error
issuer_not_available
try_again_later
generic_decline (treat as soft by default)
HARD DECLINE CODES:
expired_card
card_not_supported
stolen_card
lost_card
invalid_number
do_not_honor (context-dependent, usually hard)
Store the classification alongside the failed payment record. It drives decisions throughout the rest of the workflow.
Step 3: Communicate with the customer
This is where most of the recovery actually happens. Your communication sequence should combine channels, escalate in urgency over time, and make it dead simple to fix the problem.
The recommended sequence
For a 10-day grace period, here's a proven sequence:
Day 0 (within 1 hour): Email #1, Informational
Tell the customer what happened. Keep it friendly and low-pressure. Include one clear call to action: a link to update their payment method.
For soft declines, mention that you'll retry automatically. For hard declines, emphasize that they need to update their card.
Subject line example: "Problem with your [Product] payment"
Day 2-3: Email #2, Reminder
The customer either missed or ignored the first email. Be slightly more direct. Mention the specific deadline: "If we don't receive payment by [date], your access will be suspended."
Subject line example: "Your card is still being declined"
Day 5: SMS #1
If you have the customer's phone number, send a short SMS. SMS has a 98% open rate versus 20-30% for email. Keep it under 160 characters with a direct link.
Example: "[Name], your [Product] payment failed. Update your card to keep access: [link]"
Day 7: Email #3, Urgent
This is the escalation email. Be direct about consequences. "This is your final reminder before we suspend your account." List what they'll lose access to. Place the CTA prominently.
Subject line example: "Final notice: your account will be suspended"
Day 7: SMS #2
A final SMS reinforcing the email. "Final reminder: your [Product] access ends tomorrow. Fix it now: [link]"
Day 10: Email #4, Suspension notice
If they haven't acted, follow through. Notify them that access has been suspended. But keep the door open: "Your data is safe for 30 days. Reactivate anytime."
Channel-specific notes
Email is your primary channel. Every customer has an email address. Focus on deliverability (authenticated domain, clean sender reputation), mobile-friendly design, and a single prominent CTA.
SMS is your force multiplier. Adding SMS to an email-only sequence typically improves recovery rates by 15-25%. But SMS requires the customer's phone number and compliance with regulations (TCPA in the US, GDPR in Europe).
In-app notifications are a bonus if your product supports them. A banner saying "Your payment failed. Update your card." catches customers who are actively using the product but ignoring emails.
Step 4: Facilitate the payment update
You've told the customer their payment failed. Now make it effortless for them to fix it.
The payment update link
The link in your emails and SMS should take the customer directly to a page where they can update their card. Not your homepage. Not a login page. Not a dashboard with a buried "billing" tab.
The ideal flow:
- Customer clicks the link
- They land on a payment update page (no login required, or auto-authenticated via a magic link token)
- They enter new card details
- Done. Subscription reactivated automatically.
If you're using Stripe, you can create a Billing Portal session or a custom payment page using Stripe Elements. The fewer clicks between "I should fix this" and "It's fixed," the higher your recovery rate.
One-click retry
For soft declines where the card is still valid, sometimes the customer just needs to retry the charge. Offer a "Retry payment" button that attempts the charge again without requiring new card details. If the issue was temporary (insufficient funds that have since been resolved), this recovers the payment with zero friction.
Stripe Billing Portal
Stripe's Customer Portal lets customers manage their subscription and update payment methods. You can generate a one-time link to the portal for each customer. This is the quickest implementation path if you don't want to build a custom payment page.
Step 5: Monitor the workflow
A recovery workflow you can't measure is a recovery workflow you can't improve.
Key metrics to track
Recovery rate: The percentage of failed payments that are eventually recovered. This is your north star metric. A good target: 60-70% overall recovery. Best-in-class teams hit 75%+.
Recovery by attempt: Which touchpoint (Email #1, SMS #1, Email #3, etc.) drives the most recoveries? This tells you which messages are working and which need improvement.
Time to recovery: How many days after the initial failure does the average recovery happen? Shorter is better. If most recoveries happen on Day 1, your first email is effective. If they spike on Day 7, customers are waiting until the deadline.
Recovery rate by decline type: Soft declines should recover at 50-70%. Hard declines at 25-40%. If your hard decline recovery is below 20%, your messaging likely isn't specific enough about the need to update the card.
Channel effectiveness: Compare recovery rates for email-only touchpoints versus email+SMS. This validates whether SMS is worth the cost.
Opt-out rate: If customers are unsubscribing from your dunning emails at a high rate, your frequency might be too aggressive or your tone might be off.
Where to monitor
Build a simple dashboard showing:
- Total failed payments this month
- Total recovered (and amount)
- Current active dunning sequences
- Recovery rate trend over time
Even a basic spreadsheet works when you're starting out. The point is to look at the data regularly and act on it.
Step 6: Escalate or resolve
Every failed payment eventually reaches one of three outcomes:
Outcome 1: Payment recovered
The customer updates their card or a retry succeeds. Mark the failed payment as recovered, end the dunning sequence, and restore full access if it was restricted.
Send a brief confirmation: "Your payment went through. You're all set." This closes the loop and reassures the customer.
Outcome 2: Subscription suspended
The grace period ends without recovery. Suspend the subscription: remove access to the product but preserve the account and data. This creates a final pressure point (loss aversion) while keeping the door open for return.
Send a suspension notice with a simple reactivation link. Some customers will act now that the consequence is real.
Keep the account data intact for 30-60 days. A customer who reactivates on Day 15 is recovered revenue. A customer whose data was deleted on Day 8 is gone forever.
Outcome 3: Subscription canceled
After the data retention period, if the customer hasn't returned, cancel the subscription fully and clean up. Optionally send one final win-back email before deletion: "Your account and data will be permanently deleted in 7 days. Click here to come back."
Escalation rules
Define clear rules for when to escalate:
- Grace period ends with no payment: Suspend access
- 30 days after suspension with no reactivation: Final win-back email
- 45-60 days after suspension: Cancel and delete
- High-value accounts (above a threshold you define): Flag for manual outreach before cancellation
For high-value customers, a personal email from the founder or account manager recovers payments that automated sequences can't. A $500/month customer is worth a 5-minute email.
Building vs buying
You can build this workflow yourself. You'll need:
- A webhook endpoint for Stripe events
- A database to track failed payments and dunning state
- A job queue (BullMQ, Celery, Sidekiq) for scheduling messages
- An email service (SES, SendGrid, Postmark) for transactional emails
- An SMS service (Twilio, MessageBird) for text messages
- A payment update page or Stripe Billing Portal integration
- A dashboard for monitoring
That's a meaningful engineering investment. For a team with capacity and specific requirements, it's a reasonable choice. You get full control over every aspect of the workflow.
The alternative is a dedicated tool. Rekko, for example, handles the full workflow: webhook ingestion, classification, multi-channel messaging, payment links, and analytics. You connect your Stripe account and configure your sequence. The engineering work drops from weeks to hours.
The math is straightforward. If you're losing $5,000/month to failed payments and a recovery tool brings back 60%, that's $3,000/month recovered. The tool pays for itself many times over.
Where to start
If you're building from zero, start with the basics and expand:
Week 1: Set up the webhook endpoint. Catch invoice.payment_failed events. Store failed payments in your database.
Week 2: Build the first email. Send an automated notification within an hour of failure with a link to update payment. This alone will recover 20-30% of failed payments.
Week 3: Add reminders. Build out the 3-4 email sequence with escalating urgency.
Week 4: Add SMS. Integrate an SMS provider and add 1-2 SMS touchpoints.
Ongoing: Monitor, measure, and optimize. A/B test subject lines. Adjust timing. Track recovery by decline type.
Each step adds incremental recovery. You don't need the full workflow on day one. But every week without any recovery workflow is revenue walking out the door.