Credits and billing
Status:
betaCategory:referenceAdded:2026-06-22Last reviewed:2026-06-22
Summary
The API is metered in credits. Your account holds a prepaid credit
balance, and every successful call spends a fixed number of credits for
the route it hit. You see the cost of each call in the response headers,
and when your balance — or a budget you set — runs out, the next call is
refused with 402 PaymentRequired instead of doing any work.
Only requests that succeed are billed. A request that fails validation, authentication, or a rate-limit check costs nothing.
How billing works
- Credits are prepaid. Your balance is funded ahead of use and drawn down as you call the API. Manage the balance from the developer portal.
- Most routes have a fixed credit cost. A given endpoint costs the same whole number of credits on every successful call, independent of payload size. Heavier endpoints (composite analytics, AI-backed clinical surfaces) cost more credits than light lookups. A small number of routes are variable-cost — their charge scales with the size of the call (see Variable-cost endpoints).
- A unit price converts credits to dollars. One global dollars-per-credit rate turns the credit cost of a call into its dollar cost. Both the unit price and the per-call dollar cost are returned in the response headers.
- Only successful calls are billed. A response in the
2xx–3xxrange is billable; any4xxor5xxis not. This is the opposite of rate limits, where every request counts against your window regardless of outcome (see rate-limits.md).
What a call costs
The credit cost is fixed per route for most endpoints (and variable for a
few — see Variable-cost endpoints), and the exact
amount a call spent is returned to you on the response itself in
X-Credits-Used (credits) and X-Credits-Cost-USD (dollars). The developer
portal also shows your per-route usage and spend.
There is no static price list to memorize or hard-code — read the cost from the headers of a real call, or from the portal. Treat the headers as the source of truth for what you were charged.
Budgets
Beyond your funded balance, you can cap spend from the portal at two levels, the same way you cap rate limits:
| Level | Applies to |
|---|---|
| Account-wide cap | An optional ceiling across every key on your account. |
| Per-key allocation | A budget carved out for a single key. A key with no allocation draws from the unallocated balance. |
Budgets are entered in dollars in the portal and enforced in credits. A
call is checked against your balance and against every budget that
applies to it; the tightest one wins. When any of them is exhausted,
the call is refused with 402 (see below) — even if the others still
have room.
Credit headers
Every billable response carries the X-Credits-* set, the billing
sibling of the X-RateLimit-* headers:
| Header | Meaning |
|---|---|
X-Billable | true if this response was billed, false if not (any 4xx/5xx). |
X-Credits-Used | Credits this call spent. 0 when not billable. |
X-Credits-Cost-USD | Dollar cost of this call (credits × unit price). |
X-Credit-Unit-USD | Current dollars-per-credit unit price. |
X-Credits-Remaining | Projected balance after this call. Appears when your balance is known. |
A successful call looks like this (header values are illustrative):
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Billable: true
X-Credits-Used: 41
X-Credit-Unit-USD: 0.0025
X-Credits-Cost-USD: 0.1025
X-Credits-Remaining: 99950
X-Credits-Remaining is a projection — your balance as read at the
start of the call, minus this call's cost. It is meant for a quick "how
much is left" read, not exact accounting: concurrent calls and the
moment a charge settles mean it can lag slightly. For an authoritative
balance, read the portal. The header is omitted when the balance could
not be read; the response still succeeds.
On a non-billable response, X-Billable is false, X-Credits-Used
and X-Credits-Cost-USD are 0, and no balance is projected.
When you run out — 402 PaymentRequired
When a call cannot be funded, it is refused with 402 before the
endpoint does any work, so an unfunded call never partially executes.
The body is the standard error envelope (see errors.md):
{
"timestamp": "2026-06-22T19:04:20.118Z",
"error": "PaymentRequired",
"message": "Insufficient credits",
"request_id": "ce9ea793-1759-4cad-ab1b-fbc11475df3a"
}
The message tells you which limit you hit:
message | Condition |
|---|---|
Insufficient credits | Your account balance is depleted. |
Key credit allocation exhausted | The calling key's per-key allocation is used up, even though the account balance is not. |
Account credit allocation exhausted | Your account-wide cap is reached. |
Branch on the error code (PaymentRequired), not the message text.
A 402 is not retriable — retrying the same call without changing
your funding gets the same 402. Resolve it by funding the balance or
raising the relevant budget in the portal, then retry. Because a 402
is a failed response, it is not billed.
Variable-cost endpoints
Most routes are fixed-cost: the same whole number of credits every call. A small number are variable-cost — their charge scales with the size of the call rather than being a flat per-route number.
POST /api/ask/run is the variable-cost route today. Because
it sends your free-text prompt to a model and returns the model's answer, a
short prompt with a short answer costs less than a long one. Its charge is:
in = input_tokens (or prompt bytes when usage is null — UTF-8 byte length)
out = output_tokens (or output bytes when usage is null)
credits = max(1, ceil(in × input_cost_factor + out × output_cost_factor))
The ?model= you pick sets two per-model prices — input_cost_factor and
output_cost_factor (credits per input/output unit) — so two models can price
the same prompt differently, and a model can weight the tokens it writes
differently from the ones it reads. The current factors for each model are shown
on the developer portal's pricing page. As with every call, the exact credits
charged come back in X-Credits-Used — read that rather than predicting the
cost yourself.
The same rules above still apply: a variable-cost call is only billed when it succeeds, it is checked against your balance and budgets before it runs, and a floor of one credit means no successful call is ever free.
What is and isn't billed
Billed:
- Every successful (
2xx/3xx) authenticated/api/*call. - Each established transcription session (flat per-session cost).
Not billed:
- Any failed call —
400,401,404,413,415,422,429, and every5xx. Fix the request and retry without spending credits. - A call refused with
402for insufficient funds. - The unauthenticated
GET /healthliveness probe.
Recommended client behavior
- Watch
X-Credits-Remaining. Surface low balances to your own operators before they hit zero, rather than discovering it on a402. - Treat
402as terminal, not retriable. Stop the call, alert, and resolve funding — do not loop. Looping on a402never clears it. - Distinguish
402from429. A429clears when its window rolls over; honorRetry-Afterand retry. A402clears only when you add funds or raise a budget. Don't apply rate-limit backoff to a402. - Read cost from the headers. If you need to attribute spend,
record
X-Credits-Used/X-Credits-Cost-USDper call rather than assuming a fixed price per route. - Don't burn credits on avoidable failures. Validation and de-identification errors are free, but they still consume rate-limit window — fix them client-side (see errors.md).
Related
- errors.md — the error envelope and the full
errorcode taxonomy, includingPaymentRequired. - rate-limits.md — the
X-RateLimit-*headers and the contrasting "every request counts" rule. - authentication.md — keys and how to send them.
- ask-run.md — the variable-cost model endpoint and its per-call credit formula.
Change history
| Date | Change |
|---|---|
| 2026-06-22 | Initial publication — credit metering, the X-Credits-* headers, 402 PaymentRequired, and per-key / account budgets. |
| 2026-06-26 | Added the Variable-cost endpoints section for /api/ask/run; clarified that most (not all) routes are fixed-cost. |
| 2026-06-26 | Variable-cost pricing split into per-model input_cost_factor / output_cost_factor (input and output units priced separately). |