Claude API Usage-Based Billing Implementation
Why usage-based billing is hard with the Claude API
If you're building a product on top of Claude and charging customers based on how much they use it, you need a system that turns raw API responses into accurate, auditable billing records. The core challenge is that Claude's API bills you (the developer) per token, but your customers probably don't want to think in tokens — they want to pay per message, per document processed, per seat, or a flat monthly fee with usage caps. Implementing usage-based billing means building the translation layer between Anthropic's token-based pricing and whatever pricing model your product actually sells.
This article walks through the pieces you need: capturing usage data from every API call, aggregating it correctly across streaming and tool-use requests, mapping it to a price, and getting that into an invoicing system like Stripe without losing accuracy or double-counting retries. If you'd rather skip building this yourself, a proxy like SubToAPI exposes per-key usage metadata out of the box — but the rest of this guide is useful whether you build it in-house or not.
What you need to meter
Every Claude API response includes a usage object with input and output token counts. That's your raw metering data, but it's not the whole picture:
- Input tokens — your prompt, system message, and conversation history
- Output tokens — what Claude generates
- Cache read/write tokens — if you use prompt caching, these are billed differently and need separate tracking
- Tool use — tool calls and tool results count as regular input/output tokens, but you may want to track them separately for analytics even if you bill them the same way
- Failed requests — a request that errors before generation still consumes some input tokens in certain cases; decide up front whether you bill for these
A minimal usage record per API call should look like this:
{
"request_id": "req_8f2a...",
"customer_id": "cus_104",
"model": "claude-sonnet-4",
"input_tokens": 842,
"output_tokens": 311,
"cache_read_tokens": 0,
"cache_write_tokens": 0,
"timestamp": "2025-01-14T10:22:03Z"
}
Store this for every call, not just successful ones with completions — you'll need it for reconciliation later.
Capturing usage from streaming responses
Streaming complicates metering because the usage field doesn't arrive until the final event. You have to buffer the stream server-side (even if you relay it to the client in real time) and read the message_stop or final message_delta event to get the authoritative token counts.
let finalUsage = null;
for await (const event of stream) {
if (event.type === "message_delta" && event.usage) {
finalUsage = event.usage;
}
// relay event to your client as usual
}
await recordUsage({
customerId,
inputTokens: finalUsage.input_tokens,
outputTokens: finalUsage.output_tokens,
});
Never estimate token counts client-side with a tokenizer approximation for billing purposes — small discrepancies compound at scale and lead to billing disputes. Always use the counts Anthropic returns. See the streaming guide in the docs at /docs/streaming if you're integrating this through a proxy rather than the raw API.
Mapping usage to a price
Once you have raw token counts, you need a pricing function. Keep this as a pure function, separate from your metering pipeline, so you can change prices without touching how data is collected:
function calculateCost(usage, rateCard) {
const inputCost = usage.input_tokens * rateCard.inputPerToken;
const outputCost = usage.output_tokens * rateCard.outputPerToken;
const cacheCost =
usage.cache_read_tokens * rateCard.cacheReadPerToken +
usage.cache_write_tokens * rateCard.cacheWritePerToken;
return inputCost + outputCost + cacheCost;
}
Decide early whether you're passing Anthropic's raw cost through with a markup, charging a flat per-request fee, or bundling usage into subscription tiers with overage billing. Most SaaS products on top of Claude do some combination: a base plan with included usage, then metered overage billed through Stripe's usage records API.
Sending usage to your billing provider
Aggregate usage records on a schedule (hourly or daily is typical) rather than calling your billing provider on every API request — this avoids rate limits and keeps your billing pipeline resilient to retries:
const dailyUsage = await aggregateUsageByCustomer(date);
for (const [customerId, usage] of dailyUsage) {
await stripe.billing.meterEvents.create({
event_name: "claude_tokens",
payload: {
stripe_customer_id: customerId,
value: usage.totalTokens.toString(),
},
});
}
Keep the raw per-request records even after aggregation — you'll need them if a customer disputes a charge or you need to debug a spike in usage.
Multi-tenant and team billing
If your product has teams or seats, usage needs to roll up from individual API keys to an organization, and you need a way to attribute each call to the right tenant even when requests come from shared infrastructure. This is one of the more tedious parts to build correctly — key provisioning, per-key usage tracking, and rollups to a team invoice.
This is exactly the layer SubToAPI handles if you don't want to build it: it issues scoped application keys (sub_live_...) per team member, tracks usage metadata per key automatically, and gives you a dashboard view without writing a metering pipeline yourself. Plans run from Solo at €9 up to Team and Scale tiers with per-seat pricing — see /pricing for details, or start with a free trial at /signup. If you're integrating against it directly, the request format mirrors the standard Messages API, documented at /docs/messages and /docs/quickstart.
Common pitfalls
- Double-counting retries: if your app retries failed requests automatically, make sure you're not billing the customer for the failed attempt and the successful one.
- Ignoring tool use token overhead: tool definitions sent with every request add input tokens even when no tool is called — this adds up for customers with large tool schemas (see
/docs/toolsfor how tool definitions affect request size). - Billing lag: if you aggregate daily but your customer expects real-time usage visibility, build a lightweight running counter they can query, separate from your invoicing aggregation.
- Currency and rounding: token costs are fractions of a cent — accumulate in a high-precision unit (e.g., micro-cents) internally and round only at invoice time.
FAQ
Does Anthropic provide usage-based billing for my own customers? No. Anthropic bills you directly for API usage. If you want to charge your own customers based on their usage, you need to build (or use) a separate metering and invoicing layer on top.
Should I bill customers in tokens or in a simplified unit like "credits"? Most products abstract tokens into credits or request counts because customers don't think in tokens. Keep token counts as your internal source of truth and convert to whatever unit you expose externally.
How often should I sync usage data to my billing provider? Hourly or daily batches are standard for most products. Real-time sync is rarely necessary unless you're enforcing hard spending caps, in which case you need a separate real-time counter independent of your invoicing pipeline.