11. Keys, scopes and limits
Scopes
| Scope | Grants |
|---|---|
inference:call | every inference endpoint |
catalog:read | list and inspect models |
catalog:write | register and deregister your own model aliases (never rents compute) |
usage:read | usage rollups and analytics |
billing:read | balance, credits, costs, entitlement |
keys:read / keys:write | manage keys |
instances:read / instances:write | manage compute |
webhooks:read / webhooks:write | manage webhooks |
audit:read | read your audit log |
identity:read / identity:write | tenancy structure |
training:read / training:write | reserved |
A key can only ever be granted scopes the minting principal already holds, and
PATCH /v1/keys/{id} can only reduce them.
Per-key controls
At mint time: rate_limit_rpm, expires_at. By PATCH: name, scopes
(reduction only — widening needs a new key), rate_limit_rpm, expires_at,
and spend_cap:
curl -X PATCH "$BASE/v1/keys/$KEY_ID" \
-H "Authorization: Bearer $SESSION_JWT" -H "Idempotency-Key: $(uuidgen)" \
-d '{"spend_cap": {"max_budget_micro_cents": 500000000, "budget_window": "monthly"}}'The two halves travel together — a ceiling with no window never enforces — and
GET /v1/keys/{id} reads the cap back. A cap larger than your tenant's own
monthly allowance is refused. Omitting spend_cap leaves the existing one
alone; a cap cannot be removed, only changed.
tpm_limit,models,blocked_modelsandip_allowlistare enforced at request time but no route sets them yet — today they are operator-written columns. Spend caps are wired end to end and exercised in production.
Rotation
curl -X POST "$BASE/v1/keys/$KEY_ID/rotate" \
-H "Authorization: Bearer $SESSION_JWT" -H "Idempotency-Key: $(uuidgen)" \
-d '{"grace_period_seconds": 86400}'Both keys work during the grace window, so you can roll a deployment without
downtime. The window is in SECONDS and is capped at 24 hours; the body refuses
any other field, so a mis-spelled one is a 400 rather than a silent zero-grace
cutover. Rotation alone leaves the key alive indefinitely under its new secret
— to retire a key, PATCH its expires_at to the end of the grace window in
the same breath.