API Keys
Inspect, create, update, and delete AnyRouter LLM API keys.
Manage the LLM API keys (prefix sk-ar-) your workspace uses to call inference endpoints. List, create, inspect, update, and delete keys from a script or CI pipeline.
/api/v1/keysThe CRUD routes (GET/POST /api/v1/keys, PATCH/DELETE /api/v1/keys/{hash}) authenticate with a Management key (ak_…) carrying read:llm-keys / write:llm-keys scope, or a signed-in dashboard session. An LLM key (sk-ar-…) is not accepted on these routes — it is only used on GET /api/v1/auth/key to inspect itself.
Request
The primary write route is POST /api/v1/keys, which mints a new LLM key. Send a JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable key name. |
expires_at | string | null | No | ISO 8601 expiration timestamp. |
limit | number | null | No | Credit cap for the key. |
limit_reset | daily | weekly | monthly | null | No | Reset interval for limit. |
include_byok_in_limit | boolean | No | Whether BYOK usage counts toward the key limit. |
rate_limit | number | No | Requests per minute for this key. |
disabled | boolean | No | Create the key in a disabled state. |
allowed_models | string[] | null | No | Restrict the key to specific model ids. |
allowed_endpoints | string[] | null | No | Restrict the key to specific API paths. |
tpm | number | null | No | Tokens-per-minute ceiling. |
Other routes
| Method & path | Purpose |
|---|---|
GET /api/v1/auth/key | Return metadata about the LLM key sent as the Bearer token. |
GET /api/v1/keys | List workspace keys. Pass ?include_disabled=true to include disabled keys. |
GET /api/v1/keys/{hash} | Return one workspace key by its stored hash. |
PATCH /api/v1/keys/{hash} | Update name, disabled, include_byok_in_limit, limit, limit_reset, rate_limit, or expires_at. |
DELETE /api/v1/keys/{hash} | Soft-delete a key by hash. |
Response
POST /api/v1/keys returns the plaintext secret once alongside the key record:
{
"key": "sk-ar-v1-actual-secret-only-shown-once",
"data": {
"id": "key_123",
"hash": "f3b8...",
"name": "ci-smoketest",
"label": "sk-ar-v1",
"created_at": "2026-04-24T00:00:00.000Z",
"updated_at": null,
"expires_at": null,
"disabled": false,
"real_usage": 0,
"real_usage_daily": 0,
"real_usage_weekly": 0,
"real_usage_monthly": 0,
"real_usage_monthly_requests": 0,
"limit": null,
"limit_remaining": null,
"limit_reset": null,
"include_byok_in_limit": false,
"rate_limit": 30,
"is_free_tier": true,
"is_management_key": false,
"creator_user_id": "user_123",
"last_used_at": null,
"allowed_models": ["openai/gpt-5.4-mini"],
"allowed_endpoints": ["/api/v1/chat/completions"],
"tpm": null
}
}
GET /api/v1/keys returns a { "object": "list", "data": [...] } envelope of key records (same shape, without the plaintext key). GET /api/v1/auth/key returns a compact record:
{
"key": {
"prefix": "sk-ar-v1",
"name": "production-backend",
"created_at": "2026-04-24T00:00:00.000Z",
"rate_limit": 60,
"usage": 128,
"limit": null,
"is_free_tier": true
}
}
DELETE /api/v1/keys/{hash} performs a soft-delete and returns:
{
"deleted": true,
"id": "key_123"
}
Examples
curl https://anyrouter.dev/api/v1/keys \
-X POST \
-H "Authorization: Bearer ak_your-management-key" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-smoketest",
"rate_limit": 30,
"allowed_models": ["openai/gpt-5.4-mini"],
"allowed_endpoints": ["/api/v1/chat/completions"]
}'
import httpx
resp = httpx.post(
"https://anyrouter.dev/api/v1/keys",
headers={"Authorization": "Bearer ak_your-management-key"},
json={
"name": "ci-smoketest",
"rate_limit": 30,
"allowed_models": ["openai/gpt-5.4-mini"],
"allowed_endpoints": ["/api/v1/chat/completions"],
},
)
print(resp.json()["key"]) # shown only once
const resp = await fetch("https://anyrouter.dev/api/v1/keys", {
method: "POST",
headers: {
Authorization: "Bearer ak_your-management-key",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "ci-smoketest",
rate_limit: 30,
allowed_models: ["openai/gpt-5.4-mini"],
allowed_endpoints: ["/api/v1/chat/completions"],
}),
})
const { key } = await resp.json() // shown only once
The plaintext key is returned once on creation and never again. Store it in a secret manager immediately.
Errors
All key endpoints return the standard error envelope:
{
"error": {
"code": "authentication_required",
"message": "Authentication required",
"metadata": {
"type": "authentication_error"
}
}
}
| Status | Meaning | Fix |
|---|---|---|
| 401 | Missing or invalid credential | Send a valid Management key (ak_…) or dashboard session. |
| 403 | Key lacks the required scope | Grant read:llm-keys / write:llm-keys. |
| 404 | No key with that hash | Check the hash from a GET /api/v1/keys listing. |