Usage, cost and model spend

Per-org usage metering plus model-spend metering: what the agents an org runs (Claude Code, Codex, Grok and Muse lanes, QA Commander) spent on model calls. It is on by default (platform setting usage.metering, the kill switch for every route and tool below). Metering only: nothing is charged, nothing is blocked, and no billing flag or payment provider is involved.

What you can do

NeedRESTMCP tool
This month's usage and cost, every source, and the advisory budget stateGET /v1/orgs/{orgId}/usage?period=YYYY-MMusage_get
Set or lower the advisory monthly budgetPUT /v1/orgs/{orgId}/usage/budgetnone (a person loosens a budget)
Record what agents spent on model callsPOST /v1/orgs/{orgId}/usage/model-eventsusage_model_record
Read model spend grouped by model, engine, agent, lane or dayGET /v1/orgs/{orgId}/usage/models?period=&groupBy=usage_model_summary

The usage page (Settings > Usage and cost) shows the same numbers: its Agent models row and the by-model table are this ledger, and the month's total includes it, so the budget warning sees it.

Recording model spend

POST /v1/orgs/{orgId}/usage/model-events takes { "events": [ ... ] }, 1 to 500 events per call:

{ "events": [ {
  "externalRef": "claude:3f2a:msg_01AbC",
  "provider": "anthropic",
  "model": "claude-opus-5-5",
  "engine": "claude-code",
  "effort": "high",
  "inputTokens": 1200,
  "outputTokens": 340,
  "cacheTokens": 5000,
  "costMicroUsd": 21500,
  "agentLabel": "Claude orchestrator",
  "laneSlug": "gq-usage-model-spend-ingest",
  "occurredAt": "2026-10-06T21:04:11Z"
} ] }
  • externalRef is your idempotency key: a provider message id or a transcript line id. Use a value that is unique across everything you send (a provider message id, a UUID). A replay by the same org (the same ref again, in a later call or twice inside one call) comes back recorded: false and changes nothing, so a retry is always safe. The first record wins even if the replay carries different numbers. Replays may race: batches are applied one at a time per org.
  • costMicroUsd is an integer in micro-USD (1 USD = 1,000,000) and you price the call. GoodQA never guesses a price; a subscription-billed agent ships its notional cost. It is required: a silent zero is the problem this ledger exists to end.
  • provider, model, engine and effort are stored lower-case. occurredAt defaults to now; it may not be before 2020-01-01 or more than a day ahead.
  • The call is atomic: one bad event (400) rejects the whole batch, so nothing is half-written.
  • Response: { org, recorded, duplicates, events: [{ externalRef, recorded }] } in request order.

A ref another org already recorded is refused with 409 usage_model_ref_other_org and nothing in the batch is written, the same rule as the build-farm ledger: the ref is one global key. So a scheme two orgs could both produce (line-1) collides by design; prefix such refs with something unique to your org. The cost of the rule is that an org with a write key could pre-claim refs another org is about to use, and learns only that a ref exists; provider message ids are unguessable, so this is a denial-of-metering concern and nothing is charged or exposed.

Each month is capped per org: a batch that would take the org's summed cost, or any summed token count, for a UTC month above 1,000,000,000,000,000 is refused whole with 422 usage_model_month_ceiling, so a served total is always an exact integer.

Who may record

CredentialMay record?
Org admin, signed inyes
User token (write ability) whose owner is an org adminyes (stored as user_token)
Org API key holding write and the explicit-only usage:write familyyes (stored as api_key)
Org API key without usage:write (including the default read+write key and a key narrowed to usage or issues)no, 403
Read-only key, user-scoped key, key capped below adminno, 403
Persona keyno, persona_key_forbidden (a persona's own model calls are already metered by GoodQA)
Runner keyno, runner_key_forbidden (and a runner key cannot name usage:write at mint)
Org member who is not an admin, or someone outside the org403, 404

usage:write is its own key family so an ingest-only key can hold usage:write without usage and never read the cost figures back; a key that names no family does not reach it. Add it when you mint the key: scopes: ["write", "usage:write"].

Reading it back

GET /v1/orgs/{orgId}/usage/models?period=2026-09&groupBy=model (org admin; key family usage):

{ "org": { "id": "..." }, "period": "2026-09", "groupBy": "model", "truncated": false,
  "totals": { "events": 6, "inputTokens": 7300, "outputTokens": 1380, "cacheTokens": 5260, "totalTokens": 13940, "costMicroUsd": 307000 },
  "groups": [ { "key": "claude-opus-5-5", "providers": ["anthropic"], "events": 3, "inputTokens": 3100, "outputTokens": 610,
                "cacheTokens": 5010, "totalTokens": 8720, "costMicroUsd": 243000 } ] }

groupBy is model (default), engine, agent, lane or day. A calendar month is [first of the month, first of the next) in UTC. day reads oldest first; the others read biggest spend first. A null key is an event with no label. At most 1000 groups are returned (truncated: true when more exist); totals always covers every event.

GET /usage gains a models object (the same totals) and totalCostMicroUsd includes it, so the advisory budget (budget.state: none, ok, warning, over) reflects it. The budget only warns: a write is never refused because the budget is over.

Switching it off

Turn usage.metering off (platform setting, default on): every route above answers an unknown route's 404 before authentication, the MCP tools are not registered, and the served OpenAPI leaves the four paths out.

Not done here

No charging, invoicing or Stripe. No price table: callers price their own calls. No retention job yet (the ledger is one small row per call). A shipper that reads agent transcripts and calls this API is a separate piece of work.

Reference

  • API reference: tag orgs (/orgs/{orgId}/usage, /orgs/{orgId}/usage/budget, /orgs/{orgId}/usage/models, /orgs/{orgId}/usage/model-events) in /v1/openapi.json.
  • MCP tools: usage_get, usage_model_summary, usage_model_record; every key lists them and the route decides. See the MCP tool reference.
  • Proof script: apps/api/scripts/usage-model-loopback.mjs posts 1,000 synthetic events in batches, replays one batch (it must be a no-op) and checks the summary against what it sent.

Model spend dashboard

Settings > Usage and cost adds a Model spend section for org admins. The month picker applies to the section and uses UTC calendar months. Cost is rounded once to cents with integer arithmetic; tokens include input, output and cache tokens. Choose model, engine, agent, lane or day and activate a column heading to sort the returned groups. When the API caps a grouping at 1,000 groups, the page labels that limit and keeps the API's complete total.

The daily chart stacks costs by engine. groupBy=day additionally returns engines: [{ key, costMicroUsd }] on each day, derived in the same SQL statement as the day total. Existing summary fields and other groupings keep their contract. The chart uses the six engines with the largest monthly cost and combines the remainder as Other engines; zero-spend days remain visible. The expandable Daily spend data table supplies the same exact values to keyboard and screen reader users. A server with the older daily response shows a single All engines series.

The warning banner uses the server's advisory budget state across all priced sources, and never blocks model calls. An empty month links to these ingest instructions. The existing default-on usage.metering setting gates the entire usage API and dashboard; this view adds no separate switch.

We use essential cookies to keep you signed in. See our Privacy Policy for details.