Usage API

A read-only, cached JSON API that reports current usage across every account in your pool, Claude and Codex, plus your combined estimated AI spend.

If you pool multiple accounts, Hep.gg can expose their live usage as a single read-only JSON endpoint. Both pools are included: your Claude accounts and your Codex accounts. It's meant to be the source of truth for your own dashboards: it polls Anthropic on a safe schedule, caches the result, and serves from that cache, so your tools can poll it as often as they like without ever hitting Anthropic directly (and without burning your per-account rate limits).

Get a usage token

ccas usage-token        # show (creates one if you don't have it)
ccas usage-token new    # rotate (invalidates the old one)

You can also reveal/rotate it from the AI → Accounts page in the dashboard. Give consumers the token as a bearer header.

Endpoint

GEThttps://ai.hep.gg/usageAuth required
Aggregated usage for every account in your pool (served from cache).
GEThttps://ai.hep.gg/usage/{id}Auth required
Usage for a single account by its stable id.

Authenticate with Authorization: Bearer <usage-token>.

GET /usage
{
  "version": 1,
  "fetched_at": "2026-05-31T18:00:00Z",
  "accounts": [
    {
      "id": "stable-unique-id",
      "label": "Work Max",
      "plan": { "rate_limit_tier": "default_claude_max_5x", "label": "Max 5x" },
      "status": "ok",
      "error": null,
      "fetched_at": "2026-05-31T17:59:40Z",
      "windows": {
        "five_hour":        { "utilization": 35.2, "resets_at": "2026-05-31T21:30:00Z", "expected": 28.0, "pace_delta": 7.2, "pace": "high" },
        "seven_day":        { "utilization": 5.0,  "resets_at": "2026-06-04T09:00:00Z", "expected": 8.0,  "pace_delta": -3.0, "pace": "under" },
        "weekly_scoped":    { "utilization": 0.0,  "resets_at": "2026-06-04T09:00:00Z", "model": "Fable", "pace": "none" }
      },
      "raw_usage": { }
    }
  ],
  "codex_accounts": [
    {
      "id": "codex:0f2b...",
      "provider": "codex",
      "label": "Personal Plus",
      "plan": { "rate_limit_tier": "plus", "label": "plus" },
      "active": true,
      "status": "ok",
      "error": null,
      "fetched_at": "2026-05-31T17:59:55Z",
      "window_list": [
        { "key": "five_hour", "label": "5-hour", "utilization": 41.0, "resetsAt": "2026-05-31T21:30:00Z", "windowMinutes": 300, "expected": 33.0, "paceDelta": 8.0, "pace": "high" },
        { "key": "seven_day", "label": "Weekly",  "utilization": 31.0, "resetsAt": "2026-06-04T09:00:00Z", "windowMinutes": 10080, "pace": "under" }
      ],
      "raw_usage": { }
    }
  ],
  "all_accounts": [ ],
  "spend": { "total_usd": 1234.56, "claude_usd": 1100.00, "codex_usd": 134.56 }
}

Both pools

  • accounts is your Claude pool, unchanged.
  • codex_accounts is your Codex pool.
  • all_accounts is the same rows as one flat list, each tagged with provider (claude or codex). Read this one if you want to render everything with a single code path.

Every account also carries a window_list: the same usage windows as a plain array, in display order, each with a key, a human label, its length in windowMinutes, and the on-pace fields below. Claude accounts keep their keyed windows object as well, so nothing that already reads it needs to change.

Prefer window_list for new code. Codex plans do not all report the same windows (most report a 5-hour and a weekly one, some report a single longer window instead), so reading the list and its labels is the only way to render whatever a plan actually has.

Codex ids are prefixed codex:. That is deliberate, it means POST /usage/accounts/{id}/activate works for either pool from the id alone.

Spend

spend reports your estimated AI spend in USD: total_usd plus the claude_usd and codex_usd split. It is an estimate priced at each provider's public API list prices, not a bill. Subscription traffic has no per-request invoice to reconcile against, so treat it as a comparable measure of what your usage would have cost on the API.

Field contract

  • id - stable per account across restarts; key your display/visibility off it. Codex ids are prefixed codex:.
  • provider - claude or codex.
  • label - human name (your slot label or the account email); optional.
  • plan.rate_limit_tier - the raw tier (e.g. default_claude_max_20x, default_claude_max_5x, default_claude_ai). plan.label is a friendly form.
  • status - one of:
    • ok - last fetch succeeded.
    • rate_limited - upstream returned 429/5xx/timeout; last good data is kept.
    • auth_error - the account needs re-auth. Re-add it with ccas account login (a dedicated authorization that won't drop again), or ccas account add to re-snapshot.
    • error - anything else.
  • error - short string when status != ok, else null.
  • fetched_at (per account) - UTC of the last successful fetch for that account. It keeps returning the last good windows while status is degraded, so an "updated N ago" stays accurate.
  • windows.* - keys: five_hour, seven_day (weekly, all models), and weekly_scoped (the per-model weekly cap, for example Fable). Each is { "utilization": 0..100, "resets_at": <ISO8601 UTC>, … }, or null if that window doesn't apply. utilization is a percentage. weekly_scoped also carries a model label; Anthropic rotates which model the weekly cap targets, so read the label rather than hardcoding it. Any new windows Anthropic adds appear under raw_usage without an API change.
  • On-pace fields (per window, added server-side): tell you whether you're burning faster or slower than a steady rate that would hit 100% exactly at reset.
    • expected - the utilization you'd be at right now if perfectly on pace (elapsed fraction of the window x 100).
    • pace_delta - utilization - expected. Positive = ahead of pace (burning fast).
    • pace - a bucket for easy coloring: none (0% used or no reset time -> render neutral/white), under (behind pace -> green), over (0-5% ahead -> yellow), high (5%+ ahead -> red). expected/pace_delta are omitted when pace is none.
  • window_list - every window as an array (see Both pools above). Same numbers as windows, in a provider-neutral shape, with resetsAt, windowMinutes, expected, paceDelta and pace.
  • raw_usage - the verbatim upstream usage object, so new windows appear without an API change.

Guarantees

  • All timestamps are ISO 8601 UTC.
  • Served from cache, a consumer request never triggers an upstream call.
  • Returns 200 with per-account status; one failing account doesn't fail the whole response.
  • ETag is supported for conditional GETs, and covers both pools.
  • POST /usage/accounts/{id}/activate switches the active account in whichever pool the id belongs to.
  • Tokens are never exposed in any response.