Billing
The prepaid wallet, request-time credit reservations, metered usage, and video billing.
Prepaid wallet
Every organisation has a prepaid wallet. Usage is metered per model (SKU) from
the provider's own reported usage — never estimated — and priced at the
catalogue rate for that model at nano-USD precision.
How reservations work
Before calling the provider, the gateway reserves an estimated cost against balance minus open reservations:
- The estimate is sized from
max_tokens(falling back to a platform default when omitted), priced at the model's rate. - The reservation is held for the life of the request.
- Once usage is metered, the reservation is settled to the real cost (or released, if the request failed).
Because the check is against balance minus open reservations, concurrent requests cannot collectively overspend a small balance. This reservation gate applies to prepaid wallets — postpaid orgs are capped by a monthly budget instead (a counter cap, not a reservation).
Why 402 is not 429
If the wallet cannot cover the reservation you get HTTP 402:
{
"error": {
"type": "insufficient_quota",
"message": "Insufficient credit balance — top up to continue",
"code": "insufficient_funds",
"param": null,
"request_id": "req_01J8EXAMPLE"
}
}A funds denial is deliberately not a 429:
- It is not congestion — SDK retry/backoff does not help.
- No
Retry-Afteris sent. - Retrying without topping up will keep failing.
Top up in Billing (Stripe) and retry.
Other money-related errors
| Status | Code | Trigger |
|---|---|---|
| 402 | insufficient_funds | Wallet cannot cover the reservation. |
| 402 | key_spend_cap_reached | Per-key USD spend cap reached. |
| 402 | project_quota_exceeded | Project monthly cost ceiling reached. |
| 429 | quota_exceeded / project_quota_exceeded | Token quota windows (not funds). |
Cached tokens
Provider-reported prompt-cache tokens are surfaced, never estimated:
- OpenAI-dialect bodies:
usage.prompt_tokens_details.cached_tokens/.cache_write_tokens - Anthropic-dialect bodies:
usage.cache_read_input_tokens/usage.cache_creation_input_tokens - Every body:
provider_metadata.cache.read_tokens/.write_tokens
On OpenAI-dialect chat/embeddings responses these prompt_tokens_details
fields are always present (0 when the backend didn't report caching) — see
Normalized usage shape.
The billed amount always matches what's displayed, including the cache
discount: the same cache figures the client sees are what's metered, never a
separately-computed number.
Cached tokens are priced at the model's cached rate when the catalogue defines one, and the standard rate otherwise.
Video billing
Video jobs are billed only on confirmed completion:
| Job state | billing.state | Charged? |
|---|---|---|
queued / processing | pending | No — but see the reservation above |
completed | charged | Yes |
failed | void | No |
cancelled | void | No |
The billed unit is the requested duration (seconds). A job that expires past
its retention window keeps its already-settled charge; nothing further is billed.
Inspecting spend
- Portal → Billing: wallet balance, top-ups, invoices.
- Portal → Analytics: token/cost breakdown per model and per key.
- Every response's
usageblock shows exactly what was metered for that request.