
cancel subscription stripe: Step-by-step for Developers
cancel subscription stripe: Learn how to cancel Stripe subscriptions via API, Dashboard, or Customer Portal with code samples and best practices.
When it comes to cancelling a subscription in Stripe, you’re not locked into a single approach. You've got three solid options: you can do it manually through the Stripe Dashboard, automate it with the API, or let your users handle it themselves via the self-service Customer Portal. Each path offers a different degree of control and is built for different business needs.
Understanding Stripe Subscription Cancellation
Before you start writing code or clicking buttons, it's really important to get a handle on how Stripe thinks about subscription cancellations. It's not just a simple "off" switch. The choices you make here directly shape your customer's experience and how you recognize revenue, so it’s worth taking a moment to understand the fundamentals.
At the end of the day, your decision will come down to your business model and just how much control you want to have over the process.

The infographic above breaks down the flow for each of the three main cancellation routes—manual, programmatic, and user-driven—all of which funnel into Stripe’s powerful billing engine.
Key Cancellation Concepts
The single most important decision you'll face is when the cancellation actually takes effect. Stripe gives you two ways to play this:
Immediate Cancellation: This stops the subscription cold. The customer loses access to your service right away. While this might be necessary for certain situations (like a terms of service violation), it can feel a bit harsh for a customer who has already paid for the full month or year.
Cancellation at Period End: This is by far the more common and customer-friendly option. The subscription stays active until the end of the current billing cycle, and then it simply doesn’t renew. This feels fair—customers get to use the service they've already paid for.
Another term you'll hear is proration. This is just the practice of giving a credit or partial refund for any unused time when a subscription is changed or cancelled in the middle of a billing period. It's not usually a factor for cancellations at the end of a period, but it's a critical concept if you offer immediate cancellations and want to refund the difference.
Choosing Your Method
Deciding which cancellation method to use really comes down to your operational workflow and how you interact with your customers.
For a quick summary of your options, here’s a quick-glance table.
Stripe Cancellation Methods At A Glance
| Method | Best For | Control Level | Technical Effort |
|---|---|---|---|
| Dashboard | One-off manual cancellations by your support or admin team. | Full Manual | Low |
| API | Automated, in-app cancellations triggered by user actions or internal logic. | Full Programmatic | High |
| Customer Portal | Empowering users with self-service, reducing support tickets. | User-Driven | Medium |
This table shows that while the Dashboard is great for occasional, hands-on tasks, the API is essential for any kind of automated system. The Customer Portal, on the other hand, strikes a great balance, taking work off your plate by letting users manage their own subscriptions. It's a clean, simple interface where they can see their invoices, update payment methods, and cancel their plan without ever having to contact you.
It's no surprise that Stripe has become the go-to for subscription businesses. According to data from CoinLaw, roughly 78% of subscription-based SaaS companies rely on Stripe. Even more telling, its recurring payment volume is growing 16% faster than its one-time payment volume, which points to just how dominant the subscription model has become.
Tying Cancellations to Your App With the Stripe API
When you need to build cancellation logic directly into your application, the Stripe API is your best friend. This is how you let users cancel from within your app’s settings screen or automate cancellations based on internal triggers. You're essentially taking the manual work out of the Dashboard and putting the power right where it belongs: in your code.
Let's break down the two main ways you'll handle this.
The most common—and frankly, the most customer-friendly—way is to cancel a subscription at the end of the current billing period. This is the gold standard for SaaS and mobile apps. It lets the user keep access for the time they've already paid for, which is exactly what they expect. No surprises, no angry support tickets.
The other option is to cancel a subscription immediately. This is more of a "nuclear option" and is far less common. You'll typically reserve this for specific situations like rooting out fraudulent activity, enforcing a terms of service violation, or if a customer explicitly asks for an immediate stop (and maybe a refund).
Scheduling Cancellation for the Period End
When you let a customer finish out their paid period, you aren't actually deleting the subscription object in Stripe. That would be too final. Instead, you're just updating it and telling Stripe, "Hey, don't bill this person again."
You do this by setting the cancel_at_period_end flag to true.
This approach is fantastic because it's completely reversible. If a customer has a change of heart before their subscription officially ends, you can just flip that flag back to false, and they're back in business. It's a great way to salvage a customer who might have just been having a bad day.
Here's what that looks like in a real-world Node.js implementation:
// Using the official stripe-node library const stripe = require('stripe')('YOUR_SECRET_KEY');
async function scheduleCancellation(subscriptionId) { try { const subscription = await stripe.subscriptions.update(subscriptionId, { cancel_at_period_end: true, }); console.log('Subscription scheduled for cancellation:', subscription.id); // Now, update your internal database to reflect this change. // I usually set a 'cancellation_pending_date' or similar field. return subscription; } catch (error) { console.error('Error scheduling cancellation:', error); // Always handle API errors gracefully. throw error; } }
After running this, the subscription object you get back will have cancel_at_period_end set to true and a canceled_at timestamp showing the exact moment it will officially end.
My Two Cents: Stick with
cancel_at_period_endfor almost every scenario. It lines up with what users expect, cuts down on support noise, and even gives you a chance to win customers back. This simple choice has a big impact on reducing churn.
Pulling the Plug Immediately
For those rare times when you need to shut things down instantly, you'll use the subscriptions.del() method (or subscriptions.cancel() in newer SDKs). Be warned: this is a one-way street. There's no undo button. Once a subscription is cancelled this way, it's gone for good.
If that user ever wants to come back, you’ll have to create an entirely new subscription for them from scratch.
Here’s a simple way to do it in Python:
Using the official stripe-python library
import stripe
stripe.api_key = 'YOUR_SECRET_KEY'
def cancel_subscription_now(subscription_id): try: # This action is irreversible. Double-check you want to do this! deleted_subscription = stripe.Subscription.delete(subscription_id) print(f"Subscription {deleted_subscription.id} cancelled immediately.") # Make sure you revoke user access in your own database right away. return deleted_subscription except stripe.error.StripeError as e: print(f"Error cancelling subscription: {e}") # Handle specific Stripe errors (e.g., an invalid ID). raise e
The moment you call this, the subscription's status flips to canceled. It is absolutely critical that this API call is paired with logic in your own system that immediately revokes the user's access to paid features. The most robust way to handle this is by listening for webhooks from Stripe (which we’ll get into next), as they ensure your app’s state is always in sync with what’s happening in Stripe.
Managing Proration, Refunds, And Invoices
When a customer cancels a subscription mid-cycle, things can get financially messy in a hurry. You’ve got to handle it right to keep the customer happy (even as they're leaving) and your own books clean. This all comes down to understanding proration, deciding how to handle refunds, and making sure the final invoice is crystal clear.

Proration is just Stripe's way of calculating credit for any time left on a subscription that a customer has paid for but won't be using. By default, if you cancel a subscription immediately, Stripe automatically calculates a credit for the unused portion and sticks it on the customer's account balance. That's great if they're just switching plans, but it's not very helpful when they're leaving for good.
Taking Control With Proration Parameters
Leaving a credit on a cancelled customer's account is a recipe for future accounting headaches. You need to take control of this process, and you can do that by using a couple of key parameters in your Stripe API calls.
The two parameters you'll use most are prorate and invoice_now.
prorate: Setting this boolean tofalsetells Stripe to just skip the whole proration thing. The customer paid for the full period, and that's that. It's the simplest path, but depending on your policy, it might not sit well with the user.invoice_now: When you set this totrue, you're forcing Stripe to generate and finalize an invoice for the cancellation right away. This is absolutely critical for closing out a customer's account without any loose ends.
Juggling these two parameters gives you precise control over the final financial transaction, ensuring everything stays neat and tidy.
For immediate cancellations, my go-to strategy is to set
proratetotrue(which is the default) andinvoice_nowtotrue. This combination generates a final invoice with a prorated credit for the unused time, settling the account on the spot.
A Real-World Cancellation Scenario
Let's walk through a common situation. A customer is on a $30/month plan and decides to cancel exactly halfway through the month. You want to do the right thing and refund them for the 15 days of service they won't be using.
Here's how I'd handle that flow:
- Initiate Cancellation: Your code calls the
stripe.subscriptions.del()function, passing in the customer's subscription ID. - Enable Proration: You make sure the
prorateparameter is set totrue. This is what prompts Stripe to calculate the credit for the unused time—in this case, about $15. - Generate Final Invoice: At the same time, you set
invoice_nowtotrue. Stripe immediately creates a final invoice, which will show a negative balance of -$15 because of that proration credit. - Handle the Credit: Now, here's the crucial part: that negative balance doesn't automatically become a cash refund. It's just a credit on their Stripe account. You need to follow up programmatically to either issue a refund against their last payment or create a credit note.
Following this process makes sure the customer is treated fairly and your financial records are perfectly balanced. It turns what could be a confusing moment into a transparent and professional experience, reinforcing trust even as a customer is on their way out. The key is to decide on your company's refund and proration policy upfront—it's the foundation for a scalable and customer-friendly system.
Using Webhooks To Sync Subscription Status
It's a classic mistake to rely only on the immediate API response after you send a cancellation request. A temporary network hiccup, a server timeout—anything can go wrong. If your application misses that confirmation, you're left with a huge headache: the subscription is cancelled in Stripe, but your database still thinks it's active.
This is exactly why webhooks are a non-negotiable part of a robust subscription system.
Webhooks act as your single source of truth. They are automated messages that Stripe sends to your application whenever something important happens. It doesn't matter how the cancellation was triggered—through your API, directly in the Stripe Dashboard, or via the Customer Portal. The webhook event tells you what really happened, ensuring your system stays perfectly in sync.

Setting Up Your Webhook Endpoint
First things first, you need to create a dedicated endpoint in your application—basically, a URL that can listen for incoming POST requests from Stripe. When you configure this in your Stripe Dashboard, you'll choose which events you want to subscribe to.
For handling cancellations, you absolutely need to listen for these two events:
customer.subscription.deleted: This event fires the moment a subscription is cancelled immediately. It's your cue to revoke the user's access right away.customer.subscription.updated: This is a broader event that fires for many changes. You'll specifically want to watch it for whencancel_at_period_endis set totrue, which tells you a subscription is scheduled to end later.
By monitoring just these two events, you've covered both immediate and scheduled cancellations. Your app will always know the true state of every subscription.
Securing and Processing Events
Leaving an endpoint wide open is asking for trouble. To make sure the data you're receiving is actually from Stripe, you have to verify the webhook signature. Stripe sends a unique Stripe-Signature in every request's header. Your code must use your webhook signing secret to confirm this signature is valid before you do anything with the data.
Once you've verified the signature, you can trust the JSON payload. For a customer.subscription.updated event, you’d check if the cancel_at_period_end field is true. If it is, you can update the user's record in your database with the cancel_at timestamp, so you know exactly when their premium access should expire.
Key Takeaway: Never, ever trust a webhook payload without verifying the signature first. This single check prevents malicious actors from sending fake data to your endpoint and messing up your user records.
When a customer.subscription.deleted event comes in, the process is even simpler. You just find the user in your database via the customer ID in the payload and immediately downgrade their account. This creates a resilient, self-healing system that stays in sync no matter what. To get a better sense of all the signals you can track, it's worth exploring the complete list of Stripe events available for webhooks to see what other parts of your app you can automate.
Designing A Better Cancellation Experience
Getting the technical side of cancellations right is one thing, but building a flow designed to retain customers is where the real value is. Don't just think of it as an offboarding process. The cancellation flow is one of your most critical customer touchpoints—it's your last, best chance to find out why someone is leaving and maybe even convince them to stick around.
Instead of a dead-end "goodbye," treat this moment as the start of a conversation. A few thoughtful changes here can make a massive difference to your bottom line.
Offer an Alternative to Quitting Cold Turkey
One of the smartest moves you can make is to offer an alternative to outright cancellation. A "pause subscription" feature is a fantastic starting point.
Think about it: many customers don't actually want to leave for good. Maybe they're going on vacation, facing a tight budget for a month, or just won't be using your service for a short period. Forcing them into an all-or-nothing choice almost guarantees they'll churn.
Giving them an option to pause for one, two, or three months is a simple, low-friction way to prevent that permanent loss. It shows you understand their situation and keeps the door wide open for their return.
A simple "pause" button is a powerful retention tool. It tells the customer you're flexible and builds goodwill, making it feel natural for them to resume their subscription when they're ready.
Stripe’s subscription model is flexible enough to make this surprisingly easy to implement. You can just update the subscription to skip a few billing cycles or temporarily move the user to a free "paused" plan. This small UX improvement can have a huge, positive impact on your churn rate.
Ask "Why?" with an Exit Survey
If a customer is set on leaving, don't let them walk away without understanding the reason. This is where a simple, one-question exit survey becomes invaluable.
This isn't about putting up a barrier or making it difficult to leave. It's about collecting priceless feedback that can directly inform your product roadmap, pricing strategy, and marketing.
Keep the survey optional and dead simple. A multiple-choice list of common reasons is usually perfect for gathering actionable data quickly. Understanding what drives people away is the first step toward fixing the underlying issues. If you want to get ahead of the curve, you can dig into the most common subscription cancellation reasons customers cite and figure out how to address them proactively.
Use Dynamic Offers for Advanced Retention
While Stripe's built-in features are great, you can get even smarter by bringing in specialized retention tools. Platforms like Churnkey integrate directly with Stripe to present dynamic, personalized offers right at the moment a customer decides to cancel.
Imagine this: based on a customer’s usage patterns, current plan, or their answer to your exit survey, you could automatically offer them a temporary discount, a downgrade to a more suitable plan, or a free extension.
This strategy acknowledges that while you can't prevent all churn, a surprising amount of it is negotiable. In fact, data from over 3 million cancel sessions shows that when given the option, nearly 20% of customers will choose to pause their subscription instead of canceling it. It's no surprise that specialized platforms have helped companies save over $250 million by turning cancellation attempts into retention opportunities. Learning how to properly leverage exit surveys with Stripe is key to turning those potential losses into wins.
Common Questions About Stripe Cancellations
When you start working with Stripe subscriptions, a few questions pop up again and again. It's one thing to read the docs, but it's another to handle the real-world edge cases. Let's clear up some of the most common sticking points developers run into.

What Happens To Customer Data When I Cancel A Subscription?
Don't worry, canceling a subscription doesn't nuke the customer's record. When you cancel, Stripe simply flips the subscription's status to canceled. The underlying Customer object, their payment methods, and their entire invoice history all stay right where they are.
This is a huge benefit. If that same customer wants to come back months later, you just create a new subscription and attach it to their existing customer_id. It makes for a much smoother "welcome back" experience. The only time you'd delete the Customer object itself is for a "right to be forgotten" request, like under GDPR, which is a permanent and separate process.
Can I Reactivate A Canceled Stripe Subscription?
This is a classic "it depends" situation, and the answer hinges entirely on how you canceled it.
If you scheduled the cancellation for the end of the billing period (by setting cancel_at_period_end to true), you can absolutely reverse it. As long as the period hasn't ended, you can just make another API call to update the subscription, setting cancel_at_period_end back to false. The subscription will carry on as if nothing happened.
However, once a subscription is canceled immediately (using the subscriptions.del() method) or its scheduled end-of-period date passes, it's done for good. There's no bringing it back. At that point, your only option is to create a brand new subscription for the customer.
Expert Tip: That ability to "undo" a scheduled cancellation is a fantastic retention tool. It gives customers a cooling-off period to change their minds without having to go through the signup process all over again, which can have a real, positive impact on your churn numbers.
How Do I Test My Cancellation Logic Without Real Money?
You should always be using Stripe's test mode for this. Grab your test API keys and switch your dashboard to test mode. It’s a completely separate sandbox environment, so no real money ever changes hands.
Stripe gives you a whole suite of test credit card numbers you can use to simulate just about anything—successful payments, different kinds of card declines, you name it. This lets you confidently walk through your entire cancellation flow, from the initial API call to verifying that your webhooks are firing correctly. For more detailed scenarios, it's also worth looking into how to turn off auto-renewal, as that's often the first step in a user-driven cancellation.
It's also critical to test for involuntary churn, which is what happens when payments fail. A single failed payment can cause 35% of users to give up and cancel, and this issue is responsible for around 10% of all subscription revenue losses. While Stripe's built-in features like smart retries are great—they helped businesses recover $3.8 billion in 2022—it's not a silver bullet. In fact, 41% of businesses still saw their involuntary churn rates go up, which shows just how important it is to have solid payment recovery logic in place.