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.
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.
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.
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.
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).
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.
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
Step by step: what one tick produces
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.
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.
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.
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.
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.
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.
| Feature | Local token counter (JSONL only) | ClaudeMeter (server, three-endpoint join) |
|---|---|---|
| Tier (Pro vs Max) | not exposed | subscription_details.status + billing_interval |
| Next charge date | not exposed | subscription_details.next_charge_date |
| Card on file (brand + last4) | not exposed | subscription_details.payment_method |
| Overage cap (in dollars) | not exposed | overage_spend_limit.monthly_credit_limit |
| Overage spend so far | not exposed | overage_spend_limit.used_credits |
| Out-of-credits flag | not exposed | overage_spend_limit.out_of_credits |
| Rolling 5-hour utilization | estimated from JSONL token sums | usage.five_hour.utilization |
| Weekly Opus quota | rolled into one bar, if shown | usage.seven_day_opus.utilization |
| Refresh cadence | tail of ~/.claude/projects/**/*.jsonl writes | 60s, all three endpoints together |
| Per-org breakdown | single global counter | one snapshot per membership |
Numbers that come out of the join
All four are read from the live response, not estimated.
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.
Related guides
ccusage says 5 percent, claude.ai says rate limited
Why local token counters and the server quota disagree, and the exact field the rate limiter actually checks.
Verifying a Claude tracker actually reads server truth
The three-step protocol: DevTools intercept, localhost bridge curl, staleness flip. Verifies the data path in under a minute.
Rolling 5-hour burn rate is Δu/Δt, not tokens per minute
Why a quota burn rate cannot be derived from local logs, and the small math that turns two snapshots into a 429 ETA.