[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)

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 6, 2026

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) and rate_limits percentages, but nothing about the monthly spend limit.
  • Enterprise Analytics API (/v1/organizations/analytics/user_cost_report) — requires the org Primary Owner to mint a read:analytics key (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:

  1. Populate the fields that already exist in the /api/oauth/usage schema for usage-based Enterprise members — any of these would work:
  • extra_usage (the field that solved #34348 for the other billing configuration), or
  • the spend object, or
  • the per-window used_dollars / limit_dollars fields.

``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"
}
``

  1. 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.

View original on GitHub ↗