> ## Documentation Index
> Fetch the complete documentation index at: https://omnirelay.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Management API

> Provision API keys and pull usage from scripts, with a management key that cannot call models.

The Management API lets a script do what you would otherwise do on the **API Keys** and **Usage** pages: create keys for your own customers or services, limit and budget them, rotate or revoke them, and read usage. It lives under `https://api.omnirelay.ai/v1/manage/`.

## Management keys

The Management API accepts a **management key** (`or-mgmt-…`), never an API key. The two are separate on purpose: a key that calls models can never provision keys, and a management key can never call a model.

| Sent to | With an API key | With a management key |
| - | - | - |
| `/v1/chat/completions`, `/v1/models` | Works | `401 unauthorized` |
| `/v1/manage/*` | `401 management_key_required` | Works, within its scope |

After verified activation, create one on the **API Keys** page under **Management keys**. Creation is disabled before activation. It is shown **once** and only its hash is stored. Each key has a scope:

| Scope | Allows |
| - | - |
| `read` | List API keys and their budgets, read usage and request records |
| `write` | Everything `read` allows, plus create, change, rotate and revoke API keys and set their budgets |

A read key that attempts a write gets `403 insufficient_scope`. A management key acts **as you**: it changes your API keys; usage visibility follows your account permissions, and every change it makes appears in the audit log as `you@example.com via management key <name>`. Revoking it, suspending your account or deleting your account stops it on the next call. You can hold up to 10 active management keys.

> [!WARNING]
>
> A write key can mint API keys that spend your balance. Keep management keys on a server, never in a browser, and use a `read` key wherever reading is enough.

## Endpoints

Every request sends `Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY`. Bodies are JSON. Limited to 120 requests per minute per management key.

| Method and path | Scope | Does |
| - | - | - |
| `GET /v1/manage/keys` | read | List your API keys: name, prefix, status, holder, expiry, `default_tags`, `allowed_models` |
| `GET /v1/manage/keys/budgets` | read | Each key's budget, remaining amount, reset period and spend, in micro-USD |
| `POST /v1/manage/keys` | write | Create an API key. Returns its `key` **once** |
| `PATCH /v1/manage/keys/{id}` | write | Change `name`, `memberName`, `memberEmail`, `expiresAt`, `defaultTags` or `allowedModels` |
| `PATCH /v1/manage/keys/{id}/budget` | write | Set `budget`, `remaining` or `resetPeriod` |
| `POST /v1/manage/keys/{id}/rotate` | write | Replace the secret, keeping the key's id and settings. Returns the new `key` once |
| `DELETE /v1/manage/keys/{id}` | write | Revoke the key. It fails from its next call |
| `GET /v1/manage/usage` | read | Totals, time series and breakdowns, with the same filters as the **Usage** page |
| `GET /v1/manage/requests` | read | Paginated request records, newest first |

Anything else under `/v1/manage/` returns `404`. There is no way to reach billing, account or admin routes with a management key.

## Create a key for a customer

The owner’s workspace must currently have verified service readiness. Otherwise `POST /v1/manage/keys` returns `403 activation_required` and creates no key. Check **Overview → Live model service** and complete activation before retrying. Existing key rotation and revocation remain separate operations.

```bash theme={null}
curl https://api.omnirelay.ai/v1/manage/keys \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme production",
    "defaultTags": {"client": "acme"},
    "allowedModels": ["gpt-6-luna"],
    "budget": 50000000,
    "resetPeriod": "monthly"
  }'
```

```json theme={null}
{ "id": "3f2c…", "key": "or-live-…", "expiresAt": null }
```

`budget` is in micro-USD (50,000,000 is \$50). `defaultTags` follow the [Tags](https://omnirelay.ai/docs/general/tags.md) and `allowedModels` the [model limits](https://omnirelay.ai/docs/overview/authentication.md#limit-a-key-to-some-models). Store the returned `key` right away; it is not shown again.

## Read usage

```bash theme={null}
curl "https://api.omnirelay.ai/v1/manage/usage?range=30d&step=day&tag_key=client&tag_value=acme" \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY"
```

| Parameter | Values |
| - | - |
| `range` | `24h`, `7d`, `30d` or `90d` |
| `step` | `hour` (only with `24h` or `7d`) or `day` |
| `model`, `provider`, `key`, `status` | Narrow to one model ID, provider, API key ID, or `ok` / `error` |
| `tag_key`, `tag_value` | Keep calls carrying a tag, or only one value of it |
| `tag_group` | Add `groups.tag`: totals split by one tag key, with untagged calls in their own row |

The response holds `totals`, `previous` (the period before, for comparison), `series`, and `groups` by model, provider, key and status. Amounts are micro-USD and times are UTC.

`GET /v1/manage/requests` takes the same filters plus `limit` (up to 1,000) and `before` (the `next` cursor from the previous page).

## Calling order and fields

Create a management key in the console first. read and write scopes control management operations and do not activate models. Query [List models](https://omnirelay.ai/docs/llms/listing-models.md) with an inference key to confirm access.

Creation returns **201**; other successful operations return **200**. Response examples use placeholder IDs and credentials. Creation and rotation return the full key once.

| Request field | Rule |
| - | - |
| `name` | Required on creation, 1–60 characters. |
| `memberName`, `memberEmail` | Optional holder notes; name at most 80 characters and email must be valid. null or empty string clears a note. |
| `expiresAt` | Future Unix milliseconds; null means no expiry. |
| `defaultTags` | Object validated by [Tags](https://omnirelay.ai/docs/general/tags.md) rules. |
| `allowedModels` | 1–50 exact IDs or provider/\* rules; null allows all enabled workspace models. An empty array is invalid. Rules do not grant new model access. |
| `budget`, `remaining` | Integer micro-USD from 0 to 1,000,000,000,000; 50,000,000 is \$50. Both are null without a budget. |
| `resetPeriod` | none, daily, weekly or monthly; defaults to none. UTC calendar periods, weeks start Monday. |

PATCH preserves omitted fields. Changing budget does not refill remaining; explicitly set remaining to refill. Periodic budgets must be positive. Clear a budget with budget=null, remaining=null and resetPeriod=none together. Set expiry using the key update endpoint, not the budget endpoint.

Each owner can have 20 active API keys. Rotation preserves ID, expiry, restrictions, tags and spending counters; the old credential stops working immediately. Limited to 10 rotations per owner per hour. Creation and rotation are not idempotent: check current state before retrying an ambiguous result.

## List keys and budgets

```bash theme={null}
curl https://api.omnirelay.ai/v1/manage/keys \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY"

curl https://api.omnirelay.ai/v1/manage/keys/budgets \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY"
```

The key list returns `{ "keys": [...] }`, including revoked entries, without full credentials. Response fields use expires\_at, default\_tags and allowed\_models; write parameters use expiresAt, defaultTags and allowedModels.

Budget response example:

```json theme={null}
{
  "keys": [{
    "id": "example-key-id", "name": "Acme production", "prefix": "or-live-…",
    "status": "active", "spent": 0, "budget": 50000000, "remaining": 50000000,
    "resetPeriod": "monthly", "nextResetAt": 1793491200000,
    "expiresAt": null, "expired": false
  }],
  "budget_unit": "micro-USD", "timezone": "UTC"
}
```

## Update a key and its budget

Set KEY\_ID to the ID from creation or listing, not the full credential.

```bash theme={null}
curl -X PATCH "https://api.omnirelay.ai/v1/manage/keys/$KEY_ID" \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Acme production","defaultTags":{"client":"acme"},"allowedModels":["gpt-6-luna"]}'

curl -X PATCH "https://api.omnirelay.ai/v1/manage/keys/$KEY_ID/budget" \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"budget":50000000,"remaining":50000000,"resetPeriod":"monthly"}'
```

Both return `{ "ok": true }`. After 409 key\_changed, fetch current state before deciding to update again.

## Rotate and revoke a key

```bash theme={null}
curl -X POST "https://api.omnirelay.ai/v1/manage/keys/$KEY_ID/rotate" \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

curl -X DELETE "https://api.omnirelay.ai/v1/manage/keys/$KEY_ID" \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY"
```

Rotation returns `{ "id": "example-key-id", "key": "or-live-…" }`; store it securely and update your service. Revocation returns `{ "ok": true }` and preserves historical usage.

## Request records and pagination

```bash theme={null}
curl -G https://api.omnirelay.ai/v1/manage/requests \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY" \
  --data-urlencode "range=30d" \
  --data-urlencode "limit=50" \
  --data-urlencode "status=error"
```

```json theme={null}
{ "requests": [], "total": 0, "next": null, "limit": 50 }
```

Records include failures, sorted descending by created and id. limit defaults to 50, allowed 1–1,000. id filters an exact Request ID and accepts the chatcmpl- prefix. With a non-null next, keep the same filters and pass it unchanged as before:

```bash theme={null}
curl -G https://api.omnirelay.ai/v1/manage/requests \
  -H "Authorization: Bearer $OMNIRELAY_MANAGEMENT_KEY" \
  --data-urlencode "range=30d" \
  --data-urlencode "limit=50" \
  --data-urlencode "status=error" \
  --data-urlencode "before=$NEXT_CURSOR"
```

Do not modify the cursor. next=null ends pagination. Record status is a numeric HTTP status; tags is a JSON-encoded string or null. cost is settled spend and does not identify outstanding reservations.

Usage scope is workspace when the owner has members.read permission, otherwise user; member filtering requires that permission. Key listing and changes always apply only to the owner's keys. Usage and request reads also share a limit of 240 monitoring requests per owner per minute.

## Errors

| Status | Code | Meaning |
| - | - | - |
| 401 | `unauthorized` | The management key is missing, unknown or revoked, or its owner is suspended |
| 401 | `management_key_required` | An API key was sent to the Management API |
| 403 | `insufficient_scope` | A `read` key attempted a write |
| 404 | `not_found` | No such route, or no such key among yours |
| 429 | `rate_limited` | More than 120 requests in the current minute |

Validation errors from key changes (`invalid_input`, `invalid_tags`, `invalid_model_rules`, `invalid_key_policy`, `invalid_key_expiry`) are the same as in the console.

## API call reference

| Method and path | Reference |
| - | - |
| `GET /v1/manage/keys` | [List API keys](https://omnirelay.ai/docs/api-reference/management/list-api-keys.md) |
| `GET /v1/manage/keys/budgets` | [List key budgets](https://omnirelay.ai/docs/api-reference/management/list-key-budgets.md) |
| `POST /v1/manage/keys` | [Create API key](https://omnirelay.ai/docs/api-reference/management/create-api-key.md) |
| `PATCH /v1/manage/keys/{id}` | [Update API key](https://omnirelay.ai/docs/api-reference/management/update-api-key.md) |
| `PATCH /v1/manage/keys/{id}/budget` | [Update key budget](https://omnirelay.ai/docs/api-reference/management/update-key-budget.md) |
| `POST /v1/manage/keys/{id}/rotate` | [Rotate API key](https://omnirelay.ai/docs/api-reference/management/rotate-api-key.md) |
| `DELETE /v1/manage/keys/{id}` | [Revoke API key](https://omnirelay.ai/docs/api-reference/management/revoke-api-key.md) |
| `GET /v1/manage/usage` | [Read usage summary](https://omnirelay.ai/docs/api-reference/management/read-usage-summary.md) |
| `GET /v1/manage/requests` | [List request records](https://omnirelay.ai/docs/api-reference/management/list-request-records.md) |

## Management-key help

On **Console → API Keys**, select the question-mark icon beside the **Management keys** title to open contextual help. This icon opens help in place; the API documentation link remains in the description. Management keys do not grant model access, and inference keys cannot call the Management API.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.