Usage-based billing for APIs, explained
Updated October 20, 2026
Usage-based billing means each customer pays for what they used in a billing period instead of, or on top of, a fixed fee. For an API, that means counting billable requests per customer, adding them up when the period ends, pricing the total and putting it on an invoice. On Stripe, a meter does the adding up, a metered price does the pricing, and the subscription's period-end invoice charges it.
What it looks like for an API
Take a plan that costs $29 a month, includes 100,000 requests and charges $0.50 per 1,000 requests after that. A customer whose billing period runs from the 14th to the 14th makes 128,400 requests:
| Amount | |
|---|---|
| Included requests | 100,000 at $0 |
| Overage | 28,400 requests × $0.0005 = $14.20 |
| Next month's base fee | $29.00 |
| Invoice on the 14th | $43.20 |
Two timing details surprise people. The base fee is charged in advance and usage in arrears, so each invoice pairs next month's fee with last month's usage. And the first invoice of a new subscription has only the $29, because there's no usage yet.
Usage-based billing vs. usage-based pricing
The two terms get used interchangeably, but they're different jobs. Usage-based pricing is the commercial decision: per request, tiers, prepaid credits, or a base fee with included usage. Usage-based billing is the machinery that makes any of those work: counting, reporting, rating, invoicing and collecting. A pricing mistake is visible on your pricing page. An API usage billing mistake hides in invoices that look plausible, sometimes for months. This page is about the machinery; the usage-based pricing guide covers choosing the model.
The pipeline, stage by stage
Every usage billing system has the same six stages. Stripe runs the last four. The first two are yours, and Stripe can't check them for you.
| Stage | What happens | Where it goes wrong |
|---|---|---|
| Count | Your API records each billable request against a customer | Retries and failed requests get counted |
| Report | You send usage to Stripe as meter events | Events are duplicated, lost or late |
| Aggregate | The meter adds up events per customer and period | Events land in the wrong period |
| Rate | The metered price turns the total into money | Tiers set up so included units get charged |
| Invoice | The period-end invoice gets a line for the usage | Usage arrives after the invoice is final |
| Collect | Stripe charges the card and retries failures | You've already served usage that never gets paid |
The last row matters more for usage than for subscriptions. You deliver the requests before you get paid, so a new customer with a failing card can run up a month of usage first. Consider capping usage for new accounts, or selling prepaid credits, until a few invoices have cleared.
What to meter, and what not to bill
Count a request when you know its outcome, after the response status is set, not when it arrives. Then bill by status:
| Response | Bill it? | Why |
|---|---|---|
| 2xx | Yes | The customer asked for the work and got it |
| 5xx | No | The failure was yours, and charges for your outages make customers distrust the whole invoice |
| 429 | No | You refused the request |
| 401, 403 | No | There's no valid customer, or the call wasn't allowed |
| A retry with an idempotency key you've seen | No | The client got a stored response, not new work |
| Other 4xx (400, 404, 422) | Usually not | Our default; see below |
If you rate limit per customer (see API rate limiting), make sure the counter skips 429s. For other 4xx errors, bill only if a kind of bad request costs you real money, for example because you call a paid model before validation fails, and say so in your docs.
As for the unit, per request is the easiest for customers to check against their own logs. Start there unless your cost per call varies a lot; then meter tokens, rows or pages instead.
Idempotency: count once, report once
Duplicates come in at two layers.
Between your customer and you, a client that times out and retries without an idempotency key looks like two requests. Support Idempotency-Key headers on anything expensive and count only the first request per key. Without keys you can't tell a retry from a second call.
Between you and Stripe, your reporting job retries too. Each meter event has an identifier, and Stripe enforces uniqueness for a rolling period of at least 24 hours, so a retry with the same identifier inside that window isn't counted twice. Derive the identifier from what the event represents, such as the customer plus the period, never from a random value per attempt. And keep a ledger of what you sent: a retry after a day has no protection, so check the meter's total before resending.
Mistakes can be undone only briefly: Stripe can cancel a meter event by identifier within 24 hours of receiving it. After that, the event stays.
Billing periods and late usage
A billing period isn't a calendar month. Each subscription item has its own current_period_start and current_period_end, anchored to a UTC timestamp, usually the second the subscription started. A customer who subscribed at 14:23:07 UTC on the 14th has periods that turn over at 14:23:07 UTC on the 14th of each month.
Each meter event counts toward the period its timestamp falls in. Stripe accepts timestamps up to 35 days in the past and 5 minutes in the future, but accepting an event isn't the same as billing it. When a period ends, Stripe creates the invoice as a draft and finalizes it after a grace period: 1 hour by default, configurable up to 72 hours. Usage that arrives after finalization still shows up in the meter's summaries, but Stripe adds it to neither that invoice nor the next one. Late data from a stuck queue or a crashed worker becomes revenue you never collect.
So report each period's usage well inside the grace period, and alert when a period's report hasn't gone out. Decide where boundary data goes, too. A period total stamped one second before the period ends can't slip into the next period, and if you aggregate per minute, assign the minute that straddles a boundary by the same rule everywhere you count.
How Stripe's pieces fit together
On Stripe, usage billing is four objects:
- A meter has an event name and an aggregation formula:
sumadds up event values,countcounts events,lastkeeps the latest value. It also says which payload key holds the customer ID. - A metered price is a recurring price with
usage_type: meteredthat points at the meter. It can be per unit or tiered, and it can go below a cent withunit_amount_decimal. - A subscription holds the metered price, usually next to a flat monthly price. In Checkout, the metered line item takes no quantity.
- The invoice at the end of each period gets one line per metered price, with the quantity from the meter and the amount from the price.
To read usage back, Stripe offers meter event summaries per customer and time window, plus a preview of the upcoming invoice. Both lag a little, because Stripe processes meter events asynchronously. Usage records, the older way to report usage, were removed in API version 2025-03-31.basil.
Stripe's docs now recommend Metronome, a Stripe product, as the starting point for new usage-based integrations, and describe meters as basic usage-based billing that "remains fully supported for existing integrations." Meters still cover a base fee plus overage, you set them up yourself through the API or Dashboard, and Stripe's comparison gives them fuller Checkout, Connect and Dashboard support. Metronome is aimed at real-time usage, prepaid credits that draw down, contract commitments and high event volumes, and Stripe suggests contacting your Stripe representative to evaluate it. Stripe's recommendation has shifted before, so check that page when you start. For the code, see the Stripe usage-based billing tutorial.
Showing usage to customers
Customers check their usage before the invoice arrives, and they get annoyed when the number they saw mid-month doesn't match the bill. You have three places to get that number:
- Stripe's invoice preview shows the upcoming amount, but only for usage you've already reported, and it lags behind.
- Meter event summaries give per-customer totals by hour or day, with the same lag and the same dependence on what you've reported.
- Your own counts are current, and they are what you report anyway.
Show your own counts, labeled with when they were last updated: included requests used ("72,315 of 100,000"), overage so far, and a projected bill at the current rate. Email customers at 80% and 100% of their included amount. In Stripe's own comparison, basic usage-based billing doesn't offer real-time usage visibility, so this part is on you either way.
UsageRail sends Stripe one usage event per customer per period, 2 hours after the period ends, so mid-period usage appears in its portal, widget and dashboard rather than in Stripe's upcoming invoice.
Mistakes that cause billing errors
Counting retries twice
Client retries without idempotency keys, and reporting jobs that retry with a new identifier or after the 24-hour window, both inflate the bill. Customers find these by comparing your invoice with their logs.
Billing your own errors
Counting at request start, or counting every response, bills 5xx errors and 429s. Count after the response, by status.
Changing a metered price mid-cycle
This one loses money quietly. Since API version 2025-09-30.clover, subscriptions created through the API default to flexible billing mode: swap a metered price mid-period and the usage before the swap is rated at the old price, but with proration_behavior: none it's never charged. In classic billing mode, pre-swap usage is ignored entirely. In both modes, usage reported during the grace period after a mid-cycle price change is dropped. Stripe documents the details in its mid-cycle update guide.
The safer pattern is to apply any change that touches a metered price at the end of the period with a subscription schedule. Invoices from schedule phase transitions that change metered items do pick up grace-period usage. For this reason, UsageRail applies plan changes that involve a usage-based price at the end of the billing period.
Reporting after the invoice finalizes
With the default 1-hour grace period, a reporting job that runs a few hours after the period ends bills nothing for that period. Raise the grace period, report sooner, or both. The metered billing guide covers which grace period to pick and how to check each invoice afterward.
Canceling the wrong way
Canceling a subscription immediately without prorate discards the period's metered usage. Cancel at period end instead: the final invoice then includes the last period's usage.
Expecting to bill trial usage
Stripe doesn't bill usage recorded during a free trial; billing starts with the first paid period, which begins when the trial ends. If trial customers can make real calls, cap their usage, because whatever they use is free.
Time zones and period edges
A dashboard that groups usage by calendar month in your local time won't match invoices that follow the subscription's own periods, and Stripe's daily summaries follow UTC days. Store usage in UTC and total it by the subscription's period boundaries, not by month.
Usage billing that checks its own math
UsageRail counts billable requests per customer, sends Stripe one usage event per billing period, then reads the invoice back and flags any line that doesn't match its own total.
Start freeStripe billing isn't live yet. Keys, rate limits, quotas and the portal work today.