Guide · facts checked 4 Nov 2026
Voluntary vs involuntary churn in Stripe: split it before you fix it
Voluntary churn is a customer choosing to cancel; involuntary churn is a subscription that ends because a payment failed. Stripe tells them apart in cancellation_details.reason: cancellation_requested for an explicit cancel, payment_failed for a cancel after failed payments. Each half has its own fix: a cancel flow works at the moment a customer decides to leave, and payment retries and emails work on the invoice.
The two kinds side by side
| Voluntary | Involuntary | |
|---|---|---|
| What happens | The customer decides to leave and cancels. | A renewal payment fails, retries run out and the subscription ends or stalls. |
| Stripe signal | cancellation_details.reason = cancellation_requested | cancellation_details.reason = payment_failed, or an invoice.payment_failed event before it |
| Where you can act | On the cancel page, before the cancel is confirmed. | On the invoice: retries, card updates, customer emails. |
| Tool that fits | A cancel flow with an offer matched to the reason. | Smart Retries, customer emails, automatic card updates. |
Stripe’s reference describes the two values this way: cancellation_requested is “canceled explicitly through the API or Dashboard”, and payment_failed is “canceled automatically after payment failure, according to your billing settings”. The same field has two more values: payment_disputed, a cancel after a dispute was opened, and canceled_by_retention_policy, which Stripe uses for expiring test-mode subscriptions. Because cancellation_requested also covers cancels you make yourself in the Dashboard or API, take those out before you read the bucket as customers choosing to leave.
Split your own churn in three steps
- List the cancellations. Pull the subscriptions that ended in the period, or collect
customer.subscription.deletedevents as they arrive. - Group by
cancellation_details.reason. Four buckets at most:cancellation_requested,payment_failed,payment_disputed, anything else. - Add the subscriptions that did not cancel. Stripe lets you choose what happens when retries are exhausted: cancel the subscription, mark it unpaid, leave it past due or pause it. Only the first option moves the status to
canceled. Countunpaidandpast_duesubscriptions as their own line, or an involuntary problem will look smaller than it is.
The result is a split like “N cancelled by the customer, N ended on payment failure, N stuck unpaid”. That split, not the overall churn rate, tells you where to spend the next hour.
What Stripe gives you for the involuntary half
- Smart Retries. Stripe describes it as AI choosing the best times to retry failed payments. For new Stripe accounts it is on by default, configured for up to 8 retries within 2 weeks; you can set the window to 1 week, 2 weeks, 3 weeks, 1 month or 2 months.
- A custom schedule instead: up to three retries, each a set number of days after the previous attempt.
- Customer emails when a payment fails, a card expires or a payment method needs an update, and automatic card updates when a customer gets a new card number.
- Automations, a no-code way to build your own recovery logic and different retry policies for different customer segments.
Two limits to know from Stripe’s retry page. Stripe does not retry when no payment method is available, when the card is India-issued, or when the Connect account was disconnected. For hard declines (such as a lost or stolen card) the scheduled retries stay on the calendar, but the charge only executes once a new payment method is on file. For those customers the lever is getting a new card from them, which is a message to the customer rather than a retry setting.
What a cancel flow does for the voluntary half
A cancel flow acts when a customer starts to cancel: it asks why, then offers a pause, a discount or a lower plan that matches the answer, and lets them cancel anyway. It never sees a customer whose card simply declined, so its results belong in their own column. When you judge it, use the cancellation attempts as the denominator and a holdout as the control, as set out in what counts as a save. The reasons it collects are read in reading cancel reasons.
The two halves also meet at one spot: pausing. Stripe can pause an eligible subscription after a payment failure instead of cancelling it, and a cancel flow can offer a pause to someone who says they do not need the product right now. Both arrive as paused subscriptions, so label which one you are looking at.
A short checklist
- Is Smart Retries on, and is the window long enough for your billing cycle?
- What happens to the subscription when retries are exhausted, and are the unpaid or past-due ones counted somewhere?
- Do you split cancellations by
cancellation_details.reasonevery month? - Does every voluntary cancel go through a page that asks why and keeps “Cancel anyway” one click away?
Work on the half you can reach today
Run a sample cancel session: play a subscriber, give a reason, and see which offer is chosen and the Stripe change behind it.
90 seconds, no sign-up. You play the subscriber; the AI answers, and “Cancel anyway” is always one click away.