A Claude plan pricing tracker is a three-endpoint join, not a token counter

Most tools that call themselves Claude trackers read one thing: a rolling-window number. That tells you how full your 5-hour or weekly bucket is. It does not tell you which plan you are on, when the next charge fires, what card is on file, how much of your overage cap you have already burned, or whether your org just hit out-of-credits. Pricing context lives in two other claude.ai endpoints, and the only way to watch it live is to poll all three on the same tick.

M
Matthew Diakonov
11 min read

What “tracker” usually means, and the gap

Open the browser tab that does what most popular trackers do and you find a single bar: 62 percent of a 5-hour window, or some estimated weekly value computed from local Claude Code token logs. Useful, but it is missing the entire pricing half. If your org is on Claude Max at $200 a month with metered billing enabled, the things you actually want to watch are: the rolling-window utilization, the dollar amount you have spilled into extra usage this cycle, the cap you set on extra usage so you do not get surprise-billed, and the renewal date so you can compare last month to this month. That information lives across three separate undocumented endpoints behind your claude.ai cookie. They look stable, they have not been documented anywhere, and the only way to assemble them is to call all three and stitch the JSON yourself.

Endpoint zero: enumerate the orgs

Before any of the three real endpoints are reachable, you need an org_uuid for the URL path. That comes from /api/account. The response carries your email and a list of memberships. Most Pro users have one. Anyone in a team has at least two. Each membership produces an independent snapshot.

claude.ai/api/account

The shape is small but load-bearing. ClaudeMeter iterates every membership and treats each org as its own row in the dropdown. Tier and overage cap differ per org, which is why averaging them would lie.

Endpoint one: the rolling-window utilization

This is the endpoint everyone already knows about. /api/organizations/{org_uuid}/usage returns the bars you see on claude.ai/settings/usage. What is less well known: it returns more than one window. On Claude Pro and Max you get five_hour, seven_day, plus per-model breakdowns (seven_day_sonnet, seven_day_opus), and an extra_usage block that mirrors part of the overage endpoint.

claude.ai/api/organizations/{org_uuid}/usage

The schema is fixed in src/models.rs as the UsageResponse struct, lines 18-28. If a field is renamed upstream, the serde deserializer fails fast and the menu bar surfaces a parse error rather than a silently wrong number.

Endpoint two: overage spend limit

The endpoint that turns a usage tracker into a pricing tracker. /api/organizations/{org_uuid}/overage_spend_limit returns the metered-billing posture for the org: the cap you set, how many dollars of extra usage you have already consumed this cycle, whether you are out of credits, and whether an admin has paused the spend.

claude.ai/api/organizations/{org_uuid}/overage_spend_limit

Three fields here that exist nowhere else. disabled_reason tells you why an admin paused metered spend (for example, billing failed). disabled_until tells you the timestamp the pause auto-clears. out_of_credits flips to true the moment your used_credits equals monthly_credit_limit, which is the live signal that further prompts will start to fail rather than spill. You will not see any of these in a token-counting tracker, because they are pricing-state flags, not usage measurements.

Endpoint three: subscription details

The other half of the pricing picture. /api/organizations/{org_uuid}/subscription_details returns your tier and renewal posture: status (active, past_due, canceled), next_charge_date, billing_interval, and payment_method (brand, country, last4, type).

claude.ai/api/organizations/{org_uuid}/subscription_details

A small but useful detail: billing_interval decides which plan dollar amount to show next to your tier in the dropdown. monthly + Pro means $20 (or local currency); monthly + Max means $100 or $200 depending on the tier you picked; annual flips both to a different yearly line. Without that field, a tracker has to guess. With it, the dropdown shows a per-org renewal preview that lines up with what the billing email is going to look like.

The actual join

One alarm, one loop, four awaits per org. Below is the exact shape of fetchSnapshots from the open-source extension. Note the try/catch around overage and subscription: those endpoints can 404 on free orgs without breaking the tick.

claude-meter/extension/background.js

The loop is sequential rather than parallel by design. claude.ai applies Cloudflare-style request shaping; firing three calls back to back at minute boundaries looks identical to what a real settings-page reload does. Polling all three in parallel is faster but trips bot heuristics more often.

How the four sources collapse into one menu-bar snapshot

Three pricing-aware endpoints feed one fetchSnapshots call. The output goes three places: badge, dropdown, CLI.

Three endpoints, one tick, three surfaces

/api/organizations/{org}/usage
/api/organizations/{org}/overage_spend_limit
/api/organizations/{org}/subscription_details
fetchSnapshots()
Menu bar badge
Dropdown rows
claude-meter --json

Step by step: what one tick produces

1

Enumerate orgs

GET /api/account returns email_address plus a memberships array. The extension iterates every membership and treats each org_uuid as its own snapshot target. This is the loop body in extension/background.js lines 19-43.

2

Fetch usage

GET /api/organizations/{org}/usage returns the rolling-window object: five_hour, seven_day, seven_day_sonnet, seven_day_opus, seven_day_oauth_apps, plus an extra_usage block. If this fails, the snapshot is dropped (continue at line 31), because there is nothing to display without window data.

3

Fetch overage

GET /api/organizations/{org}/overage_spend_limit returns the metered-billing posture: monthly_credit_limit, used_credits, out_of_credits, disabled_reason. Wrapped in try/catch because free orgs and Workspaces without metered billing 404 here.

4

Fetch subscription

GET /api/organizations/{org}/subscription_details returns status, next_charge_date, billing_interval, currency, and payment_method (brand, country, last4, type). Same try/catch wrapper. This is the only endpoint that exposes pricing context.

5

Stitch and POST

All four responses (account email, usage, overage, subscription) collapse into one snapshot object keyed by org_uuid, stamped with fetched_at. POSTed to http://127.0.0.1:63762/snapshots so the menu-bar app reads from the bridge instead of double-fetching.

6

Render in the menu bar

The badge shows the worst utilization across five_hour and seven_day. The dropdown lists per-org tier, next charge date, last4, overage cap and overage burn. Numbers across all four sections were read in the same 60-second tick, so the user sees a consistent pricing snapshot.

What only a three-endpoint tracker shows

Token counters cover one column on the right. Pricing-aware fields all live in the left column.

FeatureLocal token counter (JSONL only)ClaudeMeter (server, three-endpoint join)
Tier (Pro vs Max)not exposedsubscription_details.status + billing_interval
Next charge datenot exposedsubscription_details.next_charge_date
Card on file (brand + last4)not exposedsubscription_details.payment_method
Overage cap (in dollars)not exposedoverage_spend_limit.monthly_credit_limit
Overage spend so farnot exposedoverage_spend_limit.used_credits
Out-of-credits flagnot exposedoverage_spend_limit.out_of_credits
Rolling 5-hour utilizationestimated from JSONL token sumsusage.five_hour.utilization
Weekly Opus quotarolled into one bar, if shownusage.seven_day_opus.utilization
Refresh cadencetail of ~/.claude/projects/**/*.jsonl writes60s, all three endpoints together
Per-org breakdownsingle global counterone snapshot per membership

Numbers that come out of the join

All four are read from the live response, not estimated.

0endpoints joined per tick
0scadence across all three
0rolling-window fields per usage call
0tokens summed locally

What this lets you do that a usage-only tracker cannot

Three concrete examples. First, when five_hour.utilization crosses 100, you can read overage_spend_limit.is_enabled on the same tick to know whether the next prompt will spill into metered billing or 429. Second, when watching a long Claude Code agent loop you can pair used_credits deltas with rolling-window deltas to derive a real dollars-per-prompt rate, not a token-derived guess. Third, on the day next_charge_date fires you can compare this cycle's overage burn against last cycle's before the actual charge lands, because the renewal timestamp is in the same payload as the spend. None of those are possible with one endpoint.

The honest caveat

All three endpoints are internal and undocumented. The field names in this guide map to the Rust structs at src/models.rs (UsageResponse, OverageResponse, SubscriptionResponse) and have been stable for many months, but Anthropic can rename or restructure any of them in any release. ClaudeMeter deserializes strictly: a missing field surfaces as a parse error, not as a wrong number, so you find out immediately rather than days later when the dropdown is silently lying. The README documents the risk and the menu bar shows a ! state when any one of the three breaks.

Need a tracker that joins all three?

If you are running Claude Pro or Max with metered billing on, 15 minutes is enough to wire up the three-endpoint join in your own tooling or to swap in ClaudeMeter and skip the integration.

Frequently asked questions

Why does a real plan pricing tracker need three endpoints, not one?

Because each endpoint answers a different question. /api/organizations/{org}/usage answers 'how full are my rolling windows right now', and that is what every other tracker focuses on. /api/organizations/{org}/overage_spend_limit answers 'what is my pay-as-you-go cap and how much of it have I burned this month'. /api/organizations/{org}/subscription_details answers 'what tier am I on, when does it renew, and which card is going to get charged'. A bar that shows 62 percent utilization without showing tier, renewal date, and overage spend is not a pricing tracker, it is a usage tracker.

Where exactly is the join code?

claude-meter/extension/background.js, function fetchSnapshots, lines 14-44. The function calls /api/account first to enumerate memberships, then for each org_uuid it fetches /usage, /overage_spend_limit, and /subscription_details in sequence with credentials: 'include'. The four results are stitched into a single snapshot object and POSTed to the menu-bar app at http://127.0.0.1:63762/snapshots. The Rust side has the same join in src/api.rs, function fetch_usage_snapshot, lines 10-75, which deserializes each response into UsageResponse, OverageResponse, SubscriptionResponse from src/models.rs.

What is in subscription_details that no token counter can ever see?

Four fields that determine your actual pricing posture: status (active, past_due, canceled), next_charge_date (ISO date the next plan charge fires), billing_interval (monthly or annual, which changes the dollar amount), and payment_method (brand, country, last4, type). None of those live on disk. None of those are derivable from JSONL logs. They are returned by an internal endpoint behind your claude.ai cookie, and ClaudeMeter is the only menu-bar tool that surfaces them.

What is the difference between extra_usage in the usage payload and the overage_spend_limit endpoint?

They overlap but are not identical. usage.extra_usage carries is_enabled, monthly_limit, used_credits, utilization, and currency, scoped to the rolling-window response. overage_spend_limit carries is_enabled, monthly_credit_limit, currency, used_credits, plus disabled_reason, disabled_until, and out_of_credits, which the usage payload does not include. ClaudeMeter prefers overage_spend_limit when present because out_of_credits and disabled_reason are how you find out the cap was hit (or the org admin paused metered billing) without waiting for a 429.

How is the cadence kept in sync across the three endpoints?

One alarm. chrome.alarms.create('refresh', { periodInMinutes: 1 }) at extension/background.js line 105. Every 60 seconds the same fetchSnapshots run hits all three endpoints, top to bottom, per org. There is no separate timer for the subscription endpoint or the overage endpoint, so the rolling-window number, the overage spend, and the renewal date in the menu bar were all read at the same moment. That matters when you are watching utilization tick toward 100 percent and trying to decide whether to let it spill into metered billing.

What if subscription_details or overage_spend_limit returns 404?

Both calls are wrapped in try/catch and fail soft. extension/background.js line 27 swallows overage failures with a comment that overage may not exist for all orgs. Line 29 does the same for subscription_details. The snapshot still pushes if usage is non-null. The menu bar then renders the fields it does have and leaves the missing rows blank, so a free workspace org or a team without metered billing does not break the tracker. Anthropic enabling metered billing on April 16, 2026 made overage_spend_limit start appearing for every Pro and Max account, but free orgs still 404.

Why does the join enumerate memberships from /api/account first?

Because /api/organizations/{org}/usage requires an org_uuid in the path, and most accounts belong to more than one org (your personal Pro org, plus any team you have been invited to). /api/account returns the email plus a memberships array; ClaudeMeter loops over every membership and produces one snapshot per org. The menu-bar dropdown then shows tier and overage spend per org rather than averaging them, which is the only honest way to display data when one org has metered billing enabled and the other does not.

Can I run the same join myself without installing ClaudeMeter?

Yes. Open DevTools on claude.ai/settings/usage, copy your full Cookie header, then run three curls: one to /api/organizations/{org}/usage, one to /api/organizations/{org}/overage_spend_limit, one to /api/organizations/{org}/subscription_details, all with -H "Cookie: $YOUR_COOKIE" -H "Referer: https://claude.ai/settings/usage". You get the same JSON the extension does. Pipe through jq and you have a one-shot tracker. ClaudeMeter automates the cookie wrangling, the org enumeration, the 60-second cadence, and the merging into one menu-bar surface, but the data path is the same.