- Languages: Node, HTML
- Tools Used: Stripe
- Time Saved: 3 weeks -> 40 mins
- Source Code
- Live Demo
This is the Part 3 in the series of guides on adding, managing, and keeping track of subscription payments using Stripe and Mongo for your SaaS app.
Introduction
Subscription Payments are the bread and butter of a SaaS application; it's how you start generating revenue. In a well-implemented system, users need to first be able to change or cancel their plans, and second, undergo a trial phase to see if they would even like to pay for premium features. Typically, it's a hassle to set these up. In this set of guides, we will go through all the steps required to build a complete Subscription Payments system for your SaaS app.
In Part 3, we will:
- Allow customers to switch between Basic and Pro plans
- Cancel a subscription plan
Let's start!
Step 1: Configure Billing Portal Settings
One of the great things about Stripe is that it has Billing Portal features already built in. Things like, **View Previous Invoices,\\Change Billing Information,\\Allow Promotion Codes etc. can be turned on in the Billing Portal Settings page here.
Let's enable a few options.
- Enable the
Allow customers to cancel subscriptions
- Enable the
Allow customers to switch to a different pricing plan
- Add our products so customers can see the other available plans when switching
- Add a Privacy Policy, Terms of Service, and a Redirect page. Hit
Save
.
!https://launchman-space.nyc3.cdn.digitaloceanspaces.com/saasbase/images/2021/05/1-2.png
Configuring Stripe Billing Portal Add our products so customers can see the other available plans when switching.
!https://launchman-space.nyc3.cdn.digitaloceanspaces.com/saasbase/images/2021/05/2-2.png
Add Products to Stripe Billing Portal
!https://launchman-space.nyc3.cdn.digitaloceanspaces.com/saasbase/images/2021/05/3.png
Add Terms & Services to Stripe Billing Portal That's it! Stripe just did the bulk of our work for us. All we have to do now is to trigger the Manage Billing screen. Let's do that next.
Step 2: Create a Manage Billing button
We can add a Manage Billing button in views/account.ejs
that shows up only when the customer is on an active plan. This will give them the option to update or cancel their plan.
Let's start by editing views/account.ejs
:
<% } else{ %> // ...
<p>
Not happy with your current plan? Cancel or Upgrade by clicking the button
below.
</p>
<button id="manage-billing-button" type="submit">Manage Billing</button>
<% }
When the button is clicked, we will send customer information along and trigger the Customer Billing Session on the /billing
endpoint. Edit the public/js/account.js
// ..
const manageBillingButton = $("#manage-billing-button");
manageBillingButton.click(function () {
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
customer: customer.billingID,
}),
};
fetch("/billing", requestOptions)
.then((response) => response.json())
.then((result) => window.location.replace(result.url))
.catch((error) => console.log("error", error));
});
Let's create a server-side session for Billing in app.js
app.post("/billing", async (req, res) => {
const { customer } = req.body;
const session = await Stripe.createBillingSession(customer);
res.json({ url: session.url });
});
We need to edit the src/connect/stripe.js
so we can add the createBillingSession
method.
const createBillingSession = async (customer) => {
const session = await Stripe.billingPortal.sessions.create({
customer,
return_url: "<https://localhost:4242>",
});
return session;
};
module.exports = {
// ...
createBillingSession,
};
We are ready to test it out. Login, buy a plan, and then try to change the plan.
!https://launchman-space.nyc3.cdn.digitaloceanspaces.com/saasbase/images/2021/05/4-1.png
Updating subscription plan on Manage Billing screen The plan should be correctly changed on the Stripe Dashboard. Notice, however, the information in the database is now outdated.
Step 3: Update Customer data when the plan is updated/cancelled
When the customer updates or cancels their purchased subscription plan via the Manage Billing screen, Stripe sends a customer.subscription.updated
event to our webhook.
app.post("/webhook", async (req, res) => {
// ..
case "customer.subscription.updated":
//started trial
const user = await UserService.getUserByBillingID(data.customer)
if (data.plan.id == productToPriceMap.BASIC) {
user.plan = "basic"
} else if (data.plan.id == productToPriceMap.PRO) {
user.plan = "pro"
}
const isOnTrial = data.status === "trialing"
if (isOnTrial) {
user.hasTrial = true
user.endDate = new Date(data.current_period_end * 1000)
} else if (data.status === "active") {
user.hasTrial = false
user.endDate = new Date(data.current_period_end * 1000)
}
if (data.canceled_at) {
// cancelled
user.plan = "none"
user.hasTrial = false
user.endDate = null
}
await user.save()
break
default:
}
// ..
});
Step 4: Test it out
Let's test out our application. Go through the login flow with your email address and purchase a plan. Then go back to the login page, log in again and try to cancel it via the Manage Billing button.

Next Steps
In this guide we learned how to:
- Allow customers to switch between Basic and Pro plans
- Cancel a subscription plan
Our customers can now correctly buy/update/cancel subscription plans but they don't have access to exclusive content yet. Presumably, they are buying a plan to consume some sort of premium content. We will look into how we can set up special pages that a customer can access based on the type of plan they are on.
About the author
Sukhpal Saini