Usage Metering
Phase 8 · Document 06 · LLM Gateways Prev: 05 — Routing Engine · Up: Phase 8 Index
Table of Contents
- Why This Matters
- Core Concept
- Mental Model
- Hitchhiker's Guide
- Warmup Readings
- Deep Readings and External References
- Key Terms
- Important Facts
- Observations from Real Systems
- Common Misconceptions
- Engineering Decision Framework
- Hands-On Lab
- Verification Questions
- Takeaways
- Artifact Checklist
1. Why This Matters
Usage metering is how the gateway turns every request into a billable, attributable, governable event — the foundation of cost visibility, per-tenant budgets and rate limits, chargeback, and the unit economics that decide whether your product is profitable. It's the feature that makes a gateway more than a proxy: without metering you can't answer "what does this customer cost?", can't stop a runaway tenant, and can't bill. Phase 7.09 covered cost control as a serving discipline; this doc is the gateway component that records usage, computes cost from the registry, enforces budgets/quotas, and exposes the data the dashboard and your finance team need. Get it wrong and you either lose money silently or bill customers incorrectly — both fatal.
2. Core Concept
Plain-English primer: record every request, price it, enforce limits
Metering has three jobs:
- Record a structured usage event per request (who, what model/provider, tokens, latency, cost, status).
- Compute cost from the tokens and the registry's prices (Phase 4.04).
- Enforce budgets, quotas, and rate limits — before the call (pre-flight check) and after (record actuals).
The token counts are ground truth from the provider's usage (mapped by the adapter); in streaming they arrive in the final chunk, so metering must capture them there (07, Phase 7.06).
The usage event (the atom of metering)
CREATE TABLE usage_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
request_id TEXT, ts TIMESTAMPTZ DEFAULT NOW(),
user_id TEXT, project_id TEXT, api_key_id TEXT, -- attribution dimensions
model_id TEXT, provider TEXT, route TEXT, -- what served it (route from [05])
input_tokens INT, output_tokens INT,
cached_input_tokens INT DEFAULT 0, -- prefix-cache savings [7.05]
reasoning_tokens INT DEFAULT 0, -- billed thinking [2.09]
input_cost NUMERIC(12,8), output_cost NUMERIC(12,8), total_cost NUMERIC(12,8),
ttft_ms INT, duration_ms INT,
finish_reason TEXT, fallback_used BOOL, error_type TEXT
);
Cost is the Phase 7.09/4.04 arithmetic, priced from the registry:
def cost(u, m): # m = registry row [04]
return ((u.input_tokens - u.cached_input_tokens) * m.input_price
+ u.cached_input_tokens * m.cached_input_price
+ (u.output_tokens + u.reasoning_tokens) * m.output_price) / 1e6
Budgets, quotas, rate limits (the enforcement side)
- Budget = a spend ceiling (per user/project/key, per period). Pre-flight: estimate the request's cost and reject/downgrade if it would exceed the budget; post-flight: add the actual cost to the running total (Phase 7.09).
- Quota = a count ceiling (requests or tokens per period).
- Rate limit = a velocity ceiling (RPM/TPM) to protect backends and prevent abuse — typically a token-bucket in Redis, per key.
# pre-flight (in the gateway, before routing/calling)
if spend_mtd(key) + estimate_cost(req) > budget(key):
raise HTTP(429, "Budget exceeded") # or downgrade to a cheaper model [05]
if not rate_limiter.allow(key): # token bucket (Redis)
raise HTTP(429, "Rate limit")
# ... route [05] + call ...
# post-flight
record(usage_event); increment_spend(key, usage_event.total_cost)
These tie to the routing engine's budget filter — over-budget candidates are filtered out, or the request is downgraded/rejected.
Attribution and chargeback
Every event carries dimensions — user, project, API key, model, provider, route — so you can aggregate cost per user / per workspace / per feature and do chargeback (bill internal teams or external customers for their usage). This is the data behind unit economics: cost per user, per workspace, per resolved task → gross margin (Phase 7.09, Phase 15.05).
Accuracy: reconcile against invoices
Your metered cost is an estimate from registry prices; the provider's invoice is truth. Reconcile them periodically — drift means a stale registry price (04), an unmetered path (e.g., uncaptured streaming usage, 07), or missed reasoning/cache tokens. Unreconciled metering quietly loses money or over-bills customers.
Reliability of the metering pipeline
Metering must be durable and non-blocking: emit events to a queue/async sink so a metering hiccup doesn't fail user requests, but ensure events aren't lost (at-least-once) or double-counted. Aggregate to per-period spend tables for fast budget checks. (Spend counters in Redis for hot-path budget checks; durable events in Postgres for billing.)
3. Mental Model
every request → USAGE EVENT {who · model/provider/route · tokens(in/out/cached/reasoning)
· cost · ttft/duration · finish/fallback/error}
cost = tokens × REGISTRY prices [04] (streaming: usage in FINAL chunk [07])
ENFORCE: pre-flight budget/quota/rate-limit (reject/downgrade) → ... → post-flight record + increment
budget filter feeds the ROUTER [05]; rate limit = token bucket (Redis)
ATTRIBUTE by user/project/key/feature → chargeback → $/user, $/workspace, $/resolved-task → MARGIN [15]
ACCURACY: reconcile metered cost vs provider INVOICE; pipeline durable + non-blocking
Mnemonic: record every request as a priced, attributed event; enforce budgets/quotas/rate-limits pre- and post-flight; reconcile against invoices. Metering = the gateway's billing + governance + unit-economics brain.
4. Hitchhiker's Guide
What to look for first: a complete usage event (with attribution dimensions + token breakdown) and pre-flight budget + rate-limit enforcement. Those give cost visibility and abuse protection immediately.
What to ignore at first: elaborate chargeback billing models and fancy dashboards — first get accurate, attributed events and budget enforcement; aggregation/UI follow.
What misleads beginners:
- Missing streaming usage. Token counts arrive in the final chunk — if the streaming proxy doesn't capture it, metering is blind (Phase 7.06).
- Forgetting cached + reasoning tokens. Cached input is cheaper (Phase 7.05); reasoning tokens are billed (Phase 2.09) — both must be in the event and the cost formula.
- Only post-flight enforcement. Without a pre-flight check, a runaway request/tenant blows the budget before you record it.
- No reconciliation. Metered cost drifts from invoices (stale prices, missed paths) and you lose money or over-bill.
- Blocking the request on metering. A metering outage shouldn't fail user traffic — make it async + durable.
How experts reason: they emit a rich, attributed usage event per request (durably, async), price from the registry, enforce pre- and post-flight budgets + token-bucket rate limits, aggregate to fast spend tables, and reconcile against invoices on a schedule. They treat metering as financial-grade: no lost or double-counted events.
What matters in production: event completeness/accuracy (incl. streaming, cached, reasoning tokens), reconciliation delta vs invoices, budget/rate-limit correctness, pipeline durability (no loss/double-count), and attribution granularity for chargeback.
How to debug/verify: reconcile a day's metered cost against the provider invoice; check streaming requests recorded usage; verify a budget rejects over-limit and a rate limit throttles; confirm events aren't lost under load.
Questions to ask: does it capture streaming + cached + reasoning tokens? pre-flight budget/rate-limit? per-user/project/key attribution? invoice reconciliation? durable, non-blocking pipeline?
What silently gets expensive/unreliable: uncaptured streaming usage (under-billing), missing cached/reasoning tokens (wrong cost), post-flight-only budgets (overruns), lost/double-counted events, and unreconciled drift.
5. Warmup Readings
| Title | Why to read it | What to extract | Difficulty | Time |
|---|---|---|---|---|
| Phase 7.09 — Cost Controls | The cost arithmetic + budgets | max_tokens, budgets, COGS | Beginner | 25 min |
| 04 — Model Registry | Where prices come from | pricing fields | Beginner | 20 min |
| Phase 7.06 — Streaming | Capturing usage in streams | final-chunk usage | Beginner | 20 min |
| Phase 4.04 — Pricing Pages | The price model | in/out/cached | Beginner | 20 min |
6. Deep Readings and External References
| Title | URL | Why it matters | Read first | Lab connection |
|---|---|---|---|---|
| LiteLLM spend tracking | https://docs.litellm.ai/docs/proxy/cost_tracking | Real metering | usage logs | Metering lab |
| LiteLLM budgets/rate limits | https://docs.litellm.ai/docs/proxy/users | Per-key budgets/limits | budget/tpm/rpm | Budget lab |
| OpenAI usage in responses | https://platform.openai.com/docs/api-reference/chat/object | Token usage fields | usage object | Event capture |
| Token-bucket rate limiting | https://en.wikipedia.org/wiki/Token_bucket | Rate-limit algorithm | the algorithm | Rate-limit lab |
| Phase 15.05 — Unit Economics | (curriculum) | Cost → margin | $/user, chargeback | COGS roll-up |
7. Key Terms
| Term | Simple meaning | Technical meaning | Why it matters | Where it appears | How to use it |
|---|---|---|---|---|---|
| Usage event | Per-request record | Attributed tokens+cost+latency | Billing/observability | usage_events | Emit every request |
| Attribution | Who to charge | user/project/key/route dims | Chargeback | event | Aggregate by dim |
| Cost computation | Tokens → $ | tokens × registry price | Bill accuracy | meter [04] | Price from registry |
| Budget | Spend ceiling | Per-tenant/period cap | Stop overruns | enforcement | Pre + post flight |
| Quota | Count ceiling | Requests/tokens per period | Fair use | enforcement | Per key |
| Rate limit | Velocity ceiling | RPM/TPM token bucket | Abuse/backpressure | Redis | Per key |
| Chargeback | Bill the user | Aggregate cost per dimension | Internal/external billing | reports | Per workspace |
| Reconciliation | Truth check | Metered vs invoice | Catch drift | finance | Schedule it |
8. Important Facts
- Metering = record (event) + compute (cost from registry) + enforce (budgets/quotas/rate-limits).
- Token counts are ground truth from the provider
usage; in streaming they're in the final chunk — capture them (07). - Include cached + reasoning tokens in the event and cost formula (Phase 7.05, Phase 2.09).
- Enforce budgets pre-flight (reject/downgrade) and post-flight (record) — feeds the router's budget filter (05).
- Rate limits are velocity (RPM/TPM) — typically a Redis token bucket per key.
- Attribution dimensions (user/project/key/route) enable chargeback and unit economics (Phase 15).
- Reconcile metered cost vs provider invoices to catch drift (stale prices, missed paths).
- The pipeline must be durable + non-blocking — no lost/double-counted events, no failing user traffic on a metering hiccup.
9. Observations from Real Systems
- LiteLLM records spend per key/user/team, enforces budgets + RPM/TPM, and exposes usage — production metering you can reuse (02).
- OpenRouter returns usage/cost per request and tracks per-key spend — the aggregator's metering surface (01).
- Billing incidents usually trace to uncaptured streaming usage or stale registry prices — the two classic metering bugs (07, 04).
- Reasoning-model bills surprise teams when reasoning tokens aren't metered (Phase 2.09).
- Enterprises rely on per-team chargeback from gateway metering to allocate AI spend across departments (09).
10. Common Misconceptions
| Misconception | Reality |
|---|---|
| "Usage is in the response object" | In streaming it's in the final chunk — capture it [07] |
| "Just count input+output tokens" | Include cached (cheaper) + reasoning (billed) tokens |
| "Post-flight budgets are enough" | Pre-flight prevents the overrun before it happens |
| "Rate limit = budget" | Velocity (RPM/TPM) vs spend ceiling — different |
| "Metered cost = the bill" | Reconcile vs invoices; estimates drift |
| "Metering can block requests" | Make it async + durable; don't fail traffic |
11. Engineering Decision Framework
METERING:
1. EVENT: emit a rich usage event per request (attribution dims + token breakdown + latency + status),
durably + async (no lost/double-count, no blocking traffic).
2. COST: price from the REGISTRY (input/output/cached/reasoning); capture streaming usage from final chunk. [04,07]
3. ENFORCE: pre-flight budget (reject/downgrade) + token-bucket rate-limit (Redis); post-flight record + increment. [05,7.09]
4. ATTRIBUTE: aggregate by user/project/key/route → chargeback → $/user, $/workspace, $/resolved-task. [15]
5. RECONCILE: schedule metered-vs-invoice checks; alert on drift (stale price / missed path).
6. EXPOSE: feed the admin dashboard + cost alerts. [08,7.08]
| Need | Mechanism |
|---|---|
| Stop runaway spend | Pre-flight budget (reject/downgrade) |
| Prevent abuse / protect backend | Token-bucket rate limit (RPM/TPM) |
| Bill internal teams/customers | Attribution + chargeback reports |
| Accurate bills | Capture streaming/cached/reasoning + reconcile |
| Unit economics | $/user, $/workspace, $/resolved-task |
12. Hands-On Lab
Goal
Build a metering layer: record priced, attributed usage events (incl. streaming + cached tokens), enforce a pre-flight budget and a token-bucket rate limit, and produce a chargeback report + an invoice reconciliation.
Prerequisites
- The registry from 04 for prices; SQLite/Postgres; (optional) Redis; a real or mock endpoint.
Steps
- Event + cost: for each request, capture tokens (incl.
cached_input_tokens; for streaming, parse the final chunk) and compute cost from registry prices; insert ausage_eventsrow with attribution dims. - Pre-flight budget: maintain per-key month-to-date spend; before a call, estimate cost and reject (429) or downgrade if over budget; after, increment actual spend (05/Phase 7.09).
- Rate limit: implement a per-key token bucket (RPM); fire a burst and confirm throttling.
- Chargeback report: aggregate
total_costbyproject_idand byuser_idfor a period — the data finance needs. - Reconciliation: compare summed metered cost against a (mock or real) provider invoice figure; investigate any delta (e.g., flip a registry price to simulate drift and show the reconciliation catches it).
- Streaming check: run a streaming request and confirm its usage was recorded (proving final-chunk capture, 07).
Expected output
A metering layer producing accurate, attributed, priced events; working pre-flight budget + rate limit; a per-project chargeback report; and a reconciliation that flags injected price drift.
Debugging tips
- Streaming requests show 0 tokens → not capturing the final-chunk usage [07].
- Reconciliation off → stale registry price, or missing cached/reasoning tokens in the formula.
Extension task
Add reasoning-token metering for a reasoning model and show its effect on cost (Phase 2.09); compute cost per resolved task if you have a success signal (Phase 5.09).
Production extension
Move spend counters to Redis for hot-path budget checks, events to a durable async sink (Postgres/queue), and wire chargeback + drift alerts into the dashboard and observability.
What to measure
Event completeness/accuracy (incl. streaming/cached/reasoning), budget + rate-limit enforcement, chargeback totals, reconciliation delta.
Deliverables
- A usage-event schema + recorder (priced from the registry).
- Pre-flight budget + token-bucket rate limit enforcement.
- A chargeback report + an invoice reconciliation (with injected drift caught).
13. Verification Questions
Basic
- What three jobs does usage metering do?
- Where do token counts come from in a streaming response?
- Why include cached and reasoning tokens?
Applied 4. Write the pre-flight budget check and explain reject vs downgrade. 5. How do attribution dimensions enable chargeback and unit economics?
Debugging 6. Streaming requests record zero usage. Cause and fix. 7. Metered cost is 15% below the provider invoice. Three likely causes.
System design 8. Design a durable, non-blocking metering pipeline with pre-flight budgets, rate limits, and chargeback.
Startup / product 9. Which metering outputs prove your gross margin and let you bill customers accurately?
14. Takeaways
- Metering records a priced, attributed usage event per request, computes cost from the registry, and enforces budgets/quotas/rate-limits.
- Capture streaming (final-chunk), cached, and reasoning tokens or your cost is wrong.
- Enforce budgets pre- and post-flight (feeds the router's budget filter); rate-limit by velocity (token bucket).
- Attribution → chargeback → unit economics ($/user, $/workspace, $/resolved-task).
- Reconcile against invoices and keep the pipeline durable + non-blocking.
15. Artifact Checklist
- A usage-event schema + recorder priced from the registry.
- Streaming/cached/reasoning token capture in the event.
- Pre-flight budget + token-bucket rate limit enforcement.
- A chargeback report (per project/user).
- An invoice reconciliation that catches injected price drift.
Up: Phase 8 Index · Next: 07 — Streaming Proxy