[FEATURE] Add per-request billing classification (subscription vs extra usage) to OTel api_request events
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
For claude.ai subscribers, cost_usd on claude_code.api_request and the claude_code.cost.usage metric are list-price estimates. OTel consumers cannot tell whether a request was covered by the plan or billed as extra usage, so dashboards cannot separate real extra spend from usage the subscription already absorbed.
Today the only way to classify requests is to route Claude Code through a gateway such as LiteLLM via ANTHROPIC_BASE_URL and read the anthropic-ratelimit-unified-* response headers there. That does not cover sessions that run on Anthropic's infrastructure, such as Claude Code cloud sessions and Claude Tag. They never pass through a customer-run gateway, so their spend cannot be classified at all.
Claude Code already has this information. It reads anthropic-ratelimit-unified-status and anthropic-ratelimit-unified-overage-status on each response and tracks overage state internally (shown in /usage), but none of it reaches OTel. I checked this in v2.1.283.
Inferring the class from auth method does not work. OAuth sessions can be billed as extra usage, and a misrouted session can land on API billing (#68501, #36769).
Proposed Solution
Add an attribute to claude_code.api_request events, derived from the same response's headers. For example:
billing.type = "subscription"when unified status isallowedorallowed_warningbilling.type = "extra_usage"when unified status isrejectedand overage status isallowedorallowed_warning- omitted when the headers are absent (API key, Bedrock, Vertex, Foundry) or inconsistent
Adding the same attribute to claude_code.cost.usage and claude_code.token.usage would also help.
Alternative Solutions
- #16942 asked for utilization gauges. It was closed, and a gauge cannot classify individual requests anyway.
- A gateway can read the headers for local sessions only, as described above.
- Exposing
extra_usagein the statusLine payload (#82656) does not reach OTel pipelines.
Priority
Medium - Would be very helpful
Feature Category
Other
Use Case Example
- Our organization is on a plan with extra usage enabled and exports Claude Code OTel to our own backend.
- Members use Claude Code locally, in cloud sessions, and through Claude Tag.
- A member hits the 5-hour limit and keeps working on extra usage. Their
api_requestevents look the same before and after the switch. - With
billing.type, we could sumcost_usdwherebilling.type = "extra_usage"per user and alert on it, across every surface and without running a gateway.
Additional Context
- Verified against the v2.1.283 binary. The unified rate-limit headers are parsed and overage state is held in memory, but the OTel event emitter and the standard attributes carry neither.
- Related: #16942 (utilization gauges, closed), #82656 and #69791 (rate limits and
extra_usagein the statusLine payload).