Build a subscriptions integration
Create and manage subscriptions to accept recurring payments.
Checkout
Elements
Mobile
togethere.work
Integration effort
Low code
UI customisation
Customise the appearance.
Integration type
Use pre-built embedded forms to collect payments and manage subscriptions.
Set up the server
Set up Stripe
Install the Stripe client of your choice:
Command Line
Select a language
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# Available as a gem
sudo gem install stripe
Gemfile
Select a language
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# If you use bundler, you can add this line to your Gemfile
gem 'stripe'
Create a product and price
Recurring pricing models represent the products or services you sell, how much they cost, what currency you accept for payments, and the service period for subscriptions. To build the pricing model, create products (what you sell) and prices (how much and how often to charge for your products).
This example uses flat-rate pricing with two different service-level options: Basic and Premium. For each service-level option, you need to create a product and a recurring price. To add a one-time charge for something like a setup fee, create a third product with a one-time price.
Each product bills at monthly intervals. The price for the Basic product is 5 USD. The price for the Premium product is 15 USD. See the flat rate pricing guide for an example with three tiers.
Go to the Add a product page and create two products. Add one price for each product, each with a monthly recurring billing period:
- Premium product: Premium service with extra features
- Price: Flat rate | 15 USD
- Basic product: Basic service with minimum features
- Price: Flat rate | 5 USD
After you create the prices, record the price IDs so you can use them in other steps. Price IDs look like this: price_G0FvDp6vZvdwRZ.
When you’re ready, use the Copy to live mode button at the top right of the page to clone your product from a sandbox to live mode.
If you offer multiple billing periods, use Checkout to upsell customers on longer billing periods and collect more revenue upfront.
For other pricing models, see Billing examples.
Create a Checkout Session
Add an endpoint on your server that creates a Checkout Session.
When you create the Checkout Session, pass the following parameters:
- To use the embedded payment page, set ui_mode to embedded _ page .
- To create subscriptions when your customer checks out, set mode to subscription .
- To define the page your customer returns to after completing or attempting payment, specify a return_url . Include the {the related setting _ the related setting _ ID} template variable in the URL. Checkout replaces the variable with the CheckoutSession ID before redirecting your customer. You create and host the return page on your website.
- To include your subscription and cancellation terms and a link to where your customers can update or cancel their subscription, optionally use custom text . We recommend configuring email reminders and notifications for your subscribers.
To mount Checkout, use the Checkout Session’s client_secret returned in the response.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
Build your subscription page Client
Mount Checkout
Load Stripe.js
Use Stripe.js to remain PCI compliant by ensuring that payment details are sent directly to Stripe without hitting your server. Always load Stripe.js from js.stripe.com to remain compliant. Don’t include the script in a bundle or host it yourself.
Define the payment form
To securely collect the customer’s information, create an empty placeholder div. Stripe inserts an iframe into the div.
Checkout is available as part of Stripe.js. Include the Stripe.js script on your page by adding it to the head of your HTML file. Next, create an empty DOM node (container) to use for mounting.
index.html
Initialise Stripe.js
Initialise Stripe.js with your publishable API key.
Fetch a Checkout Session client secret
Create an asynchronous fetchClientSecret function that makes a request to your server to create a Checkout Session and retrieve the client secret.
Initialise Checkout
Initialise Checkout with your fetchClientSecret function and mount it to the placeholder <div> in your payment form. Checkout is rendered in an iframe that securely sends payment information to Stripe over an HTTPS connection.
Avoid placing Checkout within another iframe because some payment methods require redirecting to another page for payment confirmation.
index.js
// Initialize Stripe.js
const stripe = Stripe('pk_test_GvF3BSyx8RSXMK5yAFhqEd3H');
initialize();
// Fetch Checkout Session and retrieve the client secret
async function initialize() {
const fetchClientSecret = async () => {
const response = await fetch("/create-checkout-session", {
method: "POST",
});
const { clientSecret } = await response.json();
return clientSecret;
};
// Initialize Checkout
const checkout = await stripe.createEmbeddedCheckoutPage({
fetchClientSecret,
});
// Mount Checkout
checkout.mount('#checkout');
}
Show a return page
After your customer attempts payment, Stripe redirects them to a return page that you host on your site. When you created the Checkout Session, you specified the URL of the return page in the return_url parameter.
Note
During payment, some payment methods redirect the customer to an intermediate page, such as a bank authorisation page. When the customer completes that page, Stripe redirects them to your return page.
Create an endpoint to retrieve a Checkout Session
Add an endpoint to retrieve a Checkout Session status with the Checkout Session ID in the URL.
Retrieve a Checkout Session
To use details for the Checkout Session, immediately make a request to the endpoint on your server to retrieve the Checkout Session status using the Checkout Session ID in the URL as soon as your return page loads.
Handle the session
Handle the result based on the session status:
- complete : The payment succeeded. Use the information from the Checkout Session to render a success page.
- open : The payment failed or was cancelled. Remount Checkout so that your customer can try again.
return.js
// Retrieve a Checkout Session
// Use the session ID
initialize();
async function initialize() {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const sessionId = urlParams.get('session_id');
const response = await fetch(`/session-status?session_id=${sessionId}`);
const session = await response.json();
// Handle the session according to its status
if (session.status == 'open') {
// Remount embedded Checkout
window.location.replace('http://localhost:4242/checkout.html')
} else if (session.status == 'complete') {
document.getElementById('success').classList.remove('hidden');
document.getElementById('customer-email').textContent = session.customer_email;
// Show success page
// Optionally use session.payment_status or session.customer_email
// to customize the success page
}
}
server.js
// Add an endpoint to fetch the Checkout Session status
app.get('/session_status', async (req, res) => {
const session = await stripe.checkout.sessions.retrieve(req.query.session_id);
const customer_account = await stripe.v2.core.accounts(session.customer_account);
res.send({
status: session.status,
payment_status: session.payment_status,
customer_email: customer_account.contact_email
});
});
Optional Configure the customer portal
Provision access
When the subscription is active, give your customer access to your service. To do this, listen to the customer.subscription.created, customer.subscription.updated and customer.subscription.deleted events (even if you use customer-configured Accounts). These events pass a Subscription object that contains a status field indicating whether the subscription is active, overdue or cancelled. See the subscription lifecycle for a complete list of statuses. To manage access to your product’s feature, learn about integrating entitlements.
In your webhook handler:
- Verify the subscription status. If it’s active , your customer has paid for your product.
- Check the product that your customer subscribed to and grant them access to your service. Checking the product instead of the price allows you to change the pricing or billing period, as needed.
- Store the product. id , subscription. id and subscription. status in your database, along with either the customer _ account. id or the customer. id you already saved. Check this record when determining which features to enable for the customer in your application.
The subscription status might change at any point during its lifetime, even if your application doesn’t directly make any calls to Stripe. For example, a renewal might fail because of an expired credit card, which puts the subscription in a overdue status. Or, if you implement the customer portal, a user might cancel their subscription without directly visiting your application. Implementing your handler correctly keeps your application status in sync with Stripe.
Test your integration
Test payment methods
Use the following table to test different payment methods and scenarios.
| Payment method | Scenario | How to test |
|---|---|---|
| the related setting Direct Debit | Your customer successfully pays with the related setting Direct Debit. | Fill out the form using the account number 900123456 and BSB 000000. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. |
| the related setting Direct Debit | Your customer’s payment fails with an account_closed error code. | Fill out the form using the account number 111111113 and BSB 000000. |
| Credit card | The card payment succeeds and doesn’t require authentication. | Fill out the credit card form using the credit card number 4242 4242 4242 4242 with any expiration, CVC, and postal code. |
| Credit card | The card payment requires authentication. | Fill out the credit card form using the credit card number 4000 0025 0000 3155 with any expiration, CVC, and postal code. |
| Credit card | The card is declined with a decline code like insufficient_funds. | Fill out the credit card form using the credit card number 4000 0000 0000 9995 with any expiration, CVC, and postal code. |
| the related setting Direct Debit | Your customer successfully pays with the related setting Direct Debit. | Fill out the form using the account number the related setting. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. |
| the related setting Direct Debit | Your customer’s PaymentIntent status transitions from processing to requires_payment_method. | Fill out the form using the account number the related setting. |
Monitor events
Set up webhooks to listen to subscription change events, such as upgrades and cancellations. You can view subscription webhook events in the Dashboard or with the Stripe CLI.
Learn more about testing your Billing integration.