Skip to content

Budgets, caps & credits

Spend is bounded at three levels: each key has its own caps, a parent key caps the sum of its sub-keys, and your organization has a credit balance and, optionally, budgets. A call must fit all three before it runs.

Every key carries a caps object (visible on GET /v1/key and on sub-keys returned by /v1/keys). Each cap is checked on every call:

Cap Default Checked Refusal
usd_day none At reservation: spent today + reserved + this call’s estimate must stay within it. Calendar day, UTC. 402 key_cap_exceeded
usd_month none Same, for the calendar month, UTC. 402 key_cap_exceeded
rpm 60 At admission: requests in the current minute, refused attempts included. 429 rate_limited
tpm none At reservation: the worst-case token estimate of every call that reached the reservation in the current minute — refused ones included, never corrected to actual use. 429 rate_limited
max_in_flight 20 At admission: calls reserved and not yet settled. 429 too_many_in_flight
max_output_tokens 4,096 At validation: max_tokens above it is refused; when you omit max_tokens, it becomes the ceiling. 400 max_tokens_exceeds_key_limit

Spend caps are in USD at your organization’s sale price. A call is admitted against the estimate it reserves, then counts its real cost once settled — see Admission & settlement. A Chat Completions or Responses call that fails without reported usage can still count the input part of its estimate, or the full estimate, against the caps. That amount is counted against the key’s caps (and its parent’s) only — it is not billed: no credits are debited, and it adds nothing to the cost in /v1/usage or /v1/credits. It shows in the key’s spent_usd on /v1/key. For rate limits and retry guidance, see Rate limits & caps.

A key with the keys:manage scope can mint sub-keys with POST /v1/keys — one level deep. A sub-key never exceeds its parent: lower or equal caps and rates, a subset of its scopes and models, an expiry no later than the parent’s. Anything you leave out is inherited. A request that asks for more is refused with 400 child_exceeds_parent.

How the limits combine at call time:

  • Spend is shared. A sub-key’s call reserves its estimate on the sub-key and on the parent’s daily and monthly counters. The parent’s usd_day and usd_month are a ceiling for the parent and all its sub-keys together. When the parent’s cap refuses, the message reads “Spend cap reached for the parent of this key”.
  • Rates are per key. Requests per minute, tokens per minute and calls in flight are counted for the key that makes the call only.
  • Status is inherited. Disabling, revoking or expiring the parent stops every sub-key: their calls answer 401 invalid_api_key.

See Sub-keys per customer for a full pattern.

After the key’s caps, the call’s estimate must fit your organization:

Code HTTP Meaning What to do
insufficient_credits 402 No active subscription, or not enough credits left for this call’s estimate. Add credits or upgrade your plan in the dashboard.
budget_exceeded 402 A budget your organization set in its dashboard is exhausted. Raise the budget, or wait for its next period.
spend_refused 402 Your organization’s spend controls refused the call for another reason. Check your organization’s billing settings in the dashboard.
pricing_unavailable 503 No price is configured for your organization yet. A retry will not fix it. Contact support.
admission_unavailable 503 The spend controls could not be checked; the call is refused rather than served unchecked. Retry after Retry-After (5 s).

GET /v1/credits (scope usage:read) returns your organization’s balance for the current period, in credits — the same unit as belarel.cost.credits:

{ "object": "credits", "unit": "credits", "has_subscription": true, "included": 50000, "consumed": 12840.5, "balance": 37159.5 }

GET /v1/key works with any valid key, whatever its scopes, and is never refused for calls in flight. It returns the key’s settings and caps, plus what it spent and reserved:

Terminal window
curl https://api.belarel.com/v1/key \
-H "Authorization: Bearer $BELAREL_API_KEY"
"usage": {
"day": { "spent_usd": 3.12, "reserved_usd": 0.04, "limit_usd": 10, "remaining_usd": 6.84, "resets_at": "2026-10-03T00:00:00+00:00" },
"month": { "spent_usd": 41.9, "reserved_usd": 0.04, "limit_usd": null, "remaining_usd": null, "resets_at": "2026-11-01T00:00:00+00:00" }
},
"rate_limit": { "requests_per_minute": 60, "requests_this_minute": 7, "tokens_per_minute": null, "max_in_flight": 20, "in_flight": 1 }

remaining_usd is null when the window has no cap. These figures are the key’s own; a parent’s figures include its sub-keys’ spend.

When a spend cap refuses a call, Belarel sends the api_key.cap_reached webhook to your organization — at most once per capped key per UTC day. When the parent’s cap is the one that refused, the event names the parent key. Its payload carries the key’s caps and its spend for the day and the month, reservations included. Subscribe in your organization’s dashboard; see Webhooks.