RyzeDeskRyzeDesk

Stripe

4105 articles

Build a subscriptions integration


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:

  1. Verify the subscription status. If it’s active , your customer has paid for your product.
  2. 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.
  3. 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 methodScenarioHow to test
the related setting Direct DebitYour 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 DebitYour customer’s payment fails with an account_closed error code.Fill out the form using the account number 111111113 and BSB 000000.
Credit cardThe 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 cardThe 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 cardThe 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 DebitYour 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 DebitYour 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.

Last verified 2026-09-27

Is this helpful?