customer.subscription.deleted: email a customer when Stripe ends it
You have a paying customer whose subscription has just ended, and Stripe has sent one event and nothing else. The event doesn't say whether they chose to leave, and that matters, because someone whose card kept failing n
You have a paying customer whose subscription has just ended, and Stripe has sent one event and nothing else. The event doesn't say whether they chose to leave, and that matters, because someone whose card kept failing never decided anything, and a "sorry to see you go" note is the wrong thing to send them. The few who did choose to leave are worth one short email asking why, and their reply is where you learn something. The guide below shows when Stripe sends the event, how to read its reason, and the email I would send.
The short answer
When a subscription ends, Stripe sends an event called customer.subscription.deleted. It is the moment a paying customer stops being one, and the best thing to send is short: say it has ended, ask why in one line, and leave the door open.
The event on its own, with the fields worth reading, is on the customer.subscription.deleted page.
When Stripe sends it
It depends on how the subscription was cancelled.
-
At the end of the period. Most cancel buttons, Stripe's customer portal included, cancel at the end of the period the customer already paid for. Stripe sends
customer.subscription.updatedwithcancel_at_period_endset totruewhen they press it, andcustomer.subscription.deletedwhen the period runs out. -
Straight away. A subscription cancelled at once sends
customer.subscription.deletedright away. -
After failed payments. If payments keep failing and your Stripe settings cancel the subscription when retries run out, it ends the same way, with
cancellation_details.reasonset topayment_failed.
That last one matters. Somebody whose card expired never decided to leave, and "sorry to see you go" is the wrong email for them. Check the reason before you send anything.
Your own webhook
- Add a webhook endpoint in Stripe that listens for
customer.subscription.deleted. - Check the signature on every request. Stripe signs each one in a
Stripe-Signatureheader and needs the raw body untouched. - Return a 2xx fast and send the email after. Keep the event ids you have handled, because an event can arrive twice.
const event = stripe.webhooks.constructEvent(rawBody, signature, endpointSecret);
if (event.type === "customer.subscription.deleted") {
const subscription = event.data.object;
const reason = subscription.cancellation_details?.reason; // "cancellation_requested", "payment_failed", ...
const customer = await stripe.customers.retrieve(subscription.customer as string);
// customer.email, customer.name
}
The subscription carries the customer's id rather than their email, so fetch the customer. If your portal asks why they're leaving, cancellation_details.feedback and cancellation_details.comment hold the answer, and your email shouldn't ask again.
What the email should say
Keep it to a few lines, from you, with nothing to sell.
Subject: Your [your app] plan has ended
Hi {{first_name}},
Your [your app] plan has ended, and you won't be charged again. Your account and everything in it is still here if you come back.
Could you tell me why you left? One line is plenty, and you can reply to this email.
[Your name]
The reply is the useful part. A cancellation survey email template has more ways to ask, and win-back emails cover what to send weeks later.
FAQ
Is customer.subscription.deleted the same as a cancellation?
It's the end of the subscription. A customer who cancels at the end of the period has cancelled before this event arrives, and is still paying until it does.
Should I email when they press cancel, or when it ends?
When it ends is the safer default, because it's when the change is real. You can also send a short "got it" when they press cancel and keep the question about why for when it ends.
What if a failed payment ended it?
Send the failed payment email instead, with a way to update the card. That customer may want to stay.
This article was written with the help of AI.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.