Stripe Dunning: How Stripe's Built-In Retry Logic Works (and Where It Falls Short)

Stripe dunning combines Smart Retries, payment-failure emails, and a hosted card-update page to recover failed subscription payments, but three settings (retry window, subscription end-state, account updater enrollment) decide how much of that recovery you actually capture.

Author
Theodore Sterling
Date posted
August 3, 2026
Category
Payment recovery
Time to read
X min

Stripe dunning is the set of built-in tools Stripe uses to recover failed subscription payments. You get Smart Retries, automated payment-failure emails, and a hosted card-update page. It works well within its defaults, but those defaults need configuration, and three settings can quietly limit how much you recover.

I've spent the last few years consulting on retention for SaaS and subscription businesses. The most consistent dunning mistake I see isn't the retry schedule. It's that teams leave Stripe's defaults untouched and assume they're already set up for recovery.

Get the three settings right, and every recoverable payment gets worked before a subscriber churns or the invoice link dies.

Key takeaways

  • Combine smart retries, payment-failure emails, and a hosted card-update page.
  • Verify your retry window, subscription end-state, and account-updater enrollment.
  • Choose "mark as unpaid" as the end-state to keep recovery alive after retries.
  • Enable account updater before Smart Retries to stop card-expiry failures early.
  • Refresh dunning links before day 30, when the hosted invoice link expires.
  • Skip hard decline codes like stolen, lost, and pickup card.

What is Stripe dunning?

In subscription billing, Stripe dunning is the set of built-in tools Stripe uses to recover failed subscription payments. Those tools are Smart Retries, automated payment-failure emails, and a hosted card-update page.

The term dunning gets used two ways, so it's worth pinning down. In accounts receivable it means chasing overdue invoices, but in subscription billing it means automatically retrying a failed charge and prompting the customer to fix their card.

Each tool handles a different failure type:

  • Smart Retries re-times the charge for soft declines, the temporary rejections a network lets you retry.
  • The hosted invoice page takes card-update requests when a card has expired or been replaced.
  • Emails prompt the subscriber to act before the retry window closes.

That split matters because a failed payment is an involuntary churn problem, not a voluntary one. The subscriber didn't choose to leave, their card did. So the job is to make the recovery path quick and easy for a customer who still wants to pay.

One scope note. Stripe dunning only applies to subscription invoices Stripe collects automatically. Smart Retries won't touch a one-off invoice on manual collection, so that invoice needs its own outreach.

How Stripe Smart Retries works

Your retry window, your subscription end-state, and your account updater enrollment together decide how much of your recoverable revenue Stripe dunning reaches.

I call these three the Stripe Dunning Configuration Checklist, and you set all of them in one place under Billing > Revenue recovery > Retries. Most teams leave them at the defaults and never look again.

You check the three together because they interact. A long retry window does nothing if a misconfigured end-state cancels the subscription the moment retries exhaust. Account updater decides how many failures even reach the retry queue, so it changes how much work the other two have to do.

The full dunning playbook walks through all three together.

Setting 1: Retry window

Match the Smart Retries window to your subscriber's billing cycle. Stripe's recommended default is 8 retries within two weeks, which suits monthly subscribers. For annual subscribers, where the billing event is rare, a longer window of one to two months fits better.

The configuration decision is the point here, not the default number, which the smart retry timing rules cover in depth.

Smart Retries uses machine-learning signals to pick the best moment inside that window. Stripe's published examples include how many different devices presented a card recently and the time of day a given card type tends to clear.

The window length sets how much room the model has to work. A shorter window gives it fewer chances to find a favorable moment. A window shorter than the billing cycle is worse, because some charges fail and close before the next renewal would have reset the cardholder's balance.

Stretching the window past 30 days creates a second problem, though. The card-update link in your dunning emails expires before a long window closes, so any email you send in week five points to a dead page. The next section covers why.

Setting 2: Subscription end-state

Set the end-state to "mark as unpaid" when retries run out. Cancellation ends any layered recovery campaign and turns reactivation into a fresh sign-up instead of a simple card update. "Mark as unpaid" lets recovery continue, while "cancel" stops it.

The difference is what each one does to the subscription record.

"Mark as unpaid" preserves the record and the customer's data, so a downstream tool or a Stripe Automation can keep reaching out after the retry window closes. "Cancel" fires Stripe's subscription-deleted event, which most billing systems treat as a final state and use to stop all recovery.

Picture a subscriber whose card fails while your setting is "cancel after retries." Smart Retries works for two weeks. On day 15 the subscription cancels, and your recovery tool loses the record.

Switch the setting to "mark as unpaid," and the record stays open so the subscriber can still update their card.

The third option, "leave past-due," is a fair middle ground for teams that drive their own recovery from Stripe webhooks. It needs custom webhook handling to avoid piling up unpaid invoices forever, so "mark as unpaid" is the safer default until you've built that.

Setting 3: Account updater enrollment

Enable account updater before you lean on Smart Retries, because it stops most card-expiry failures from reaching the retry queue. In one line, account updater refreshes a stored card's credentials when the card expires or gets reissued.

It's the most effective of Stripe's built-in tools, because it runs before a charge is even attempted.

The sequencing is the whole point. When a stored card is expiring or has been reissued, account updater refreshes the number before the next billing cycle fires, so most of those charges never fail.

Smart Retries runs after a failure, working a problem account updater would have prevented. Turn account updater on first, and Smart Retries only handles what's left.

There's a cost to weigh on cheap plans. Stripe charges a per-update fee, and for low-revenue products under about $10 a month, that fee can approach the margin on a recovered charge. Check the math before enabling it at scale.

The hosted_invoice_url expiry trap

Stripe's hosted_invoice_url, the card-update link in every dunning email, expires 30 days after the invoice due date. A subscriber who clicks a dunning email more than 30 days after the failure sees an expired-link page instead of a payment form.

This is the quiet failure that undoes a retry window stretched too long.

Stripe does offer a recovery path. A subscriber can enter their email to get a fresh link, but only if they originally received the invoice through Stripe's own email system.

For anyone who didn't, the expired link shows a "contact support" message with no self-service option, which makes the dunning email a dead end. The customer who still wanted to pay now has to wait for a human reply, and most won't.

There's a way around it for teams with the engineering to use it. A link retrieved through the Stripe API stays valid for at least 10 days from the moment you fetch it. So a layered tool that refreshes the link by API before each email sidesteps the expiry entirely.

Hard declines: what Smart Retries won't touch

Smart Retries works soft declines but skips hard decline codes, the permanent failures like stolen_card, lost_card, pickup_card, and revocation_of_authorization, because a hard decline will never clear on a retry.

For these, Stripe's scheduled retries still fire but never succeed, so the retry window gets spent on a charge that was never going to clear.

A hard decline needs a different response than a retry. Send a card-update request for a replaceable card, or set a direct involuntary-churn flag for an account that's permanently closed. Retrying adds no recovery value, and on certain codes it adds a per-attempt network fee instead. 

The full sorting of hard decline vs. soft decline handling lives in the cluster article.

Stripe does give you the raw material to handle this yourself. It surfaces the reason in the invoice's last_payment_error.decline_code field. A team with webhook infrastructure can read that field and route hard declines straight to a card-update flow.

That beats waiting out the retry window on a charge that can't clear.

What Churn.io adds to Stripe's native dunning

Churn.io's dunning layer adds three things Stripe's built-in tools lack. Together they catch the subscriber Stripe's retries miss, the one who ignores every email and quietly reaches the "mark as unpaid" end-state. The three are:

  • Behavioral exit-intent triggers: reach a subscriber who is about to leave over a failed payment.
  • Churn-reason capture: record why the subscribers who never recover decided to go.
  • Cancel-flow integration: route a dunning failure into a save offer rather than a silent cancel.

The gap is in how each side defines success. Stripe counts dunning as won when the payment clears. Churn.io counts it as won when the subscriber stays, with a captured reason if they leave anyway.

That difference is the line between voluntary and involuntary churn tooling. Retries fix the billing failure. A save flow keeps the customer who ignored every email and would otherwise have slipped through.

One order-of-operations note. The layer works on top of Stripe's native stack, so the configuration checklist comes first. Churn.io's campaigns assume Smart Retries has already run and that your end-state is "unpaid" rather than "canceled."

Use the churn rate calculator to size the revenue at stake before you configure the three settings.

FAQ

Does Stripe automatically enable Smart Retries, or is it off by default?

Smart Retries is on by default for Stripe Billing subscriptions, set to the recommended 8 retries within two weeks. The window and the end-state are yours to change, so "on by default" doesn't mean "configured for your billing cycle."

What happens to my subscriber when Stripe's retries run out?

What the subscriber sees depends entirely on your end-state setting. With "cancel" they get a cancellation notice and lose access, while "mark as unpaid" keeps the subscription open so they can still update their card to restore it.

Should I use Smart Retries or a fixed retry schedule?

Use Smart Retries unless you have a specific reason not to, because its ML timing beats a fixed schedule for most monthly subscribers. A fixed schedule only makes sense when you drive recovery from your own webhook logic and need predictable, hard-coded retry dates.

Can I A/B test my Stripe dunning emails?

No, because Stripe's native dunning emails are single-channel and don't support A/B testing or segmentation. Testing subject lines or copy means handling the emails through a layered tool instead.

Theodore Sterling

Share this article: