Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
Overview
Billing
OverviewAbout the Billing APIs
Subscriptions
    Overview
    How subscriptions work
    Quickstart
    Use cases
    Build your integration
      Design a subscriptions integration
      Build a subscriptions integration
      Integrate with Salesforce
      Subscription event definitions
    Subscription features
    Entitlements
    Analytics
Invoicing
Usage-based billing
Quotes
Customer management
Billing with other products
Revenue recovery
Automations
Test your integration
Tax
Overview
Use Stripe tax
Manage compliance
Reporting
Overview
Select a report
Configure reports
Reports API
Reports for multiple accounts
Revenue recognition
Data
OverviewSchema
Custom reports
Data Pipeline
Data management
HomeRevenueSubscriptionsBuild your integration

Build a subscriptions integration

Create and manage subscriptions to accept recurring payments.

Embedded Checkout previewEmbedded Checkout preview
togethere.work

Integration effort

Low code

UI customization

Customize the appearance.

Integration type

Use prebuilt embedded forms to collect payments and manage subscriptions.

Set up the server

Set up Stripe

Install the Stripe client of your choice:

Command Line
Ruby
Python
PHP
Java
Node
Go
.NET
No results
# Available as a gem sudo gem install stripe
Gemfile
Ruby
Python
PHP
Java
Node
Go
.NET
No results
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Create a product and price

Create your products and their prices in the Dashboard or with the Stripe CLI.

This example uses a fixed-price service with two different service-level options: Basic and Premium. For each service-level option, you need to create a product and a recurring price. (If you want to add a one-time charge for something like a setup fee, create a third product with a one-time price. To keep things simple, this example doesn’t include a one-time charge.)

In this example, each product bills at monthly intervals. The price for the Basic product is 5 USD. The price for the Premium product is 15 USD.

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 intervals, use Checkout to upsell customers on longer billing intervals 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 Checkout form, set ui_mode to embedded.
  • 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 {CHECKOUT_SESSION_ID} template variable in the URL. Checkout replaces the variable with the Checkout Session ID before redirecting your customer. You create and host the return page on your website.

To mount Checkout, use the Checkout Session’s client_secret returned in the response.

Command Line
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node
Go
.NET
No results
curl https://api.stripe.com/v1/checkout/sessions \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d mode=subscription \ -d "line_items[0][price]"=
{{PRICE_ID}}
\ -d "line_items[0][quantity]"=1 \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}"

Build your subscription page
Client

Mount Checkout

Add Stripe to your React app

To stay PCI compliant by ensuring that payment details go directly to Stripe and never reach your server, install React Stripe.js.

npm install --save @stripe/react-stripe-js @stripe/stripe-js

Load Stripe.js

To configure the Stripe library, call loadStripe() with your Stripe publishable API key. Create an EmbeddedCheckoutProvider. Pass the returned Promise to the provider.

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.

Initialize Checkout

To allow the child components to access the Stripe service through the embedded Checkout consumer, pass the resulting promise from loadStripe and the fetchClientSecret function as an option to the embedded Checkout provider.

App.jsx
import * as React from 'react'; import {loadStripe} from '@stripe/stripe-js'; import { EmbeddedCheckoutProvider, EmbeddedCheckout } from '@stripe/react-stripe-js'; // Make sure to call `loadStripe` outside of a component’s render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('pk_test_123', { }); const App = ({fetchClientSecret}) => { const options = {fetchClientSecret}; return ( <EmbeddedCheckoutProvider stripe={stripePromise} options={options} > <EmbeddedCheckout /> </EmbeddedCheckoutProvider> ) }

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 authorization page. When they complete 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 according to 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 canceled. 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 = await stripe.customers.retrieve(session.customer); res.send({ status: session.status, payment_status: session.payment_status, customer_email: customer.email }); });

OptionalConfigure the customer portal

Provision access

Now that the subscription is active, give your user access to your service. To do this, listen to the customer.subscription.created, customer.subscription.updated, and customer.subscription.deleted events. These events pass a subscription object that contains a status field indicating whether the subscription is active, past due, or canceled. See the subscription lifecycle for a complete list of statuses. To learn about managing access to your product’s feature, see the doc on integrating entitlements.

In your webhook handler:

  1. Verify the subscription status. If it’s active then your user has paid for your product.
  2. Check the product the customer subscribed to and grant access to your service. Checking the product instead of the price gives you more flexibility if you need to change the pricing or billing interval.
  3. Store the product.id, subscription.id and subscription.status in your database along with the customer.id you already saved. Check this record when determining which features to enable for the user in your application.

The state of a subscription might change at any point during its lifetime, even if your application does not directly make any calls to Stripe. For example, a renewal might fail due to an expired credit card, which puts the subscription into a past due state. 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 state 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
BECS Direct DebitYour customer successfully pays with BECS Direct Debit.Fill out the form using the account number 900123456 and BSB 000-000. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later.
BECS Direct DebitYour customer’s payment fails with an account_closed error code.Fill out the form using the account number 111111113 and BSB 000-000.
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.
SEPA Direct DebitYour customer successfully pays with SEPA Direct Debit.Fill out the form using the account number AT321904300235473204. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later.
SEPA Direct DebitYour customer’s PaymentIntent status transitions from processing to requires_payment_method.Fill out the form using the account number AT861904300235473202.

Monitoring events

Set up webhooks to listen to subscription change events such as upgrades and cancellations. Learn more about subscription webhooks. You can view events in the Dashboard or with the Stripe CLI.

Learn more about testing your Billing integration.

Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Join our early access program.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc