The card failed. Retrying it is not dunning.
Dunning is the conversation after a Stripe invoice fails — not the silent retry of the card. How to recover failed payments and stop involuntary churn without sounding like a debt collector.
Renewal day. Stripe tries the card. The bank says no. In the dashboard the subscription flips to past due. In the background the processor will likely try the charge again. The customer who would have updated their card this afternoon hears nothing from you — or they get a generic note that looks like it came from the payment form, not from the product they actually use.
That gap is involuntary churn: they did not cancel. The payment failed, and nobody ran a proper follow-up. Dunning is that follow-up.
What dunning means
In subscription billing, dunning is the process of recovering a failed payment before the customer lapses — by asking them to fix what broke, and by retrying the charge only when a retry can still work.
The word is old English: to dun someone was to persistently ask for money that is owed. In SaaS it is not a collections letter. Glossaries used by billing platforms (Recurly, Zuora) draw the same line: a retry resubmits the transaction; dunning is the workflow around it — the emails, the timing, the decision to stop.
If you only retry the card, you recovered a network. If you also talk to the customer, in your brand, you recover the invoice.
Dunning is not a retry. It is not collections either.
| What it does | When | |
|---|---|---|
| Retry | Sends the same charge back to the bank | Soft, temporary declines |
| Dunning | Tells the customer what happened, gives them a way to update the card, retries only when it still makes sense, stops the moment the invoice is paid | Right after invoice.payment_failed, while they still wanted to stay |
| Collections | Chases a debt after you have given up on “they still want this product” | Late, manual, assertive |
People search “failed payment recovery”, “dunning emails”, “dunning management”. They all point at the middle row. A silent retry is the first row. A threatening “pay now or we close your account” mail is already sliding into the third.
Why Stripe invoices fail
Most failed subscription charges fall into a handful of buckets, visible directly on the Charge object's outcome in your own Stripe data. The decline code should change what you do next.
- Expired or replaced card — the customer has a new number and does not know you still hold the old one. Retrying the dead card does nothing. They have to update.
- Insufficient funds — often a timing problem. A retry a few days later can work. An email the same hour that sounds like a threat does not.
- Bank or fraud filter — 3-D Secure friction, a block on recurring charges, a flag on an unfamiliar merchant. Another immediate retry can make it worse.
- Lost, stolen, or closed card — a hard decline. No schedule will collect it. The only move is a clear “update your payment method” path.
One generic “your payment failed, update your card” email treats all four as the same event. That is why a sequence that never looks at the decline type feels busy and recovers little.
What a processor retry leaves on the table
Stripe will retry a failed invoice on a schedule. That is collection: the charge goes back to the network. Useful for a soft decline. Useless, by itself, for an expired card.
Stripe does let you add your logo, brand colors, and even a custom sending domain to its own notifications — the surface was never the gap. The gap is what happens behind the email: that retry logic does not know this customer has been with you two years while that other one is three days into a trial. It does not move the day or the hour a message goes out based on when a customer actually opens mail. It does not offer a pause or a coupon instead of losing the subscription outright. And the moment the customer actually cancels, it stops looking at them entirely — there is no follow-up built in for someone who already left.
Keep the processor retry on if you want. You are not buying a nicer-looking retry from a dunning tool. You are buying the decisions the retry cannot make on its own.
What a good dunning sequence actually does
Timing
Front-load a card-update note when you can see an expiry coming (pre-dunning). After a failure, space follow-ups around the retry window — not on top of every automatic attempt. Three calm emails over a week beat seven “urgent” ones in 48 hours.
Tone
The mail that works reads like an account note: “The last payment for [Plan] did not go through. Update your card here.” Urgency, guilt, and “final notice” copy belong to collections. Dunning assumes they still want the product.
Hard path vs soft path
Soft decline: tell them you will try again, and do. Hard decline: do not pretend another retry will save it — send the update link and wait for them. Tenure and plan value are the other two splits worth making: a trial and an annual plan should not share a script.
When to stop
The day the invoice is paid, dunning is over. Instantly. A reminder that lands after they already fixed the card is how automation earns a support ticket. If they cancel instead of paying, this sequence should end — that is a win-back, not another unpaid nudge.
How churnhook runs that sequence
churnhook connects to your Stripe account with Stripe Connect (OAuth — no secret key stored). When a subscription goes past due, unpaid, or incomplete, it lands on Unpaid: customer, plan, decline reason, how long it has been failing, where the run is.
Not a fixed 3-5-7 day cadence — a journey built per customer
A sequence is not one script sent to everyone on the same schedule. A Split branches on tenure, decline type, or invoice amount, so a two-year customer and a three-day trial never get the same message or the same offer. Timing is not "wait 3 days" on autopilot either: a wait step can land on a specific day of the week, inside the hour window you choose — the moment you know your customers actually open mail, not whatever a generic dunning schedule assumes.
The offers a processor retry can't make
This is where the real gap from a bare Stripe retry shows up. On a Leaving sequence, the same conversation can carry a live offer — Keep, a Coupon already sitting on your own Connect account, or a Pause — that the customer accepts in one click, applied instantly, with no manual work on your side. And if they cancel anyway, it does not stop there: a win-back sequence can reach out automatically afterward, with a time-limited coupon sent to a real Stripe Checkout on their old plan. Stripe's own retry schedule has nothing like this — it does not know the customer left, and it has nothing to offer them if it did.
A Retry invoice step still asks Stripe to charge again at the point you choose in all of this — if it succeeds, the run flips to recovered and no further mail goes out. Every sequence ends in a 72-hour Closing window so the job is bounded.
From Unpaid you can still act by hand: retry now, or copy a payment-update link that opens the card screen directly.
You can walk the whole path — failed payment, offer, win-back — in Stripe test mode with the simulation lab before anything touches a live customer.
If you are comparing dedicated recovery tools — or just want to know what Stripe already does on its own — see the full comparison. The short definition of dunning also lives in the glossary.
See how a sequence looks · Start the 60-day trial
FAQ
Isn’t retrying the card enough? For a short insufficient-funds blip, sometimes. For an expired or replaced card — the common case — a retry without a conversation never collects. Dunning is the conversation.
Is this debt collection? No. Dunning assumes a customer who still wanted to stay. Collections starts after you have decided they are a bad debt. The tone, the timing, and the stop condition are different.
Do I have to hand over a Stripe API key? No. Connect is OAuth. You can revoke it from your Stripe dashboard. No secret key from your account is stored.
Can I test this without touching real customers? Yes. Connect a test-mode account and run failed payments through the lab before you turn a live sequence on.
