Claude API Multi-Tenant Usage Tracking: A Dev Guide
If you're building a SaaS product on top of Claude and serving multiple customers, teams, or workspaces from a single Anthropic account, you need a way to answer one question reliably: how much did each tenant actually use? Claude API multi-tenant usage tracking means attributing every request, every input/output token, and every dollar of spend to a specific customer, team, or internal project — not just to your account as a whole.
This matters for three reasons: you need accurate usage-based billing for your own customers, you need to detect which tenant is driving cost spikes or abuse, and you need per-team quotas so one noisy tenant doesn't burn through your shared Anthropic budget. Anthropic's raw API gives you a single key tied to your account — it doesn't natively separate usage by customer. Solving multi-tenancy is something you have to build on top, either yourself or with a layer like SubToAPI (https://subtoapi.app).
Why Raw Claude API Access Doesn't Solve This
A standard Anthropic API key is account-level. Every call you make — regardless of which customer triggered it — hits the same key and shows up in the same usage dashboard. If you're running a multi-tenant SaaS (an AI writing tool, a support bot platform, an internal developer tool with multiple teams), you have a few options:
- Provision a separate Anthropic key per tenant. This works but Anthropic's console isn't built for managing hundreds of keys with per-tenant metadata, spend caps, or revocation at scale.
- Build your own proxy layer that logs every request with a
tenant_id, calls Claude, and writes usage to your database. - Use a layer that already does this, giving each application or customer its own scoped API key with usage reporting baked in.
Option 2 is the most common DIY path, so let's look at what it actually requires.
What You Need to Track Per Tenant
At minimum, a usage tracking system needs to capture, per request:
- Tenant/customer identifier — which account or workspace triggered the call
- Model used — Claude Opus, Sonnet, and Haiku have different pricing
- Input tokens and output tokens — these are billed separately and at different rates
- Timestamp — for daily/monthly rollups and rate windows
- Request outcome — success, error, or rate-limited (for debugging and SLA reporting)
- Feature or endpoint — if your product has multiple AI features, track which one was used
A Minimal Logging Schema
CREATE TABLE usage_events (
id BIGSERIAL PRIMARY KEY,
tenant_id TEXT NOT NULL,
model TEXT NOT NULL,
input_tokens INT NOT NULL,
output_tokens INT NOT NULL,
feature TEXT,
status TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_usage_tenant_time ON usage_events (tenant_id, created_at);
Every call to Claude should write one row here. Then your billing job aggregates by tenant_id and created_at at the end of each billing period.
Capturing Token Counts from the API Response
Anthropic's Messages API returns usage data in every response:
{
"id": "msg_01...",
"usage": {
"input_tokens": 512,
"output_tokens": 128
}
}
Your proxy or middleware layer should read this field on every call and write it to your usage table, tagged with the tenant that made the request:
async function callClaudeForTenant(tenantId, messages, model) {
const res = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": process.env.ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({ model, max_tokens: 1024, messages }),
});
const data = await res.json();
await db.usage_events.insert({
tenant_id: tenantId,
model,
input_tokens: data.usage.input_tokens,
output_tokens: data.usage.output_tokens,
status: res.ok ? "success" : "error",
});
return data;
}
This works, but you're now maintaining a logging pipeline, a rollup job, per-tenant rate limiting, and (eventually) a dashboard so your support team can see what each customer is using.
A Faster Path: Per-Tenant API Keys
Instead of building this proxy and ledger yourself, you can issue a distinct API key per tenant and let the usage tracking happen automatically at the key level. SubToAPI works this way: you connect your existing Claude access once, then generate scoped sub_live_... keys — one per customer, team, or environment — from your dashboard. Every request made with a given key is automatically attributed to that key's usage history, with input/output token counts and request metadata tracked without any custom logging code.
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Summarize this ticket."}]
}'
Issue a separate key per tenant, label it in the dashboard, and usage rolls up per key automatically — no custom database schema, no rollup cron job. This is particularly useful for teams on the Team (€19/seat) or Scale (€49/seat) plan, where multiple internal teams or customer-facing apps each need their own isolated usage view without separate Anthropic billing accounts. See /pricing for plan details and /docs/quickstart to get a key issued in minutes.
Handling Streaming and Tool Use in Multi-Tenant Tracking
Two complications come up often in real deployments:
- Streaming responses don't deliver a single
usageobject until the stream closes — you need to buffer and read the finalmessage_deltaevent to get the output token count. See /docs/streaming for the event shapes if you're building this yourself. - Tool use calls (where Claude invokes a function and you return a tool result) count as part of the same conversation's token usage, but each tool round-trip adds its own input/output tokens. If you're tracking cost per tenant accurately, make sure your logging captures every turn, not just the first request. Reference /docs/tools and /docs/messages for the full request/response structure.
Both of these are handled automatically if you're using per-tenant keys through a managed layer — the usage ledger accounts for the full conversation regardless of how many turns or tool calls it took.
Bottom Line
Multi-tenant usage tracking for Claude comes down to attaching a tenant identifier to every request and capturing token counts from each response. You can build this yourself with a logging table and a rollup job, or skip the plumbing by issuing per-tenant API keys through SubToAPI, where usage, streaming, and tool calls are tracked per key out of the box. Start with a free trial at /signup if you want to see it on your own Claude usage.
Questions
Does Anthropic's API support per-customer usage tracking natively? No. A standard Anthropic API key is account-level; it doesn't separate usage by customer or tenant. You need to build a proxy layer or use a service that issues scoped keys per tenant.
What's the minimum data I need to log for accurate billing? Tenant ID, model name, input tokens, output tokens, and timestamp for every request. Model and token counts matter because Claude's pricing differs by model and by input vs. output token.
How do I track usage across streaming and multi-turn tool calls? Read the token usage from the final event of a stream (not the first chunk), and log every turn in a tool-use conversation, not just the initial request, since each round-trip adds tokens.