- Регистрация
- 1 Мар 2015
- Сообщения
- 11,730
- Баллы
- 155
Modern SaaS businesses need a pricing model that aligns with customer usage and scales effectively. Seat-based billing is a common pricing model for SaaS businesses, allowing customers to pay a fee based on the number of seats or users they need each month.
In this article, we’ll explore how to implement a seat-based subscription model using Stripe Hosted Checkout for initial subscription creation and Stripe Customer Portal for post-purchase seat management.
Prerequisites
In this section, we'll go through the requirements for the tutorial. To follow along with the rest of this guide, you will need the following:
To get started, we must first install the Stripe Node Library. This library is required to create a new checkout session on our application. To install the library, run the following command in the root of your project's directory:
npm install stripe express
The command also installs Express to the project. Express is a minimalistic back-end web application framework used for building applications with Node.js.
Step 2: Building the UI
Next, we need to build out the UI for the application. This step involves building a lightweight UI to handle the transition to Stripe's hosted checkout, as well as the success.html and cancel.html pages required by Stripe checkout.
Create the checkout.html
For the checkout.html, we'll create a simple HTML page with a form and button that triggers Stripe's checkout session when clicked, as shown:
<body>
<section>
<form action="/create-checkout-session" method="POST">
<button type="submit" id="checkout-button">Checkout</button>
</form>
</section>
</body>
Create the success and cancel pages
Next, let's create the success and cancel pages—success.html and cancel.html. Stripe requires these pages as they determine how our application handles redirects after a successful checkout or upon cancellation.
<!-- success.html -->
<body>
<section>
<p>
We appreciate your business! If you have any questions, please email
<a href="mailto:orders@example.com">orders@example.com</a>.
</p>
</section>
</body>
For the cancel.html:
<!-- cancel.html -->
<body>
<section>
<p>
Forgot to add something to your cart? Shop around then come back to pay!
</p>
</section>
</body>
Step 3: Setup the server
Now that we've built the UI, we can begin setting up the backend server that handles the checkout session.
First, we must import and initialize the Stripe and Express libraries that we installed earlier as shown:
// server.js
const stripe = require("stripe")("YOUR_STRIPE_SECRET_KEY");
const express = require("express");
const app = express();
app.use(express.static("public"));
const YOUR_DOMAIN = "";
Create the checkout session
Now, we can begin setting up the checkout session. To begin, we must define an endpoint on the server that handles the form submission request from the front end. This endpoint must match the value of the action attribute on the form element in the checkout.html file. For this tutorial, we will be using /create-checkout-session as shown:
// server.js
app.post("/create-checkout-session", async (req, res) => {
const session = await stripe.checkout.sessions.create({
line_items: [
{
// Provide the Price ID of the recurring product
price: "PRICE_ID",
quantity: 4,
},
],
mode: "subscription",
success_url: `${YOUR_DOMAIN}/success.html`,
cancel_url: `${YOUR_DOMAIN}/cancel.html`,
});
res.redirect(303, session.url);
});
The stripe.checkout.sessions.create method creates a . A Checkout Session controls what your customer sees on the payment page, such as line items, the order amount, and acceptable payment methods.
Within the line_items array, provide the price ID of the product for which you want to implement seat-based billing within the price field and the number of initial seats within the quantity field. Each object in the array represents a product in your product catalog. To create seat-based billing, the price IDs of all products in the array must have a recurring price.
Next, include the values of the success and cancel URLs. These values must match the HTML pages created earlier. Since seat-based billing is a type of recurring payment, we must set the billing mode to subscription using the mode parameter.
At this point, our server.js should look like this:
const stripe = require("stripe")("YOUR_STRIPE_SECRET_KEY");
const express = require("express");
const app = express();
app.use(express.static("public"));
const YOUR_DOMAIN = "";
app.post("/create-checkout-session", async (req, res) => {
const session = await stripe.checkout.sessions.create({
line_items: [
{
// Provide the exact Price ID (for example, pr_1234) of the product you want to sell
price: "PRICE_ID",
quantity: 4,
},
],
mode: "subscription",
success_url: `${YOUR_DOMAIN}/success.html`,
cancel_url: `${YOUR_DOMAIN}/cancel.html`,
});
res.redirect(303, session.url);
});
app.listen(4242, () => console.log("Running on port 4242"));
Now, we can test the application to ensure it works as desired. To begin:
Stripe allows us to manage the subscription by making updates after creating a new seat-based billing subscription.
However, since Stripe Checkout only supports creating a new subscription, we must use an alternative method for updating our seat-based billing subscription. For this tutorial, we’ll use Stripe’s . The customer portal allows customers to self-manage their payment details, invoices, and subscriptions.
To get started:
After completing these steps, Stripe will generate a customer portal link that your customers can use to manage their subscriptions.
To update a subscription:
Note that in test mode, Stripe will only send authentication emails if you have a test mode customer associated with the email address provided.
Next steps
Using Stripe's Hosted Checkout and Customer Portal, you have learned how to create a new seat-based billing subscription and upgrade and downgrade seat count after purchase.
While this provides a solid foundation for per-seat billing, some notable limitations can create challenges for businesses managing seat-based subscriptions. For example, Stripe's proration invoices can be difficult to interpret, especially when customers upgrade or downgrade their seat count mid-cycle. The resulting invoice lacks clear line items that reflect standard industry practices.
Secondly, the simplicity of Stripe's approach forces businesses to build additional logic to enforce seat limits within their application. These gaps can lead to increased engineering effort and commitment for companies looking for a more robust and scalable solution.
In this article, we’ll explore how to implement a seat-based subscription model using Stripe Hosted Checkout for initial subscription creation and Stripe Customer Portal for post-purchase seat management.
Prerequisites
In this section, we'll go through the requirements for the tutorial. To follow along with the rest of this guide, you will need the following:
- A account: You can use an account in test mode for now. However, ensure you enable live mode on your account when in production.
- Node.js: You can download and install a NodeJS version with Long-Term Support (LTS) from the .
- A code editor of choice. The tutorial assumes that you already have a product with a recurring billing setup. If you don't have one, see on the Stripe documentation for more information.
To get started, we must first install the Stripe Node Library. This library is required to create a new checkout session on our application. To install the library, run the following command in the root of your project's directory:
npm install stripe express
The command also installs Express to the project. Express is a minimalistic back-end web application framework used for building applications with Node.js.
Step 2: Building the UI
Next, we need to build out the UI for the application. This step involves building a lightweight UI to handle the transition to Stripe's hosted checkout, as well as the success.html and cancel.html pages required by Stripe checkout.
Create the checkout.html
For the checkout.html, we'll create a simple HTML page with a form and button that triggers Stripe's checkout session when clicked, as shown:
<body>
<section>
<form action="/create-checkout-session" method="POST">
<button type="submit" id="checkout-button">Checkout</button>
</form>
</section>
</body>
Create the success and cancel pages
Next, let's create the success and cancel pages—success.html and cancel.html. Stripe requires these pages as they determine how our application handles redirects after a successful checkout or upon cancellation.
<!-- success.html -->
<body>
<section>
<p>
We appreciate your business! If you have any questions, please email
<a href="mailto:orders@example.com">orders@example.com</a>.
</p>
</section>
</body>
For the cancel.html:
<!-- cancel.html -->
<body>
<section>
<p>
Forgot to add something to your cart? Shop around then come back to pay!
</p>
</section>
</body>
Step 3: Setup the server
Now that we've built the UI, we can begin setting up the backend server that handles the checkout session.
First, we must import and initialize the Stripe and Express libraries that we installed earlier as shown:
// server.js
const stripe = require("stripe")("YOUR_STRIPE_SECRET_KEY");
const express = require("express");
const app = express();
app.use(express.static("public"));
const YOUR_DOMAIN = "";
Create the checkout session
Now, we can begin setting up the checkout session. To begin, we must define an endpoint on the server that handles the form submission request from the front end. This endpoint must match the value of the action attribute on the form element in the checkout.html file. For this tutorial, we will be using /create-checkout-session as shown:
// server.js
app.post("/create-checkout-session", async (req, res) => {
const session = await stripe.checkout.sessions.create({
line_items: [
{
// Provide the Price ID of the recurring product
price: "PRICE_ID",
quantity: 4,
},
],
mode: "subscription",
success_url: `${YOUR_DOMAIN}/success.html`,
cancel_url: `${YOUR_DOMAIN}/cancel.html`,
});
res.redirect(303, session.url);
});
The stripe.checkout.sessions.create method creates a . A Checkout Session controls what your customer sees on the payment page, such as line items, the order amount, and acceptable payment methods.
Within the line_items array, provide the price ID of the product for which you want to implement seat-based billing within the price field and the number of initial seats within the quantity field. Each object in the array represents a product in your product catalog. To create seat-based billing, the price IDs of all products in the array must have a recurring price.
Next, include the values of the success and cancel URLs. These values must match the HTML pages created earlier. Since seat-based billing is a type of recurring payment, we must set the billing mode to subscription using the mode parameter.
At this point, our server.js should look like this:
const stripe = require("stripe")("YOUR_STRIPE_SECRET_KEY");
const express = require("express");
const app = express();
app.use(express.static("public"));
const YOUR_DOMAIN = "";
app.post("/create-checkout-session", async (req, res) => {
const session = await stripe.checkout.sessions.create({
line_items: [
{
// Provide the exact Price ID (for example, pr_1234) of the product you want to sell
price: "PRICE_ID",
quantity: 4,
},
],
mode: "subscription",
success_url: `${YOUR_DOMAIN}/success.html`,
cancel_url: `${YOUR_DOMAIN}/cancel.html`,
});
res.redirect(303, session.url);
});
app.listen(4242, () => console.log("Running on port 4242"));
Now, we can test the application to ensure it works as desired. To begin:
- Start the application server and navigate to .
- Click the Checkout button to trigger the checkout session. This will redirect you to the Stripe Checkout page.
- Fill in the required information and click the Subscribe button to create the subscription. This creates a new subscription for the product. You can find the new subscription on the page on your Stripe dashboard.
Stripe allows us to manage the subscription by making updates after creating a new seat-based billing subscription.
However, since Stripe Checkout only supports creating a new subscription, we must use an alternative method for updating our seat-based billing subscription. For this tutorial, we’ll use Stripe’s . The customer portal allows customers to self-manage their payment details, invoices, and subscriptions.
To get started:
- Go to the page on the Stripe dashboard.
- Click the Activate test link button.
- Go to the Subscriptions menu on the portal configuration section.
- Enable the Customers can switch plans and Customers can update the quantity of their plans options.
- Next, select the product for which you created a subscription.
- Finally, click the Save changes button to save the latest changes.
After completing these steps, Stripe will generate a customer portal link that your customers can use to manage their subscriptions.
To update a subscription:
- Go to your customer portal link on a browser.
- Enter your customer email to log in. The customer email you provide must be associated with an existing customer. Stripe automatically creates a new customer when a subscription is created, so you can use the customer email provided at checkout.
- Click on the login link sent to the customer email provided.
- Click the Update subscription button and then set the new number of seats to be purchased.
- Click Continue > Confirm to confirm the update.
Note that in test mode, Stripe will only send authentication emails if you have a test mode customer associated with the email address provided.
Next steps
Using Stripe's Hosted Checkout and Customer Portal, you have learned how to create a new seat-based billing subscription and upgrade and downgrade seat count after purchase.
While this provides a solid foundation for per-seat billing, some notable limitations can create challenges for businesses managing seat-based subscriptions. For example, Stripe's proration invoices can be difficult to interpret, especially when customers upgrade or downgrade their seat count mid-cycle. The resulting invoice lacks clear line items that reflect standard industry practices.
Secondly, the simplicity of Stripe's approach forces businesses to build additional logic to enforce seat limits within their application. These gaps can lead to increased engineering effort and commitment for companies looking for a more robust and scalable solution.