Languages | Tools Used | Time Saved
Node.js, HTML Stripe 3 weeks → 40 mins
Goodies
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.
Every SaaS app needs subscription payments - a recurring payment. Users need to be able to change or cancel their plans, go through a trial phase to see if they even would like to pay for premium features.
In Part 3, we will:
- Allow customers to switch between Basic and Pro plans
- Cancel their subscription plan
- Exit Survey collecting feedback on why customers are churning
Configure Billing Portal Settings
Enable Allow customers to cancel subscriptions
and Allow customers to switch to a differnt pricing plan
in the Stripe Portal Settings page here.
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
.
Create a Manage Billing button
We can add a button to views/account.ejs
that shows only when the customer is on an active plan. This will give the customer the option to update or cancel their plan.
Let's start by adding a button to 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>
<% }
Now create the event listener for when the button is clicked in 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))
})
We create a session for Billing on the server-side in app.js
app.post('/billing', async (req, res) => {
const { customer } = req.body
const session = await Stripe.createBillingSession(customer)
console.log('session', session)
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
}
Now let's test it out. Login, buy a plan, and then try to change the plan.
The plan will be changed on Stripe but of course we have to update our database as well.
Update Customer data when plan changes
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) {
console.log("You are talking about basic product");
user.plan = "basic";
}
if (data.plan.id == productToPriceMap.PRO) {
console.log("You are talking about pro product");
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
console.log("You just canceled the subscription" + data.canceled_at);
user.plan = "none";
user.hasTrial = false;
user.endDate = null;
}
console.log("actual", user.hasTrial, data.current_period_end, user.plan);
await user.save();
console.log("customer changed", JSON.stringify(data));
break;
default:
}
// ..
});
Test it out
Go through the login flow with your email address, purchase a plan, and try to cancel it.