Create an API key (returns the plaintext once)
Returns the new key's plaintext secret, which is shown only in this response, with its id, prefix, organization id, and any permissions or budget. With permissions enabled, only a signed-in session creates keys, and a new key belongs to the organization (kind org), so it keeps working if its creator leaves; personal and service kinds are refused, except dashboard playground keys, which are always personal. Its permissions come from template or permissions and can never exceed the creator's own access (403 ESCALATION_REFUSED). scopes still works and maps to the key's ceiling. budget caps what the new key may spend on inference per period. A key that carries a budget cannot create keys (403 FORBIDDEN), so it cannot mint itself one without a budget.
Required permission
Checked against the apikey.create permission for the resource it acts on. See Permissions for the roles and API key permissions that include it.
Command line
The orl CLI wraps this endpoint:
orl api-keys create --name <name>apiKeyAuthorizationBearer <token>OpenRelay API key. Send it as Authorization: Bearer or_… (legacy vl_… keys still work).
orgId*stringapplication/json- body
name*stringscopes?array<string>Supported values: clusters:read, clusters:write, vms:read, vms:write, inference, and inference:endpoint: for an enabled dedicated endpoint owned by the organization. An endpoint scope also adds the inference scope when it is omitted. clusters:read grants read access to the organization's resources, including VMs and pods, and clusters:write grants write access, including VM restart and API key creation. vms:read and vms:write are accepted for compatibility but grant nothing on their own, so each must be requested together with clusters:read or clusters:write respectively; a request with one but not the other returns 400. With permissions enabled, a session's request with scopes creates an organization key whose ceiling the scopes map to.
expiresInSeconds?integerOptional server-side expiry, in seconds from now. When set (and > 0) the key stops authenticating after this many seconds, capping the leak window regardless of any client-side cleanup. Omitted or <= 0 means the key never expires (the default).
int64budget?A spend budget for the key. The inference API refuses the key's requests with 402 key_budget_exceeded when its spend in the period plus an estimate of the request's cost would pass the limit, and its new batches once the spend reaches the limit. The estimate is not a bound and nothing is reserved: a request can cost more than its estimate (its prompt size is estimated, and cache writes are not priced into it), requests and batches already running finish, and requests sent at the same time can each pass the limit.
kind?stringPermissions enabled only. org (the default) belongs to the organization and keeps working if its creator leaves. personal is refused for non-ephemeral creates.
"personal""org"serviceAccountId?stringDeprecatedNo longer supported. Requests containing this field are refused.
template?stringPermissions enabled only. A key template id from GET /v1/authz/catalog (inference, inference_batch, compute_automation, read_only). Ignored when permissions is set.
permissions?array<string>Permissions enabled only. The key's permission ceiling, as permission ids.
restrictions?note?stringPermissions enabled only. Where the key is used; shown when someone revokes it.
length <= 512ephemeral?booleanDashboard use only: a short-lived personal key for the playground and batch pages, limited to Inference, Batch Read and Batch Write (each held by the creator), expiring within 900 seconds and never listed.
Created
application/json- response
id*stringkey*stringPlaintext key, shown once
keyPrefix*stringname*stringscopes*array<string>createdAt*stringorganizationId*stringThe organization this key is bound to. Every API key belongs to exactly one organization; keep this id alongside the key so callers can build org-scoped request paths without a separate lookup (GET /v1/whoami returns the same id for an existing key).
kind?string"personal""org""legacy"ownerUserId?stringpermissions?array<string>restrictions?expiresAt?stringcedar?stringThe Cedar policies generated for the key's restrictions.
budget?The key's spend budget and what the key has spent in the current period. Amounts are integer nanoUSD (1 USD = 1,000,000,000). Every inference request the key makes counts, batches included, at the price it is billed, from when the budget was set; compute (VMs and pods) is not counted.
curl -X POST 'https://api.openrelay.inc/v1/orgs/string/api-keys/create' \ -H 'Content-Type: application/json' \ -d '{ "name": "ci-deploy", "scopes": [ "clusters:read", "clusters:write", "vms:read" ]}'{ "id": "string", "key": "string", "keyPrefix": "string", "name": "string", "scopes": [ "string" ], "createdAt": "string", "organizationId": "string", "kind": "personal", "ownerUserId": "string", "permissions": [ "string" ], "restrictions": { "permissions": [ "string" ], "models": [ "string" ], "endpoints": [ "string" ], "ipRanges": [ "string" ] }, "expiresAt": "string", "cedar": "string", "budget": { "limitNanoUsd": 0, "period": "lifetime", "spentNanoUsd": 0, "periodEndsAt": "2019-08-24T14:15:22Z" }}List an org's API keys (no secrets) GET
Returns the organization's API keys with each key's id, name, prefix, kind, scopes, budget, expiry and last use. The plaintext secret is never returned. With permissions enabled, a caller without apikey.read gets only their own personal keys. Dashboard playground keys are never listed.
Edit an API key budget PATCH
Sets, changes or removes an API key's spend budget and returns the key with its current spend. A limitNanoUsd of 0 removes the budget. Requires a signed-in session: your own key, or apikeys.write for any key. In organizations with permissions enabled, only the budget can be edited. Name, note and restrictions return 400. Available with permissions enabled; otherwise 404.