🎉 Announcing our $3 million seed round
Logo
7 min read

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.

Reporting Usage

Finally, it's crucial to report the customer's usage accurately. In Stripe, usage reporting is done at the SubscriptionItem level. You can either increment the usage or set a new total value. Stripe has rate limits for usage reporting, so it's often more practical to meter usage separately and report the total amount to Stripe periodically:

await stripe.subscriptionItems.createUsageRecord('my_subscription_item_id', {
  quantity: 100,
  timestamp: 'now',
  action: 'set',
});

To avoid issues with rate limits and accuracy, we recommend using OpenMeter to measure usage and report it to Stripe. Also, check out our Stripe example on GitHub.

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?