Sign in
An image of the Stripe logo
Create account
Sign in
Home
Payments
Business operations
Financial services
Developer tools
Security
All products
Home
Payments
Business operations
Home
Payments
Business operations
Financial services
Developer tools
Support
Overview
Overview
How subscriptions work
How to model subscriptions
Get started
Quickstart
Design an integration
Build a subscriptions integration
Integrate the customer portal
Migrate subscriptions to Stripe
Billing resources
Coupons
Customers
Subscriptions
Subscription invoices
Manage subscriptions
Change subscriptions
Use trial periods
Set payment methods
Subscriptions with multiple products
Set subscription quantities
Subscription webhooks
Schedule subscriptions
Tax
Integrate with Salesforce
Manage recurring revenue
Revenue recognition
Revenue recovery
Subscription metrics
Testing
Test your integration
Test clocks
Metered billing with Elements
Fixed-price billing with Elements
Per-seat billing with Elements
Migrate to Prices
Strong Customer Authentication (SCA)
Invoices API updates
Improved tax support
Testing
No-code options
Billing
·
HomePaymentsSubscriptions

Build a subscriptions integration

Create and manage subscriptions to accept recurring payments.
Complexity:

Customize logo, images, and colors.

Use prebuilt hosted forms to collect payments and manage subscriptions.

Clone a sample integration from GitHub.

For an immersive version of this guide, see the Billing integration quickstart.

View the demo to see a hosted example.

What you’ll build

This guide describes how to sell fixed-price monthly subscriptions using Stripe Checkout.

By following this guide, you’ll

  • Model your business by building a product catalog.
  • Add a Checkout session to your site, including a button and success and cancellation pages.
  • Monitor subscription events and provision access to your service.
  • Set up the customer portal.
  • Add a customer portal session to your site, including a button and redirect.
  • Let customers manage their subscription through the portal.

If you aren’t ready to code an integration, you can set up basic subscriptions manually in the Dashboard. You can also use Payment Links to set up subscriptions without writing any code. Or learn more about designing an integration to understand the decisions you’ll need to make and the resources you’ll need.

After you complete the integration, you can extend it to:

  • Display taxes
  • Apply discounts
  • Offer customers a free trial period
  • Add more payment methods
  • Integrate the hosted invoice page
  • Use Checkout in setup mode
  • Set up metered billing, pricing tiers, and usage-based pricing
  • Manage prorations
  • Allow customers to subscribe to multiple products

Set up Stripe

Install the Stripe client of your choice:

Terminal
# Available as a gem sudo gem install stripe
Gemfile
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Install the Stripe CLI (optional). The CLI provides webhook testing, and you can run it to create your products and prices.

To install the Stripe CLI with homebrew, run:

Terminal
brew install stripe/stripe-cli/stripe

To run the Stripe CLI, you must also pair it with your Stripe account. Run stripe login and follow the prompts. For more information, see the Stripe CLI documentation page.

Create the pricing model
Dashboard or Stripe CLI

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.

Navigate 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: Standard model | 15 USD
  • Basic product: Basic service with minimum features

    • Price: Standard model | 5 USD

You don’t need to specify the unit amount in the Dashboard unless you use the package pricing model.

After you create the prices, record the price IDs so you can use them in subsequent 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 test mode 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
Client and Server

Add a checkout button to your website that calls a server-side endpoint to create a Checkout Session.

index.html
View full sample
<html> <head> <title>Checkout</title> </head> <body> <form action="/create-checkout-session" method="POST"> <!-- Note: If using PHP set the action to /create-checkout-session.php --> <input type="hidden" name="priceId" value="price_G0FvDp6vZvdwRZ" /> <button type="submit">Checkout</button> </form> </body> </html>

On the backend of your application, define an endpoint that creates the session for your frontend to call. You need these values:

  • The price ID of the subscription the customer is signing up for—your frontend passes this value
  • Your success_url, a page on your website that Checkout returns your customer to after they complete the payment
  • Your cancel_url, a page on your website that Checkout returns your customer to if they cancel the payment process

If you created a one-time price in step two, pass that price ID as well. After creating a Checkout Session, redirect your customer to the URL returned in the response.

server.rb
View full sample
# Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key =
'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
# The price ID passed from the front end. # price_id = params['priceId'] price_id = '{{PRICE_ID}}' session = Stripe::Checkout::Session.create({ success_url: 'https://example.com/success.html?session_id={CHECKOUT_SESSION_ID}', cancel_url: 'https://example.com/canceled.html', mode: 'subscription', line_items: [{ # For metered billing, do not pass quantity quantity: 1, price: price_id, }], }) # Redirect to the URL returned on the session # redirect session.url, 303

This example customizes the success_url by appending the Session ID. For more information about this approach, see the documentation on how to Customize your success page.

From your Dashboard, enable the payment methods you want to accept from your customers. Checkout supports several payment methods.

Provision and monitor subscriptions
Server

After the subscription signup succeeds, the customer returns to your website at the success_url, which initiates a checkout.session.completed webhooks. When you receive a checkout.session.completed event, you can provision the subscription. Continue to provision each month (if billing monthly) as you receive invoice.paid events. If you receive an invoice.payment_failed event, notify your customer and send them to the customer portal to update their payment method.

For testing purposes, you can monitor events in the Dashboard. For production, set up a webhook endpoint and subscribe to appropriate event types. If you don’t know your STRIPE_WEBHOOK_SECRET key, click on the webhook in the Dashboard to view it.

server.rb
View full sample
# Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key =
'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
post '/webhook' do webhook_secret =
{{'STRIPE_WEBHOOK_SECRET'}}
payload = request.body.read if !webhook_secret.empty? # Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured. sig_header = request.env['HTTP_STRIPE_SIGNATURE'] event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, webhook_secret ) rescue JSON::ParserError => e # Invalid payload status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature puts '⚠️ Webhook signature verification failed.' status 400 return end else data = JSON.parse(payload, symbolize_names: true) event = Stripe::Event.construct_from(data) end # Get the type of webhook event sent event_type = event['type'] data = event['data'] data_object = data['object'] case event.type when 'checkout.session.completed' # Payment is successful and the subscription is created. # You should provision the subscription and save the customer ID to your database. when 'invoice.paid' # Continue to provision the subscription as payments continue to be made. # Store the status in your database and check when a user accesses your service. # This approach helps you avoid hitting rate limits. when 'invoice.payment_failed' # The payment failed or the customer does not have a valid payment method. # The subscription becomes past_due. Notify your customer and send them to the # customer portal to update their payment information. else puts "Unhandled event type: \#{event.type}" end status 200 end

The minimum event types to monitor:

Event name
Description
checkout.session.completedSent when a customer clicks the Pay or Subscribe button in Checkout, informing you of a new purchase.
invoice.paidSent each billing interval when a payment succeeds.
invoice.payment_failedSent each billing interval if there is an issue with your customer’s payment method.

For even more events to monitor, see Subscription webhooks.

Configure the customer portal
Dashboard

The customer portal lets your customers directly manage their existing subscriptions and invoices.

Use the Dashboard to configure the portal. At a minimum, make sure to configure it so that customers can update their payment methods. See Integrating the customer portal for information about other settings you can configure.

Create a portal Session
Server

Define an endpoint that creates the customer portal session for your frontend to call. Here CUSTOMER_ID refers to the customer ID created by a Checkout Session that you saved while processing the checkout.session.completed webhook. You can also set a default redirect link for the portal in the Dashboard.

You can also create the Stripe Customer object separately and pass the customer ID to the initial call to the Checkout Session endpoint and subsequent calls to the customer portal endpoint.

You can also pass an optional return_url value for the page on your site to redirect your customer to after they finish managing their subscription:

server.rb
View full sample
# Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key =
'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
# This is the URL to which users will be redirected after they are done # managing their billing. return_url =
'{{DOMAIN_URL}}'
customer_id =
'{{CUSTOMER_ID}}'
session = Stripe::BillingPortal::Session.create({ customer: customer_id, return_url: return_url, }) # Redirect to the URL for the session # redirect session.url, 303

Send customers to the customer portal
Client

On your frontend, add a button to the page at the success_url that provides a link to the customer portal:

success.html
View full sample
<html> <head> <title>Manage Billing</title> </head> <body> <form action="/customer-portal" method="POST"> <!-- Note: If using PHP set the action to /customer-portal.php --> <button type="submit">Manage Billing</button> </form> </body> </html>

After exiting the customer portal, the Customer returns to your website at the return_url. Continue to monitor webhooks to track the state of the Customer’s subscription.

If you configure the customer portal to allow actions such as canceling a subscription, see Integrating the customer portal for additional events to monitor.

See also

  • Offer customers a free trial period
  • Apply discounts
  • Manage prorations
Was this page helpful?
Questions? Contact us.
View developer tutorials on YouTube.
Check out our product changelog.
Powered by Markdoc
You can unsubscribe at any time. Read our privacy policy.
On this page
What you’ll build
Set up Stripe
Create the pricing model
Create a Checkout Session
Provision and monitor subscriptions
Configure the customer portal
Create a portal Session
Send customers to the customer portal
Stripe Shell
Test mode
▗▄ ▄▟█ █▀▀ ▗▟████▙▖ ██████ ███▗▟█ ███ ███▗▟██▙▖ ▗▟█████▙▖ ███▖ ▀▀ ███ ███▀▀▀ ███ ███▀ ███ ███ ███ ▝▜████▙▖ ███ ███ ███ ███ ███ █████████ ▄▄ ▝███ ███ ▄ ███ ███ ███▄ ███ ███ ▄▄ ▝▜████▛▘ ▝▜███▛ ███ ███ ███▝▜██▛▘ ▝▜█████▛▘ ███ ▀▘
Welcome to the Stripe Shell! This is a graphical user interface of the Stripe CLI. You can use it to discover webhook events and manage your Stripe resources. By pressing ctrl + ` you can toggle it open from any page within the Stripe documentation. - View supported commands: - Listen for webhook events: - Trigger webhook events: - Call Stripe APIs: stripe [api resource] [api operation] (e.g. )
The Stripe Shell is best experienced on desktop.
$