Failed Payments and Dunning for SaaS: Retries, Emails and Billing Edge Cases
By Obaid Tariq, Founder & Lead Engineer · Published
The short answer
Treat a failed renewal as a recoverable event, not a cancellation. Turn on your billing provider's automatic retries, send a short sequence of clear emails with a one-click link to update the card, keep the customer's access during a defined grace period, and decide in advance what happens when recovery fails. Most of the engineering work is in handling the webhooks correctly, so your app's idea of who has paid always matches the billing provider's.
How should I handle failed payments, payment retries, dunning and billing edge cases?
Let the billing provider retry automatically, tell the customer quickly and plainly, give them a hosted page to fix the card, and keep access for a grace period that matches the retry window. Make your application react to billing webhooks rather than polling, and write down what happens at the end of the window before the first customer ever fails a payment.
Why failed payments matter more than they look
A customer whose card fails did not decide to leave. Expired cards, a bank's fraud filter, insufficient funds on the renewal date or a card that now needs extra authentication all look the same in your revenue chart as a cancellation if nothing recovers them. This is usually called involuntary churn, and unlike voluntary churn it is mostly an engineering and operations problem, so it is one of the cheaper retention problems to fix. For the wider picture of retention, see our guide to SaaS metrics and churn.
Step 1: Configure automatic retries
Every mainstream subscription billing system can retry a failed renewal on a schedule. Using Stripe Billing as the example, Stripe recommends its Smart Retries feature, which chooses retry times using signals such as when a payment method is most likely to succeed; its documentation gives a recommended default of 8 tries within 2 weeks, with retry windows of 1 week, 2 weeks, 3 weeks, 1 month or 2 months. You can instead define a custom schedule of up to three retries at set day intervals.
Step 2: Write a dunning sequence people actually act on
Dunning is the sequence of messages that asks the customer to fix the payment. In our experience the wording matters less than three practical details: the email arrives from a recognisable sender, it says exactly what failed and what happens next, and it has one button to a hosted page where the card can be updated without logging in to anything else. A sequence we would start from:
| When | Message | Purpose |
|---|---|---|
| Day 0 (first failure) | "Your payment didn't go through" with the amount, the card's last four digits and an update link | Most fixes happen here; keep it short and neutral |
| Day 3 | Reminder, same link, mention that access continues for now | Catch people who missed the first email |
| Day 7 | Reminder that names the date access will change | Create a clear, honest deadline |
| Final retry day | Last notice: what happens today and how to restore the account | No surprises when access changes |
| After the window | Account paused or downgraded; one-click restore link | Make coming back easy |
For B2B accounts, send the messages to the billing contact and, where you have one, the account owner: the person who uses the product is often not the person whose card is on file. An in-app banner for admins is worth adding once you have more than a handful of customers.
Step 3: Decide what happens to access
Decide this before you launch, because it is a product decision as much as a technical one. Stripe, for example, lets you choose what a subscription does once retries are exhausted: cancel it, mark it unpaid, leave it past_due, or pause it where eligible. Whichever you pick, map each billing state to a clear level of access in your application:
- Active: full access.
- Past due (inside the retry window): full access plus a banner. Cutting access on day one punishes customers for their bank's mistake.
- Unpaid or paused (after the window): read-only access or a locked workspace, with data kept. Deleting data because a card expired is rarely what anyone wants, and may conflict with what your terms promise.
- Cancelled: follow your published data-retention policy, with an export option. See our guide to GDPR and SaaS legal basics for retention and deletion.
Step 4: Handle the webhooks properly
This is where most custom billing integrations go wrong. Your app should learn about payment state from the billing provider's webhooks and store it, rather than assuming a payment succeeded because the checkout page redirected. Stripe's webhook documentation sets out the rules that matter:
- Verify the signature on every event using the endpoint's signing secret and the raw request body; otherwise anyone can post a fake "paid" event to your endpoint.
- Expect duplicates. Stripe says an endpoint may receive the same event more than once; log processed event IDs and skip repeats.
- Do not rely on order. Stripe does not guarantee events arrive in the order they were created, so fetch the current subscription state from the API when an event arrives rather than applying events as a sequence of changes.
- Return a 2xx quickly and do the work in a background job. Stripe retries undelivered live-mode events for up to three days with exponential back-off, so a slow or failing endpoint causes repeated deliveries.
- Listen to the events you need, typically
invoice.payment_failed,invoice.paidandcustomer.subscription.updated/deleted, rather than every event type.
Billing edge cases to test before launch
| Edge case | What goes wrong | How to handle it |
|---|---|---|
| Card needs authentication (SCA / 3D Secure) | The renewal cannot complete without the customer present | Email a link to a hosted page where they can authenticate; do not keep retrying silently |
| Customer updates the card in the wrong place | Retries keep using the old card | Stripe retries the subscription's default payment method first, so update the payment method on the subscription, not only on the customer |
| Plan change mid-cycle | Unexpected prorated charge fails | Show the proration amount before confirming; treat a failed proration like any other failed invoice |
| Seat added on a failing account | More usage on an unpaid account | Block upgrades while past due, or require payment first |
| Refund or dispute | Access stays on after the money has gone | Listen for refund and dispute events and flag the account for review |
| Free trial ends without a card | Account converts to nothing | Decide whether trials need a card up front; send a reminder before the trial ends |
| Annual renewal | A large charge fails after a year of silence | Send a renewal notice in advance and check local consumer-law rules on renewal reminders |
| Taxes and invoices | B2B buyers need a VAT/GST number on the invoice | Collect tax IDs at checkout and use the provider's tax tools or a tax adviser |
Measure it
Track three numbers each month: the share of renewal invoices that fail on the first attempt, the share of those recovered by retries and emails, and the revenue lost after the window closes. If recovery is low, look first at the emails (are they reaching the billing contact?) and the hosted update page (does it work on mobile?) before tuning retry timing.
When to build more than this
For an early SaaS, the billing provider's built-in retries, emails and hosted pages are usually enough, and building your own dunning engine is a distraction; see what not to build in a SaaS. Custom work starts to pay off when you invoice large B2B accounts by bank transfer, sell through resellers, need usage-based billing reconciled against your own metering, or run several billing providers in different regions.
Frequently asked questions
What is dunning in SaaS?
Dunning is the process of recovering a failed subscription payment: automatic retries of the charge, a sequence of emails or in-app notices asking the customer to update their payment details, and a defined change to the account if the payment is not recovered by the end of the retry window.
How many times should a failed subscription payment be retried?
There is no universal number. Stripe's documentation gives a recommended default for its Smart Retries feature of 8 tries within 2 weeks, and lets you choose windows from 1 week to 2 months. Hard declines such as a lost or stolen card should not be retried at all without a new payment method.
Should I cut off access as soon as a payment fails?
Usually not. Most failures are not a decision to leave, so keep access during the retry window and show a banner. Change access at the end of the window, preferably to read-only or paused rather than deleting data.
Do I need to build my own dunning system?
Not at the start. Billing providers such as Stripe include automatic retries, customer emails and hosted pages for updating payment details. Your job is to connect their webhooks to your application's access rules correctly and test the edge cases.
Sources
- Stripe Docs: Automate payment retries (Smart Retries) — Smart Retries; recommended default of 8 tries within 2 weeks; retry windows; custom schedules of up to three retries; non-retryable hard decline codes; payment-method retry order; end-of-retry subscription states (cancel, unpaid, past due, pause). Accessed 19 October 2026.
- Stripe Docs: Receive Stripe events in your webhook endpoint — Signature verification with the raw body; duplicate events; no ordering guarantee; returning 2xx quickly; automatic retries of undelivered live-mode events for up to three days. Accessed 19 October 2026.
Recommendations without a source are AI Dev Planner’s own engineering opinion. Platform features and prices change; check the linked pages for the current position. Found an error? See our corrections policy.
Related guides
- Pricing, Metrics & Business ModelSaaS Pricing Strategy: Choosing Between Value, Usage, Seats and FreemiumPick a value metric, check your unit costs, and price AI features so heavy users don't erase your margin.
- Pricing, Metrics & Business ModelSaaS Metrics That Matter: MRR, Churn, Activation, LTV and How to Reduce ChurnFormulas for MRR, churn, retention, activation and LTV, the vanity metrics to ignore, and a churn reduction playbook.
- Building & Shipping ProductsWhat Not to Build in a SaaS: Build vs Buy for Auth, Email, Analytics and PaymentsA build-or-buy table for auth, email, billing, analytics, search and more, plus the criteria for deciding.
Browse all 50 questions in the SaaS & web development guide.
Need billing that doesn't leak revenue?
We build Stripe subscription billing into SaaS products, including webhooks, access rules and the edge cases above. Tell us how you charge and we will tell you what to build and what to leave to Stripe.