Skip to content
OpenRelay is in early access, and the /v1 API is stable. New capabilities ship in the changelog.
GuidesInference

Key budgets

Cap what an API key may spend on inference per day, per month or in total, and how requests near the limit are handled.

An API key can carry a spend budget: the most it may spend on inference in total, per UTC day, or per UTC month. Give each agent its own key with a budget and a misbehaving agent stops at its limit instead of draining the organization's balance.

A budget caps the key, not the organization: the key still needs a funded balance, and the organization's other keys are unaffected.

Set a budget

Pass budget when you create the key. Amounts are integer nanoUSD (1 USD = 1,000,000,000 nanoUSD):

curl -X POST https://api.openrelay.inc/v1/orgs/{orgId}/api-keys/create \
  -H "Authorization: Bearer $OPENRELAY_SESSION_OR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "triage-agent", "budget": { "limitNanoUsd": 50000000000, "period": "monthly" } }'
{
  "id": "key_123",
  "key": "or_…",
  "name": "triage-agent",
  "budget": {
    "limitNanoUsd": 50000000000,
    "period": "monthly",
    "spentNanoUsd": 0,
    "periodEndsAt": "2026-11-01T00:00:00Z"
  }
}
periodResets
lifetime (the default)never
dailyat 00:00 UTC
monthlyat 00:00 UTC on the first of the month

With the CLI: orl api-keys create --name triage-agent --budget-usd 50 --budget-period monthly.

A key that carries a budget cannot create keys, so it cannot mint itself one without a budget.

Change a budget

With permissions enabled, a signed-in member changes a budget through PATCH /v1/orgs/{orgId}/api-keys/{id}. A key never changes its own budget.

{ "budget": { "limitNanoUsd": 80000000000 } }

budget changes the fields it names, and a field left out keeps its value:

  • A new limitNanoUsd alone keeps the period and what was spent so far in it.
  • A new period keeps the limit and counts from zero.
  • "limitNanoUsd": 0 removes the budget. A budget set again later counts from zero.
  • A key without a budget needs limitNanoUsd to get one.

Without permissions, a budget is fixed when the key is created: to change it, create a key with the new budget and revoke the old one.

A change applies to the key's next request, usually at once: the update clears the key's cached authentication record. A request that reloads that record while the update lands, or a clear that fails, can keep the old budget in use for up to a minute. Requests already running count toward the budget they were admitted with.

What counts

  • Every inference request the key makes, at the price it is billed: the openrelay.cost_nano_usd figure on the response (Pricing & billing).
  • Batches the key submits, at the batch price, counted as the batch's records are billed when it finishes.
  • Spend counts from when the budget is set. What the key spent before it had a budget does not count.
  • Compute is not counted. VMs and pods the key creates spend nothing against its budget.

When the budget runs out

Before a request runs, the API checks the key's spend in the current period plus an estimate of the request's cost: its prompt, sized from its bytes, at the input price, plus max_tokens (or the model's default output cap when you send none) at the output price. If that would pass the limit, or the spend has already reached it, the request is refused with 402 Payment Required before it reaches a model:

{
  "error": {
    "message": "this API key's spend budget is used up; it resets at 2026-11-01T00:00:00Z",
    "type": "insufficient_quota",
    "code": "key_budget_exceeded"
  }
}

A request refused for its estimate alone says so; set max_tokens so a request's estimate fits what is left. Creating a batch is refused the same way once the budget is used up. Do not retry a key_budget_exceeded unchanged: wait for the reset, or ask whoever manages the key to raise the budget.

A budget can be passed

The estimate is not a bound, and nothing is reserved while a request runs.

  • A single request can cost more than its estimate, so it can pass the limit by more than the estimate left room for: the prompt's size is estimated from its bytes and can hold more tokens, cache writes are not priced into the estimate, and without max_tokens the estimate uses the model's default output cap.
  • Requests admitted at the same time are each checked against the same spend, so each of them can pass the limit.
  • A batch is checked only when it is created, and only for a budget that is used up, so one batch can pass the limit by its whole cost. It finishes, and its cost counts toward the key.

A request that was admitted finishes and is billed. Once the recorded spend reaches the limit, every new request and batch is refused.

Check a key's budget

GET /v1/whoami with the key returns its budget on the key object, with what it has spent this period and when the period ends. orl auth status prints the same line, and orl doctor warns once the budget is used up:

budget:  $12.40 of $50.00 spent (monthly, resets 2026-11-01 00:00 UTC)

The key list returns each active key's budget and spend the same way. If the spend cannot be read for a moment, the budget comes back without spentNanoUsd, and orl prints "spend unavailable".

On this page