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

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>
POST
/v1/orgs/{orgId}/api-keys/create

Authorization

apiKey
headerAuthorizationBearer <token>

OpenRelay API key. Send it as Authorization: Bearer or_… (legacy vl_… keys still work).

Path Parameters

orgId*string

Request Body

application/json
  1. body
name*string
scopes?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?integer

Optional 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).

Formatint64
budget?

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?string

Permissions enabled only. org (the default) belongs to the organization and keeps working if its creator leaves. personal is refused for non-ephemeral creates.

Value in"personal""org"
serviceAccountId?stringDeprecated

No longer supported. Requests containing this field are refused.

template?string

Permissions 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?string

Permissions enabled only. Where the key is used; shown when someone revokes it.

Lengthlength <= 512
ephemeral?boolean

Dashboard 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.

Response Body

Created

application/json
  1. response
id*string
key*string

Plaintext key, shown once

keyPrefix*string
name*string
scopes*array<string>
createdAt*string
organizationId*string

The 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
Value in"personal""org""legacy"
ownerUserId?string
permissions?array<string>
restrictions?
expiresAt?string
cedar?string

The 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.

Example Request
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"  ]}'
Example Response
{  "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"  }}