Implement advanced usage-based billing with pricing plansPrivate preview
Bill your customers based on usage and recurring charges.
You can group different pricing components into a single pricing plan. For example, you can create a pricing plan that includes rate cards for usage-based billing, license fees for recurring charges, and service actions for recurring credit grant allocations. When a customer subscribes to a pricing plan, all the recurring components are automatically enrolled and billed according to the cadence you configure.
Supported pricing models include:
- Pay as you go
- Real-time credit burndown with top-ups
- Flat fee and overages
Private preview
Pricing plans are currently in private preview and could change in functionality and integration path before they’re generally available to all Stripe users. Contact us here to request access.
Before you begin
You can also use a guided API (Blueprint) version of this guide in the Dashboard.
Pricing plans use /v2 API endpoints. Learn more about the /v2 and /v1 namespaces.
Use sandboxes to test your pricing plans integration. You can’t use test mode with /v2 APIs.
Create a pricing plan
Use the Stripe Dashboard or API to create a pricing plan that contains all the relevant billing components of your pricing model.
For each pricing plan, you can configure:
- Currency: Specify the currency for all the components in your pricing plan.
- Include tax in prices: Specify whether to include tax in your price (inclusive) or to add it to the invoice subtotal (exclusive). Learn more about inclusive and exclusive taxes for billing.
- Metadata: Optionally add your own metadata to the pricing plan.
After you set the currency and tax parameters, define the relevant components of your plan. Which components you include depends on your pricing model. This guide uses all three components ((rate cards, license fees, and service actions), but which components you use depends on your pricing model. For example, with pay-as-you-go pricing and real-time credit burndown with top-ups you only need a rate card. With flat fee and overages, you need a rate card and a license fee, and for recurring credits with overage you need a rate card and a service action.
Subscribe your customer to a pricing plan
After you set up a pricing plan, you can subscribe a customer to it. You can create a subscription by using the Checkout Sessions API with either a Stripe-hosted page or embedded components as a payment UI (the Checkout Session also creates a customer). You can also use the API to directly create a pricing plan subscription. If you use the direct API method, you need to create a customer, collection setting, billing cadence, and billing intent, which creates the pricing plan subscription.
Record customer usage
After you subscribe a customer to a pricing plan consisting of a rate card, record their usage of your service by sending meter events to a meter.
Create a preview invoice
Create a preview invoice to see a preview of a customer’s invoice. The preview includes the relevant line items from the various pricing plan components.
Monitor servicing events
Pricing plan subscriptions send event notifications whenever the servicing and collection states change.
Listen for these events and use them to construct your business logic:
v2. | The user pays the subscription which activates the service. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
v2. | The user pauses the subscription. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
v2. | The user cancels the service. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
v2. | The collection of the subscription is ongoing. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
v2. | The collection is waiting for the customer to do something. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
v2. | The collection is paused. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
v2. | The collection is past due. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
v2. | The collection is considered unpaid. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
To handle these v2 Events, configure an Event Destination and point it at your webhook endpoint. You can either:
- Create the Event Destination from Workbench.
- Create the Event Destination through the Stripe API.
After you’ve created a destination, you can set up your webhook endpoint to handle these events:
require 'stripe' post '/v2_webhook_endpoint' do payload = request.body.read sig_header = request.env['HTTP_STRIPE_SIGNATURE'] event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, endpoint_secret ) rescue JSON::ParserError => e status 400 return rescue Stripe::SignatureVerificationError => e status 400 return end client = Stripe::StripeClient() case event.type when 'v2.billing.pricing_plan_subscription.servicing_activated' # The customer clicked Pay on Stripe Checkout, which activates the service. subscription_id = event.related_object.id subscription = client.v2.billing.pricing_plan_subscriptions .retrieve(subscription_id) # Look up your user in the database using the metadata passed into # Checkout Session create user_id = subscription.metadata["my_user_id"] user = User.find_by_id(user_id) # Fill in your logic here: mark_subscription_active(user, subscription) when 'v2.billing.pricing_plan_subscription.servicing_paused' # The customer paused the subscription. subscription_id = event.related_object.id subscription = client.v2.billing.pricing_plan_subscriptions .retrieve(subscription_id) # Look up your user in the database using the metadata passed into # Checkout Session create user_id = subscription.metadata["my_user_id"] user = User.find_by_id(user_id) # Fill in your logic here: mark_subscription_paused(user, subscription) when 'v2.billing.pricing_plan_subscription.servicing_canceled' # The customer canceled the subscription. subscription_id = event.related_object.id subscription = client.v2.billing.pricing_plan_subscriptions .retrieve(subscription_id) # Look up your user in the database using the metadata passed into # Checkout Session create user_id = subscription.metadata["my_user_id"] user = User.find_by_id(user_id) # Fill in your logic here: mark_subscription_canceled(user, subscription) end status 200 end"sk_test_BQokikJOvBiI2HlWgH4olfQ2"
Test the integration
To test your integration:
- Create a sandbox.
- Create a test pricing plan and at least one underlying pricing component in your sandbox.
- Use test cards to simulate successful and failed payments.
- Create test meter events to simulate usage.
- Use test clocks to simulate billing.
Don't create test clocks in the past
When you create a test clock for a pricing plan subscription, only create clocks in the future. If you create a clock in the past, invoice amounts won’t be correct.
Create a test clock with a UNIX timestamp:
Make a note of the test clock’s ID. Next, create a test customer with the clock:
Create a billing profile:
Create a billing interval to define when to bill the customer. Save the ID.
Create a pricing plan subscription for the test customer.
Create a billing intent to track the status of the pricing plan subscription. First, you create a draft billing intent. Save the ID of the intent.
Next, reserve the billing intent:
Next, commit the billing intent to activate the pricing plan subscription and bill the customer according to the plan and cadence. (If you configured collection settings to automatic, you must have a successful PaymentIntent to commit the Intent. If you have the collection setting set to send_, you don’t need to pass the Payment Intent.)
For testing purposes, you can set payment_ to “pm_card_visa”.
Pay the invoice generated by the subscription. After the invoice is paid, you can simulate usage and advance the clock, which triggers the next month’s billing. If you use Checkout, you can open the returned Checkout Session’s url in your browser and complete payment with a test card.
Record some test usage:
Advance the test clock’s frozen time forward by a month. In this example, the test clock currently has a timestamp of 1577836800. To add a month, add 30 * 24 * 60 * 60, or 2592000 seconds. The new timestamp a month from now is 1580428800.
OptionalCollect taxes
To collect taxes automatically, create a Checkout Session that includes checkout_items and set automatic_ to true.
The page displays your pricing plan’s details and collects the customer’s payment information. After the customer completes the session, they’re redirected to the URL you specified for success_.
OptionalSet up the customer portal
You can provide self-service functions to your customers by setting up a customer portal.
Using the customer portal with pricing plan subscriptions is currently read-only: customers can’t cancel, change plans, or update their payment methods for pricing plan billing subscriptions. Currently, you can only configure a customer portal session through the Dashboard.
Using the customer portal with pricing plan subscriptions lets your customers view:
- The plan they’re subscribed to, including details of the hybrid plan you’re offering.
- Upcoming invoices that help them understand how much they’ll be billed at the end of the month.
- The payment method on file for the Subscription in question.
- Past invoices they’ve been charged for.
- Their billing information.
