How to Track Failed Stripe Payments and Involuntary Churn
Oct 12, 2026 · Matt
But a meaningful share of lost revenue comes from customers who never decided to leave: a renewal payment failed, recovery attempts ended, and the subscription became unpaid or was canceled under the business's configured Stripe settings. That is different from a voluntary cancellation.
Some of this revenue can be recovered because the underlying problem may be a temporary decline or payment-method issue rather than a decision to leave. Recovery is not guaranteed, and the appropriate response depends on the decline guidance, retry stage, customer value, and whether customer action can resolve the failure. During recovery, a subscription can be `past_due` while the related invoice remains `open`; later outcomes depend on the account's configured settings.
This post covers how to track failed payments from Stripe data, separate involuntary churn from the voluntary kind, and build a recovery process that runs on numbers you can trust.
Why failed payments are easy to lose track of
When payment for an automatically collected renewal invoice fails, the invoice generally remains `open` and the subscription can move to `past_due`. Stripe then follows the account's configured recovery workflow, which can include Smart Retries, customer emails, or custom automations. If recovery attempts do not succeed, the final states still depend on the merchant's settings: a subscription may become `unpaid` or `canceled`, while an invoice can remain `open` or later be marked `uncollectible`.
Stripe Billing does surface this — its revenue-recovery dashboard shows your failure rate, recovery rate, top decline codes, and a table of customers whose payments recently failed and are still being retried. That's a real head start. (Smart Retries and this dashboard are part of Stripe Billing, a paid add-on at roughly 0.7% of billing volume.) What it doesn't do is let you rank those at-risk accounts by your measure of value (MRR, lifetime value, strategic importance), decide your own outreach priority, or work the list as a task with notes on who's been contacted and what came back. For that you need the underlying rows somewhere you can sort, annotate, and act on — otherwise recoverable revenue still slips away one expired card at a time.
Failed payments are the part of churn most people miscount. For the broader picture — voluntary vs. involuntary, customer vs. revenue churn — see How to Calculate Churn Rate from Stripe Data.
Voluntary vs. involuntary churn — and why the split matters
Lumping all churn together hides your most fixable problem. The two kinds call for completely different responses:
Voluntary churn — the customer chose to cancel. The fix is product, pricing, or value: a retention problem.
Involuntary churn — the payment failed. The fix is billing mechanics: better retries, card-update prompts, and timely outreach. A recovery problem.
If 30% of your churn is involuntary and you're treating all of it as a product problem, you're rebuilding features when you should be sending "your card on file expired" emails. Splitting the two tells you where the recoverable money actually is.
The Stripe signals to track
Failed-payment tracking lives across a few Stripe objects. The ones worth pulling into a sheet:
Invoice status — `draft`, `open`, `paid`, `uncollectible`, or `void`. For recovery work, focus on open automatically collected renewal invoices with an amount remaining or failed payment attempts; invoice status alone does not identify every at-risk account.
Subscription status — `active`, `past_due`, `unpaid`, or `canceled` for the recovery states discussed here. A transition associated with exhausted payment recovery may represent involuntary churn; use the related invoice and payment context rather than assuming every cancellation was payment-related.
Failed charges and their decline codes — such as `insufficient_funds`, `expired_card`, or `card_declined`. The code can guide the next action, but it does not establish a recovery probability on its own.
Retry context — Stripe's Invoice API can expose fields such as `attempt_count` and `next_payment_attempt`, but those fields are not currently included in SyncStaq's standard public sample tabs. Add them from another approved source if your recovery workflow requires exact retry timing.
Decline codes should guide the next action, not predict the outcome. Incorrect or expired details can often be addressed by asking the customer to update the payment method, while issuer declines may require different customer or bank action. No decline code guarantees recovery, so prioritize using both account value and the action Stripe recommends.
A worked example
Pull this month's failed renewals with their state and value, and the picture gets actionable fast:
Customer | MRR | Decline reason | Subscription status | Priority inputs |
|---|---|---|---|---|
Acme | $499 | expired_card | past_due | High value; payment-method update may help |
Borealis | $99 | insufficient_funds | past_due | Value, retry stage, and customer context |
Cedar | $250 | expired_card | past_due | Payment-method update may help |
Delta | $40 | do_not_honor | canceled | Review as churn; exclude from active recovery |
The three `past_due` accounts represent $848 in at-risk MRR in this hypothetical example. Delta is already canceled, so its $40 belongs in churn reporting rather than the active recovery total.
A recovery list should separate accounts still in a recovery window from subscriptions that have already ended, then rank the active cases using value and actionable decline guidance.
In this example, $848 of MRR remains in `past_due` subscriptions that may still be recoverable. Two accounts have expired-card decline reasons, which suggests a payment-method update request may help; Delta is already canceled and should be reviewed separately as involuntary churn.
Why this belongs in a spreadsheet
Failed-payment recovery is operational work: a regularly refreshed list of at-risk accounts, sorted using account value and actionable payment context, that someone actually reviews. A spreadsheet is useful because the team can filter by decline code, record outreach, and measure which recovery actions succeed.
The hard part is keeping that list current. Failed payments change state constantly — a retry succeeds, a past_due flips to canceled, a new renewal fails. A list you exported on Monday is wrong by Wednesday. And because the most common way to pull Stripe data filters by creation date, status changes that happen after an invoice was created are exactly the updates a manual export tends to miss. (More on that trap in Why Stripe Makes Simple Revenue Questions Hard to Answer.)
A setup that recovers more revenue
Keep Stripe data synced into Google Sheets — invoices, subscriptions, charges, and their statuses — refreshed automatically so state changes update the rows instead of going stale.
Split voluntary from involuntary churn so you know how much of your loss is a billing problem you can actually fix.
Build an hourly refreshed at-risk list using the invoice, subscription, charge, and customer fields that are actually present in your synced tabs. Add retry-stage data separately if exact next-attempt timing is required.
Prioritize using account value, retry stage, decline guidance, and whether customer action can resolve the problem. Test recovery outcomes rather than assuming one decline reason always produces the highest return.
Track recovery outcomes so you can see what your dunning + outreach is actually winning back each month.
This turns failed-payment churn into a measurable recovery workflow without assuming that every failed renewal can or should be recovered.
Stop letting recoverable revenue slip away in past_due limbo. SyncStaq keeps your Stripe invoices, subscriptions, and charges — with their current statuses — synced into Google Sheets every hour, so your at-risk and recovery lists refresh with the source data. See how the Stripe → Sheets sync works, or start a 14-day free trial.
Related reading: How to Calculate Churn Rate from Stripe Data and How to See Total Revenue by Customer in Stripe.