Usage

What a run costs, and where to read it. Every ceiling, with its number, is on Limits.

Where usage shows up

Four places — and the first three are not all the same number. The difference is delegation, and it decides which one you may bill from:

  • On the stream — a usage event carrying the coordinator's own turn. It is a final aggregate for that turn, not a running total, and it does not include what a delegated specialist spent.
  • On the awaited result — usage on the response of /runs/await, carried over from that same event, so it is coordinator-only too, and it is the last such frame rather than a sum of them.
  • On the run — usage on GET /v1/runs/{runId}, summed from the metering records, which carry one row per agent. This is the whole run, delegation included, and it is the one your plan is charged against.
  • In the Console — aggregated per month, per agent and per end user, under Console → Usage. There is no /v1 endpoint for aggregates today.
text/event-stream
event: usage
data: {"inputTokens":1841,"outputTokens":612,"totalTokens":2453}

If you re-bill your own customers, read the run, not the stream. An agent that delegates spends tokens under the specialist's name; those land in the metering records and in GET /v1/runs/{runId}, and they are what your monthly allowance is measured against — but they never reach the usage event or the awaited result. Bill from the stream and you will under-bill exactly the runs that cost the most.

The monthly limits

Two plan limits are checked before a run starts — and before a retry, which is a new model call. Both are counted per UTC calendar month, and neither counts usage on your own provider key:

  • A spending budget, amy.cost.month, in money: what Amy has spent on your organisation's runs this month, against an amount your plan carries in minor units (cents) of the plan's currency.
  • A token allowance, amy.tokens.month, in tokens whatever they cost.

Over either, the start call is refused. The spending budget is judged first, so a start that has spent both reports the spending budget:

403 application/problem+json
{
  "type": "/errors/entitlement-required",
  "title": "Plan entitlement required.",
  "status": 403,
  "detail": "amy.tokens.month",
  "reason": "limit_reached",
  "limit": 100000,
  "remaining": 0
}

403, not 402: it is the same entitlement refusal every plan-gated capability uses — title is always Plan entitlement required. and detail names the capability that refused. reason says why: limit_reached means the limit is spent; subscription_state or not_in_plan mean the plan does not allow the run at all, whatever you have used, and unknown_capability means the plan does not define the limit. Branch on reason, then on detail. For limit_reached, limit and remaining are token counts when detail is amy.tokens.month, and money in minor units when it is amy.cost.month — then the body also names the currency. Plans and prices are in ZAR.

When a limit bites depends on how the run was started. A streamed or awaited start is refused up front, as above. A submitted run is checked again when the run starts, and a run waiting on background tasks is checked again when it wakes; either ends failed with quota_exceeded, cost_budget_exhausted or plan_inactive (see Errors). The token allowance does not stop a run that is already under way, even if it takes the month past the allowance; the next start is refused. The spending budget does: a run that reaches it stops before its next model call with status: "budget_exceeded" and errorCode: "cost_budget_exhausted", keeping what it had produced.

The rate limit

Separately from the plan, every call counts against a request rate. By default that is 300 requests a minute for your API client — all the keys of that client share the one count — and a stricter count for calls with no valid key. Over it, the answer is 429 with a Retry-After header in seconds; wait that long, then send the same request again. The header is authoritative: the figure can change. A cancel, a poll of a run and a conversation read all count, so poll on an interval rather than in a tight loop.

Caps inside a run

Some tool families — web search, image analysis — carry a per-run call cap, so a single run cannot spend without bound. Hitting one is not a failure: the run continues with that capability switched off and emits one tool_cap frame naming the family. Surface it as a note, not an error, and expect the answer to be thinner rather than absent.

Separately, a run that would exceed its own per-run token budget stops gracefully and reports status: "budget_exceeded" on run_completed — a policy stop with whatever answer it had, which is why you read status rather than assuming a terminal frame means success.