How do you meter AI usage for billing? Pick a billable unit your customers understand, record exactly one usage event for each unit delivered, keyed by an identifier such as your request id, and send those events to your billing system before the invoice closes. Then reconcile the billed totals against your own request log every period. The pricing is the easy part; this guide covers the data underneath it.
Choose the billable unit first
The unit you bill decides everything downstream. There are three common choices:
| Unit | Example | Good when | Problem |
|---|---|---|---|
| Raw tokens | 1M tokens | Your customers are developers buying model access | Unpredictable for customers; changes with model and tokenizer |
| Work units | Documents, answers, images, audio minutes | Each unit has a stable meaning to the customer | You carry the risk of cost per unit changing |
| Outcomes | Resolved tickets, completed tasks | Value is clear and measurable | Needs a reliable definition of "done" |
For most SaaS products, work units are the right answer. A customer can predict "500 documents a month"; nobody can predict tokens. Work units also protect the customer from your model choices: if you move a feature to a model whose tokenizer produces more tokens for the same text, their bill should not change.
Internally, keep both: the unit you bill and the provider cost behind it. The gap between them is your margin per unit, and it is the number to watch. AI feature unit economics shows how to work it out.
Price the unit from cost, then check it against value
A work unit needs a price that survives your heaviest realistic use of it. Start from the provider cost of one unit at the 90th percentile, not the median, because the expensive documents and long conversations are the ones that erode margin. Add the cost of retries and failures you absorb, then your target margin. That is the floor.
Then compare the floor with what the work is worth to the customer. If a reviewed contract saves a lawyer twenty minutes, $0.13 is far below the value and you have room; if the floor is close to the value, the feature needs a smaller model or a different design before it needs a price. Review the floor whenever a provider changes a rate.
Design the usage event
One event per billable unit, written when the unit is delivered. A good event carries:
{
"event_id": "req_01JBZ4K2M7", // unique and stable: your request id
"customer_id": "cust_42", // your billing customer, not an email
"unit": "document_processed",
"quantity": 1,
"occurred_at": "2026-10-20T14:03:11Z",
"feature": "contract-review",
"model": "anthropic/claude-sonnet-5.5", // for your margin analysis, not the invoice
"provider_cost_usd": "0.0231" // estimate, for margin; never billed directly
}Three rules make it reliable:
- The identifier is the deduplication key. Derive it from something that already exists once per unit, such as the request id. A retried send of the same event must carry the same identifier.
- Write it after delivery, not before the call. An event written before the provider call bills requests that later fail.
- Keep it immutable. Corrections are new events (a negative quantity, or an adjustment in your billing system), not edits, so the history explains itself.
Decide the edge cases before the first invoice
Every AI product meets the same five cases. Write down what each one bills before a customer asks.
- Failed requests. The provider erred or timed out and the customer got nothing. Most products bill nothing, but count the failure separately so totals reconcile with the request log.
- Retries. Your code retried a timed-out request and the provider billed both attempts. The customer received one result, so bill one unit; absorb the duplicate provider cost and track it.
- Streams cut short. The customer's connection dropped halfway through a streamed answer. Decide whether a partial answer is a unit. Usage for a stream often arrives only at its end, so a disconnected stream may have no usage at all from the provider.
- Cached answers. If you serve repeats from a cache at no provider cost, decide whether the customer pays for the unit. Billing the unit keeps pricing predictable; not billing it is generous. Either is fine if it is stated.
- Internal and trial traffic. Evaluations, demos and free trials should never produce billable events. Keep them under a separate customer id or project.
Getting usage into Stripe
Stripe now offers two routes. Its documentation calls Metronome, now part of Stripe, its primary usage-based billing platform and the recommended starting point for new integrations, with real-time usage visibility and high-volume ingestion; basic usage-based billing on the Meters API remains fully supported for existing integrations12.
If you use the Meters API, these limits shape the design3:
- Event fields. Each meter event carries the meter's event name, the Stripe customer id, a numerical value (decimals allowed) and an optional timestamp.
- Idempotency. Every meter event has an identifier you can set; if you do not, Stripe generates one. Set it, from your request id.
- Time window. Timestamps must be within the past 35 calendar days and not more than 5 minutes in the future. Stripe notes that accepting an event does not guarantee it reaches an invoice: usage must be reported before the period's invoice finalizes.
- Rate. Live-mode meter events are limited to 1,000 calls per second per account and one concurrent call per customer per meter. The v2 meter event stream accepts up to 10,000 events per second.
- Dimensions. Each meter accepts up to 10,000 unique dimension combinations per hour, and 100 per customer across all events.
import stripe
def report_usage(event: dict) -> None:
stripe.billing.MeterEvent.create(
event_name="documents_processed",
identifier=event["event_id"], # same id on every retry: counted once
payload={
"stripe_customer_id": event["stripe_customer_id"],
"value": str(event["quantity"]),
},
timestamp=event["occurred_at_unix"],
)The per-customer concurrency limit is the one that surprises teams: a busy customer generating many units per second will hit it. Stripe's own advice is to pre-aggregate usage before sending, for example one event per customer per minute, or to use the meter event stream for high volumes3. Pre-aggregation also reduces how much of your request path depends on a third-party API being up.
Reconcile every period
Usage billing goes wrong quietly: an event that failed to send, a duplicate with a fresh identifier, a timezone boundary. Close each period with a reconciliation:
- Sum billable units per customer from your request log.
- Sum the same customers' metered usage in the billing system.
- Investigate every difference above a small threshold before invoices finalize.
Do the same on the cost side: sum your estimated provider cost and compare it with the provider's invoice. A customer's share of provider cost is always an estimate, because provider cost APIs report organization totals; the organization total is what reconciles. Reconciling estimated LLM spend covers the cost side.
Limits before invoices
A usage price without a limit turns an infinite loop in a customer's integration into a large invoice and a dispute. Put a spend or quota ceiling on every usage-billed customer, with a notice at a threshold and an explicit opt-in to go above it. Per-customer AI usage limits covers the enforcement.
Exporting usage per customer from INFRO
If your AI requests go through INFRO, each one is already attributed to the end-customer id your app sends in metadata.user_id or the X-INFRO-User-Id header. From the Team plan, GET /v1/usage/end-customers returns one row per end customer, period, project and model — requests, unpriced and failed requests, cached responses, tokens, media units and the estimated provider cost at the rate in force when each request ran — as JSON pages or one CSV, ready to aggregate into meter events. INFRO measures; your billing system bills at your prices. INFRO never charges your customers and takes no part in that billing.
Summary
Bill a unit customers can predict, record one immutable event per unit with an identifier you already have, settle the edge cases in writing, send events within your billing system's window, and reconcile billed usage against your request log before every invoice closes.
