Stripe past_due vs unpaid: what each subscription status actually means
June 8, 2026 · 6 min read
When a renewal charge fails, Stripe moves the subscription — but where it lands depends on a setting most founders never reviewed. Understanding Stripe past_due vs unpaid is the difference between treating a failure as a recoverable retry window and writing it off as churn. The short version: past_due means Stripe is still trying, and unpaidmeans Stripe has stopped. Everything you do to recover that revenue hinges on knowing which state you're in.
The short answer
Two states, two completely different meanings. past_due is the retry window: at least one renewal payment has failed, but Stripe is still attempting the charge on a schedule. The customer usually still has access, and the invoice is still collectible. unpaid is the end of the line: Stripe has exhausted its retry attempts and applied whatever terminal behavior you configured.
The part that surprises people: whether an exhausted subscription lands in unpaid or jumps straight to canceledis a billing setting you chose — often by accepting a default during setup. Same failure, different outcome, entirely because of a checkbox in your Stripe dashboard.
The full lifecycle: active to past_due to unpaid or canceled
Here is how a subscription moves through the renewal-failure path, what triggers each transition, and what Stripe does on its own at each step:
- active— the normal, paid state. On the renewal date Stripe generates an invoice and attempts payment. If it succeeds, you stay active and nothing else happens.
- past_due— entered the moment a renewal invoice fails on its due date. Stripe keeps the subscription here and automatically retries the open invoice on your configured schedule. Each failed attempt fires an invoice.payment_failed event. The customer typically keeps access during this window.
- unpaid — entered after retries are exhausted, ifyour terminal setting is “mark unpaid.” Stripe stops retrying, keeps the subscription record, and leaves the invoice open. Access is usually revoked, but the relationship is preserved.
- canceled — entered after retries are exhausted ifyour terminal setting is “cancel.” The subscription is closed out and treated as a terminal state.
Two edge cases worth pinning down. incomplete and incomplete_expired apply only to the firstinvoice of a brand-new subscription — when the initial payment needs confirmation (for example, 3D Secure) and hasn't completed. They are not part of the renewal-failure path, so a subscription that has ever been active won't revisit them. And neither trialing nor active ever jumps straight to unpaid: a renewal failure always routes through past_due first, because unpaid only exists after a retry cycle has run and failed.
What controls whether you end up unpaid or canceled
The terminal behavior lives in your Stripe billing settings. In the dashboard, look under Settings → Billing(the revenue-recovery / retries section), where you configure the retry schedule and the “after retries” behavior for when attempts run out. As of writing, the options come down to three trade-offs:
- Leave in past_due— keep retrying or keep the customer in limbo with access intact. Useful short-term, but a subscription stuck here forever is neither collecting nor churning cleanly.
- Mark unpaid— revoke access (your app should gate on the status) while keeping the subscription and its open invoice on the books. This is the recoverable middle ground.
- Cancel— hard-close the subscription. Clean for reporting, but it throws away the live billing relationship and forces a full re-subscribe to recover.
Most founders should not leave subscriptions parked in past_due indefinitely. An open retry window is the right place to work a recovery, but a subscription that never resolves there pollutes your active count and quietly bills nobody. Pick a deliberate terminal state instead of inheriting whatever default shipped with your account.
What Stripe stops doing once a subscription is unpaid
The most important thing about unpaid is what goes silent. Once a subscription crosses into it:
- Automatic retries stop.Stripe will not attempt the open invoice again on its own — the schedule is finished.
- The scheduled invoice.payment_failed events stop firing.If your dunning logic keys off that event, it goes quiet exactly when you might assume there's “nothing left to do.”
- next_payment_attempt becomes null on the invoice. This is your cleanest programmatic signal that Stripe has given up retrying and the next move is yours.
- The invoice stays open or uncollectiblerather than being deleted. The record persists so you can collect later or reconcile — the money is still owed, not erased.
What you should do at each state
Each state wants a different play. Match the action to where the subscription actually is:
- past_due— this is your active recovery window. Run a dunning sequence and keep the invoice's hosted_invoice_url(or a no-login card-update link) fresh in every message while Stripe's retries run in parallel. Most of the recovery happens here.
- unpaid— retries are done, so the goal shifts to getting a new payment method on file, then re-attempting the open invoice or creating a fresh recovery invoice against the updated card. Don't keep sending “we'll try again” emails — Stripe won't.
- canceled— the billing relationship is closed, so route to a win-back, not a dunning email. The message is “come back,” not “update your card.”
Detecting each state is straightforward. Read subscription.status for past_due, unpaid, or canceled, and watch the webhook stream: invoice.payment_failed while retries run, customer.subscription.updated when the status flips, and invoice.payment_succeeded when a recovery lands. Treat a null next_payment_attemptas the boundary between “Stripe is still trying” and “over to you.” For the broader playbook, see our guide on how to reduce involuntary churn.
Common mistakes that turn recoverable revenue into churn
The failure mode is almost never the failed card — it's how the states get handled:
- Leaving the terminal action on a default you never reviewed.If you don't know whether exhausted retries land in unpaid or canceled, you don't know what your recovery flow is even allowed to do.
- Revoking access on day one of past_due. The retry window exists precisely because a lot of failures are transient (insufficient funds clearing near payday, a temporary issuer hold). Cutting access immediately turns a recoverable hiccup into a reason to leave.
- Sending the same generic email at past_due and unpaid.“Your payment failed, we'll retry” is wrong once Stripe has stopped retrying. The two states need different copy and a different call to action.
- Treating unpaid as permanently lost. An unpaidsubscription still has a live customer record and an open, collectible invoice. A meaningful share of it comes back with a single card update — treat it as a recovery queue, not a graveyard.
Where Backstop fits
Backstop works the past_due window for you: decline-aware smart retries plus a real 4-touch dunning sequence sent from your own verified domain, before Stripe ever reaches its terminal state. It keeps the no-login update-card link fresh in every message and stops emailing the moment the invoice is paid or next_payment_attemptgoes null — so you never nag a customer who already fixed it. For subscriptions already sitting in unpaid or canceled, it routes them to recovery or win-back instead of dead silence. It runs on top of your existing Stripe setup in about ten minutes — start free or compare the pricing, and see exactly how it wires in via how it works.
Backstop recovers failed Stripe payments and saves canceling subscribers.
Smart retries, a visual cancel flow, and a hosted portal — flat $79/mo, a free tier, and 0% revenue share.