[FEATURE] /api/oauth/usage returns null spend/extra_usage for Enterprise orgs with per-member monthly spend limits — no parity with claude.ai Usage UI (follow-up to #34348)
Preflight Checklist
- [x] I have searched existing requests — this is a follow-up to #34348, which was closed (and is now locked) after the author found their org's spend under
extra_usage. That fix does not apply to the Enterprise billing configuration described below. - [x] This is a single feature request (not multiple features)
Problem Statement
#34348 asked to expose Enterprise spending-limit data via /api/oauth/usage and was closed because the endpoint "already returns" it under extra_usage. That is true for some Enterprise configurations, but not for orgs where members have a per-member monthly spend limit (usage-based billing). For those seats every dollar-bearing field the endpoint has is null:
// GET https://api.anthropic.com/api/oauth/usage — Enterprise seat, usage-based org
{
"five_hour": { "utilization": 100.0, "limit_dollars": null, "used_dollars": null, "remaining_dollars": null },
"seven_day": { "utilization": 56.0, "limit_dollars": null, "used_dollars": null, "remaining_dollars": null },
"extra_usage": {
"is_enabled": false, "monthly_limit": null, "used_credits": null,
"utilization": null, "credits_ever_enabled": false
},
"spend": { "used": { "amount_minor": 0, "currency": "USD", "exponent": 2 }, "limit": null, "enabled": false },
"member_dashboard_available": false
}
Meanwhile the claude.ai web UI (Settings → Usage) shows the member exactly what you'd want in a statusline: "$57.32 of $1,500.00 spent · Spend limit · Resets Sep 1". The web app reads it from an internal endpoint that has no OAuth-accessible equivalent:
// GET https://claude.ai/api/organizations/{org_uuid}/overage_spend_limit?account_uuid={account_uuid}
// (browser session cookie only)
{
"limit_type": "member",
"is_enabled": true,
"monthly_credit_limit": 150000, // cents → $1,500.00
"used_credits": 6123, // cents → $61.23
"period": "monthly",
"currency": "USD",
"used_credits_basis": "post_discount"
}
So the per-member spend data exists and is member-visible in the UI, but there is no sanctioned way for Claude Code (or any tool holding the Claude Code OAuth token) to read it:
/api/oauth/usage— nulls, as shown above.- The statusline stdin JSON — has
cost.total_cost_usd(session estimate) andrate_limitspercentages, but nothing about the monthly spend limit. - Enterprise Analytics API (
/v1/organizations/analytics/user_cost_report) — requires the org Primary Owner to mint aread:analyticskey (regular members cannot self-serve), and has a documented 4–24 h data lag, so it can't match the real-time number the UI shows anyway.
Current workaround (and why it's bad)
The only way to get the UI number into a statusline today is to borrow the browser session:
# statusline fragment — fetch the same number the claude.ai Usage page shows
from curl_cffi import requests as cffi # plain curl/urllib is blocked by Cloudflare (JA3 check)
sk = subprocess.run( # claude.ai sessionKey, manually copied from the
['security', 'find-generic-password', # browser into the macOS Keychain
'-s', 'claude-web-session', '-w'],
capture_output=True, text=True).stdout.strip()
r = cffi.get(
'https://claude.ai/api/organizations/%s/overage_spend_limit?account_uuid=%s' % (ORG, ACC),
impersonate='chrome', # TLS-fingerprint impersonation to pass Cloudflare
cookies={'sessionKey': sk}, timeout=5)
spent = r.json()['used_credits'] / 100 # → "⚡$61.23/$1500" in the statusline
This works, but every part of it is wrong:
- the user must manually extract a full-privilege browser session cookie and store it locally, just to read one number they are already allowed to see;
- it silently breaks whenever the claude.ai session rotates (re-login), freezing the displayed value;
- it needs TLS-fingerprint impersonation (
curl_cffi) because Cloudflare blocks honest HTTP clients — clearly not an intended integration path and fragile against any bot-protection change; - the org/account UUIDs must be scraped from browser DevTools, because the Claude Code OAuth identity uses a different ID namespace.
Proposed Solution
Give Claude Code parity with the claude.ai Usage page for all Enterprise billing flavors:
- Populate the fields that already exist in the
/api/oauth/usageschema for usage-based Enterprise members — any of these would work:
extra_usage(the field that solved #34348 for the other billing configuration), or- the
spendobject, or - the per-window
used_dollars/limit_dollarsfields.
``json``
"spend": {
"used": { "amount_minor": 6123, "currency": "USD", "exponent": 2 },
"limit": { "amount_minor": 150000, "currency": "USD", "exponent": 2 },
"percent": 4, "enabled": true, "resets_at": "2026-09-01T00:00:00Z"
}
- Ideally, also surface the same numbers in the statusline stdin JSON (next to
rate_limits), so statusline scripts don't have to call any endpoint at all — subscription users already get their limits pushed this way, Enterprise members get nothing.
The data is already computed per member and already shown to the member in the web UI; this is only about exposing it through the surfaces Claude Code can reach.