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 to implement complex pricing models that combine multiple charging strategies. For example, 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, Stripe automatically enrolls and bills all recurring components at 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 in private preview and might change in functionality and integration path before they become generally available to all Stripe users. Contact us here to request access.
Before you begin
- Pricing plans use
/v2API endpoints. Learn more about the /v2 and /v1 namespaces. - Use sandboxes to test your pricing plans integration. You can’t use test mode with
/v2APIs.
You can also use a guided API (Blueprint) version of this guide in the Dashboard.
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, 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 setting the currency and tax parameters, define the relevant components of your plan. Which components you include depends on your pricing model. This guide demonstrates all three components ((rate cards, license fees, and service actions). For example, pay-as-you-go pricing and real-time credit burndown with top-ups only need a rate card, flat fee and overages needs a rate card and license fee, and recurring credits with overage needs a rate card and 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.new() 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 Simulations 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.
