You're adding metered pricing to a SaaS and wondering whether to wire up Stripe's Billing Meters or something newer. Start by reading the first section below against your own pricing sheet, because Stripe's own guidance changed: for new usage-based integrations its docs now point to Metronome, not to Billing Meters.
This guide covers where Stripe usage-based billing with Billing Meters still fits, how meter events behave (limits, errors, corrections), and what to show customers while usage accumulates. Everything here was checked against Stripe's documentation on 30 September 2026. It sits inside the wider SaaS billing and payments guide.
Is Stripe usage-based billing with Billing Meters still the right starting point?
Only if your pricing is plain pay-as-you-go and you already bill through Billing Meters; for new integrations, Stripe's documentation says to use Metronome, its primary usage-based billing platform.
The same page lists the cases where Metronome is the recommended route: starting from scratch, adding usage-based pricing to existing flat-rate subscriptions, prepaid credits, enterprise commits, dimensional pricing, real-time usage visibility and high-volume ingestion. Stripe adds that basic usage-based billing "remains fully supported" and that existing Billing Meters users don't need to migrate. The comparison page puts the difference in a table:
| Capability | Billing Meters (basic) | Metronome |
|---|---|---|
| Pay-as-you-go, flat fee plus overage | Supported | Supported |
| Prepaid credits with real-time drawdown | Not supported | Supported |
| Enterprise commits, minimums, ramps | Not supported | Supported |
| Dimensional pricing | Not supported | Supported |
| Real-time usage visibility | Not supported | Supported |
| Connect, Adaptive Pricing, Workflows | Supported | Not supported |
| Checkout | Supported | Limited |
Why does this matter for pricing? Usage-based models are attractive partly because buyers ask for them. An IDC survey of more than 1,000 IT professionals, reported by CIO.com in January 2025, found that 46% named unpredictable pricing as a primary obstacle to implementing generative AI, and respondents preferred pay-as-you-go consumption over upfront commitments. That is a survey of AI buyers, so treat it as a signal for AI-shaped products rather than for every SaaS.
When is a flat fee the better answer?
If usage doesn't track the value you deliver, don't meter at all. BookBed (Flutter, Firebase and Stripe) has subscriptions wired up, not yet activated for paid traffic, and no metering layer, because nothing in its pricing needs one. The question to ask is whether consumption matches customer value better than a seat or tier does. If the answer is "maybe", start flat and add metering once you have evidence. The Supabase and Stripe stack page and the subscription pattern post cover the flat-subscription baseline for a typical B2B SaaS.
What about Lago and other tools?
Open tooling exists if you want to own the billing logic. Lago's documentation describes deduplicating re-sent events through a transaction_id and running self-hosted. This guide doesn't benchmark it, so no throughput figures are quoted. Before adopting any second system, list what you'd give up: Stripe's comparison above shows Metronome gives up Connect support, and any extra billing layer means another service to run and reconcile.
How do Stripe billing meter events work?
A Billing Meter names an event, aggregates the values you report with sum, count or last, and a metered price bills that aggregate on each subscription invoice.
The implementation guide walks through three objects: a meter, a metered price attached to it, and a subscription. You create the meter once:
curl https://api.stripe.com/v1/billing/meters \
-u "$STRIPE_SECRET_KEY:" \
-d "display_name=API tokens" \
-d event_name=api_tokens \
-d "default_aggregation[formula]=sum" \
-d "customer_mapping[event_payload_key]=stripe_customer_id" \
-d "customer_mapping[type]=by_id" \
-d "value_settings[event_payload_key]=value"
Then you attach it to a price with recurring[usage_type]=metered and recurring[meter], and report usage as meter events. Stripe's migration guide states that the legacy usage records APIs were removed in API version 2025-03-31.basil and that metered prices must be backed by meters from that version on. Any tutorial that sets usage_type: 'metered' without a meter is out of date.
Two behaviours are easy to miss. Meters exist independently of subscriptions, so the same migration guide notes you can collect usage before a customer has a subscription and track many customers on one meter. And max aggregation is not supported.
Why is the meter configuration effectively permanent?
Once a meter is configured you can't change anything except its display name, according to the meter configuration docs.
That covers the event name, aggregation formula and the payload keys for customer and value. Each event name can only be used with one meter. If you realise count should have been sum, you create a new meter and move subscribers to a new price, which is a migration during a live billing period. So rehearse in a sandbox first: send events with realistic payloads, preview the invoice, and try edge cases such as zero values, very large values and payloads missing the value key. Stripe's error codes include meter_event_value_not_found and meter_event_invalid_value, so those cases do surface, just asynchronously.
The configuration page also describes two ingestion modes. Raw mode treats every event as standalone. Pre-aggregated mode keeps only the most recent event in each hourly or daily window, so a newer event overwrites the previous one. Pick deliberately, because the choice changes what a retry does.
How do you report meter events at scale without losing revenue?
Send a deterministic identifier with every event, pre-aggregate where volume demands it, and listen for Stripe's asynchronous error events, because Stripe validates meter events after it accepts them.
Here are the limits and behaviours from the recording usage documentation and the meter event API reference, as of this writing:
| Topic | What Stripe documents |
|---|---|
| Standard rate limit | 1,000 calls per second per account in live mode, plus one concurrent call per customer per meter |
| High-throughput stream (API v2) | Up to 10,000 events per second, live mode only; contact sales for up to 200,000; auth tokens valid for 15 minutes |
| Timestamp window | Within the past 35 calendar days, at most 5 minutes in the future |
| Identifier uniqueness | Enforced within a rolling period of at least 24 hours |
| Dimension cardinality | 10,000 unique combinations per meter per hour; 100 per customer per meter overall |
| Decimal values | Accepted; negative overall usage shows as 0 on the invoice |
Why does the identifier matter?
If you don't pass an identifier, Stripe generates one, so a client that retries after a timeout sends a second event that looks new. Derive the identifier from something that's identical on retry, such as your internal request ID or a hash of the usage record. Stripe's reference recommends UUID-like values and notes the uniqueness check mainly targets accidental retries within very short intervals, so it isn't a substitute for your own deduplication over longer periods.
How do you handle errors and late events?
Stripe processes meter events asynchronously and creates error events when something is wrong. The documented event types are v1.billing.meter.error_report_triggered and v1.billing.meter.no_meter_found, both delivered as thin events, and the error codes include timestamp_too_far_in_past, timestamp_in_future and meter_event_dimension_count_too_high. Subscribe to them in a webhook endpoint on day one, alert a human, then correct and resend the invalid events.
Usage reported after a period ends has a documented window. Invoices get a default finalization grace period of one hour, configurable up to 72 hours, and only subscription-cycle and schedule-phase invoices pick up usage reported during it, per the grace period docs. Usage reported after the grace period isn't included on that invoice. Decide your own cutoff for late events and write it down.
For mistakes, you can cancel events sent within the last 24 hours with a meter event adjustment, or record negative quantities. Canceling usage already on a finalized invoice doesn't update that invoice.
When should you pre-aggregate?
Stripe's own advice for high volume is to accumulate usage and send one aggregated event periodically, or move to the v2 stream. A sound pattern is a durable queue on the hot path, a background job that groups events per customer, and deterministic identifiers on each flush. The flush interval is your call; I'd start with something a human can reason about, like every minute, and raise it only if you approach the rate limit. That is my recommendation, not a Stripe figure.
What should customers see while their usage accumulates?
Show them your own live counter, and use Stripe's meter event summaries to reconcile against what will be invoiced.
The Meter Event Summary API returns aggregated usage for a customer, meter and time window:
curl -G https://api.stripe.com/v1/billing/meters/$METER_ID/event_summaries \
-u "$STRIPE_SECRET_KEY:" \
-d customer=$CUSTOMER_ID \
-d start_time=$PERIOD_START \
-d end_time=$PERIOD_END
Stripe warns that summaries and upcoming invoices might not immediately reflect recent events, because processing is asynchronous. Its own comparison table lists real-time usage visibility as unsupported in basic usage-based billing. So if customers need a number that moves as they work, keep a parallel counter in your own store and treat Stripe's summary as the billing record. Show the gap honestly instead of displaying zero while the invoice says otherwise.
Two more Stripe features reduce bill shock. Usage alerts fire when a customer crosses a meter threshold, with a maximum of 25 alerts per meter and customer combination. Billing credits cover prepaid or promotional usage, but they're applied only when an invoice finalizes, so customers can exceed their balance mid-cycle. That caveat is exactly why Stripe steers prepaid-draw-down designs to Metronome.
Wire meter errors, invoice events and subscription changes into one handler rather than several, and keep the broader Stripe integration in a single place. Your next step: in a Stripe sandbox, create one meter, send three events with fixed identifiers, resend one of them, and check whether the summary counts it once. Which of your real usage events would have no stable identifier to pass?



