Skip to content

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.

POST/api/v1/keys

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

FieldTypeRequiredDescription
namestringYesHuman-readable key name.
expires_atstring | nullNoISO 8601 expiration timestamp.
limitnumber | nullNoCredit cap for the key.
limit_resetdaily | weekly | monthly | nullNoReset interval for limit.
include_byok_in_limitbooleanNoWhether BYOK usage counts toward the key limit.
rate_limitnumberNoRequests per minute for this key.
disabledbooleanNoCreate the key in a disabled state.
allowed_modelsstring[] | nullNoRestrict the key to specific model ids.
allowed_endpointsstring[] | nullNoRestrict the key to specific API paths.
tpmnumber | nullNoTokens-per-minute ceiling.

Other routes

Method & pathPurpose
GET /api/v1/auth/keyReturn metadata about the LLM key sent as the Bearer token.
GET /api/v1/keysList 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"
    }
  }
}
StatusMeaningFix
401Missing or invalid credentialSend a valid Management key (ak_…) or dashboard session.
403Key lacks the required scopeGrant read:llm-keys / write:llm-keys.
404No key with that hashCheck the hash from a GET /api/v1/keys listing.

Related