Logo

How To Implement Usage-Based Pricing with Stripe?Comprehensive guide to translating SaaS packaging and pricing into Stripe

Peter Marton
Peter Marton@slashdotpeter
cover

Engineers often get confused about how to model SaaS products’ pricing and packaging with Stripe. This can be even more difficult for people new to Stripe and having usage-based pricing scenarios. As Stripe was designed to be generic enough for physical and software goods, engineers must tailor entities to their specific use case. By the end of this guide, you will master translating SaaS pricing and packaging concepts into Stripe entities.

Our Example

To illustrate, we'll use a hypothetical Twilio-like API-driven SMS/MMS-sending service as our case study. This example will help clarify how to translate various pricing and packaging concepts into Stripe and implement usage-based pricing effectively.

HobbyPro
Base Fee$99/m$249/m
SMS Included20,000100,000
SMS Send ($/SMS)$0.005$0.004
MMS Send ($/MMS)$0.015$0.01
Annual discount20%20%

The upcoming sections will cover the key points to translate the pricing table above into Stripe following these steps:

  1. Defining products and prices for our line items (SMS, MMS)
  2. Applying tiered pricing for our plans' included SMS
  3. Using meters to manage prices
  4. Packaging prices for customers and subscriptions
  5. Reporting usage

Products and Prices

Everything in Stripe starts with Product and Price entities. The product word is often synonymous with the software sold in the SaaS world. But in Stripe, a Product is the smallest entity that can be priced. In our example, SMS is one product, and MMS is another. Products can have single or multiple prices, depending on various factors such as:

  • Different plans (Hobby vs. Pro)
  • Different currencies (USD, Eur, etc.)
  • Different billing cycles (Monthly, Annual, etc.)
  • Experimenting with pricing or grandfathering old customers

Prices can also be one-time fees, for example, an installation fee or recurring, which is billed for every current and future billing period. In our example, all prices are recurring, monthly, or annually.

We have two Stripe products: SMS and MMS, each with different recurring prices for the Hobby and Pro plans. Moreover, we offer a 20% discount on annual subscriptions, necessitating two more permutations for monthly and annual subscriptions. Hence, we define 2 Products (SMS, MMS) _ 2 Plans (Hobby, Pro) _ 2 Billing Periods (Monthly, Annual) = 8 Prices in total.

Stripe Products and Prices Note, amounts in Stripe are in cents

Note: If your business operates in multiple currencies, you will need to duplicate prices for each of them.

We also need to account for the base fee and the included SMS. There are multiple ways to do this. For simplicity, we'll include them in the SMS price as a zero-fee first tier in the next chapter, but alternatively, you could define a new product and prices just for the base fee.

Per Unit and Tiered Pricing

Stripe's recurring prices can be set per unit or using tiered pricing. With Stripe’s tiered pricing, you can define the price per unit or volume. This also allows us to describe included units and more complex pricing structures like volume-based or graduated pricing.

For example, here's how we would describe the 20,000 SMS included in the Hobby plan using tiered pricing:

First UnitLast UnitPer UnitFlat Fee
020,000-$99
20,001$0.005

Stripe Tiered Price

Licensed and Metered

Stripe's recurring price usage type can be set to licensed or metered. It's set to licensed by default, meaning the customer always pays for the same quantity regardless of usage. For usage-based pricing, this must be set to metered, and the customer’s consumption (usage) needs to be reported. For instance, here's how we can set the Stripe price object to reflect this:

{
  id: 'price_xxx',
  object: 'price',
  billing_scheme: 'tiered',
  currency: 'usd',
  product: 'prod_OHWPWbAhIdEpq4',
  recurring: {
    aggregate_usage: 'sum',
    interval: 'month',
    interval_count: 1,
    trial_period_days: null,
    usage_type: 'metered'
  },
  tiers: [
    {
      flat_amount: 9900,
      flat_amount_decimal: '9900',
      unit_amount: null,
      unit_amount_decimal: null,
      up_to: 20000
    },
    {
      flat_amount: null,
      flat_amount_decimal: null,
      unit_amount: null,
      unit_amount_decimal: '0.5',
      up_to: null
    }
  ],
  tiers_mode: 'graduated',
  type: 'recurring',
  unit_amount: null,
  unit_amount_decimal: null,
  ...
}

Packaging and Customer Subscriptions

In the previous chapters, we defined our products and prices to describe our example pricing table in Stripe. Now it’s time to package them for our customers with Stripe’s subscription entity. In Stripe, you can assign one or many subscriptions to a customer. A Subscription defines, for example, the billing period and frequency. It also has a billing anchor to tell Stripe which day the subscription needs to switch the billing cycle. The part we will focus on now is the packaging which is described in Stripe via the SubscriptionItem entity. A SubscriptionItem is essentially a single price with a corresponding product. For example, SMS Hobby Monthly price. If a price is licensed, this is also where we can define the licensed quantity. Our prices are usage-based (metered), so we won’t need to define quantity.

For example, when we start a monthly Hobby subscription for our customer, the Subscription and its items would look the following:

const subscription = await stripe.subscriptions.create({
  customer: 'cus_O7paI94y4zKm1q',
  items: [
    // SMS Hobby Monthly Price ID
    { price: 'price_1NLZvGLvyihio9p5V3w373xd' },
    // MMS Hobby Monthly Price ID
    { price: 'price_1NLZvGLvyihio9p5V3w373xd' },
  ],
});

Stripe Subscription Items

It makes sense, but worth noting that the subscriptions’ billing period has to match the price’s recurring interval. For example, you can only add monthly prices to monthly subscriptions.

Metering Usage

Update, March 2024

As of March 2024, Stripe has introduced a new Meter entity to track usage. We updated the guide to reflect this change.

Stripe has a Meter entity that you can assign to a price to track usage.

The great thing is that the reported usage on the meter is decoupled from the price. We can create new prices with an existing meter, and the usage can be tracked on the same meter.

1. Create a Stripe meter for SMS usage:

We recommend creating meters on the Stripe Dashboard, but you can also do it programmatically. If you are using the OpenMeter Stripe Integration, we create the meters for you automatically.

const meter = await stripe.billing.meters.create({
  display_name: 'SMS Total',
  event_name: 'sms_sent',
  default_aggregation: {
    formula: 'sum',
  },
  customer_mapping: {
    type: 'by_id',
    event_payload_key: 'stripe_customer_id',
  },
});
Stripe doesn't support dimensions

As of July 2024, Stripe meters don't support group bys. If you need to track usage by dimensions like GPT-3, GPT-4, etc. you need to create multiple meters.


We recommend using OpenMeter Stripe Integration for advanced metering and syncing usage data to Stripe.

2. Assign the meter to the SMS price:

We recommend creating meters on the Stripe Dashboard, but you can also do it programmatically.

const price = await stripe.prices.create({
  object: {
    id: "price_1Pf6cRE98Y117at04Pcua14D",
    active: true,
    billing_scheme: "per_unit",
    currency: "usd",,
    product: "prod_QW8uP54CnZmCZE",
    type: "recurring",
    recurring: {
      interval: "month",
      interval_count: 1,
      meter: meter.id,
      usage_type: "metered",
    },
    unit_amount: 100,
    unit_amount_decimal: "100",
  },
});

3. Report usage to the meter:

Stripe meters are event-based, so you need to report usage as events. For example, to report 10,000 SMS for a customer, we would use the following code:

const meterEvent = await stripe.billing.meterEvents.create({
  event_name: 'sms_sent',
  payload: {
    value: '10000',
    stripe_customer_id: 'cus_NciAYcXfLnqBoz',
  },
  identifier: 'identifier_123',
});
Stripe API Limit: 1,000 RPS

Stripe meters have a 1,000 event limit per second, so you might need to batch your usage reporting before reporting it to Stripe.


We recommend using OpenMeter Stripe Integration to avoid rate limits and pre-aggregate usage.

Summary

In conclusion, while implementing usage-based pricing with Stripe may seem challenging, understanding the process and the right tools can simplify it greatly. Remember, the key is to accurately translate your pricing model into Stripe's Product, Price, and Subscription entities.

Checkout OpenMeter’s demo, where we build usage-based pricing with Stripe from scratch: OpenMeter.io Stripe Usage-Based Pricing Tutorial.

Implementing usage-based billing?