Stripe webhook reference
Stripe customer.subscription.deleted
The webhook that fires when a Stripe subscription truly ends. The most common bug: treating it as the cancellation moment when it's actually the end-of-period moment, weeks too late for the exit email.
Quick answer
customer.subscription.deleted fires when the subscription period ends after a cancellation, not when the customer hits cancel. Listen for customer.subscription.updated with cancel_at_period_end=true to catch the cancellation moment. Use cancellation_details.reason to split voluntary vs involuntary churn.
The cancel_at_period_end gotcha
By default, when a customer cancels mid-period in your billing portal, Stripe sets cancel_at_period_end=true and keeps the subscription active until the period elapses. The event that fires at that moment is customer.subscription.updated, notcustomer.subscription.deleted.
If you wait for customer.subscription.deletedto trigger your exit-feedback email, you'll send it days or weeks after the customer decided to leave. By then they've moved on. Reply rates collapse from ~20% (sent at the moment of decision) to ~3% (sent weeks later).
Voluntary vs involuntary churn
The cancellation_details.reason field tells you why the subscription ended. Treat the two groups completely differently:
| cancellation_details.reason | Meaning | Right follow-up |
|---|---|---|
| cancellation_requested | Customer chose to leave | Plain-text exit email asking why |
| payment_failed | Dunning exhausted, card never fixed | "We couldn't charge your card. Reactivate here" |
| incomplete_expired | Initial payment never completed | Onboarding follow-up, not exit email |
FAQ
When does customer.subscription.deleted fire?▼
Difference between cancel_at_period_end and customer.subscription.deleted?▼
How do I detect a cancellation immediately?▼
What's in the customer.subscription.deleted payload?▼
How do I distinguish voluntary from involuntary churn?▼
Should I send an exit email on customer.subscription.deleted?▼
What if cancel_at_period_end is true on the deleted event?▼
How does ChurnNote handle customer.subscription.deleted?▼
Catch cancellations the moment they happen.
ChurnNote listens for both .updated (cancel moment) and .deleted (period end), routes voluntary cancellers into exit-feedback and involuntary ones into reactivation. $12/mo flat.
Get started