AnyRouter

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.

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 | nullNoRolling window limit is measured over. null is measured over 30 days, not for the key's lifetime.
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. Ids are matched without regard to case. anyrouter/auto and anyrouter/free only route to listed models that are in their own pool; to use any other listed model, call it directly.
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/keyOpenRouter-compatible current-key info. With an LLM key (sk-ar-…, including sign-in app keys) it returns only that key: data.label, limit, limit_remaining, usage, is_free_tier, rate_limit. With a dashboard session or Management key it returns the workspace's newest active key.
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.
POST /api/v1/keys/{hash}/rotateIssue a new secret for the same key. The old secret stops working immediately; the key's id, limits, restrictions and usage history are unchanged.

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
  }
}

limit_remaining is limit minus the key's spend in that window — a daily key's is measured over the last 24h, a weekly one over 7 days, and a monthly (or null) one over 30 days — so it can rise again as the window rolls.

POST /api/v1/keys/{hash}/rotate returns the same envelope with a new plaintext secret and the key's new hash. Everything else is carried over unchanged — id, name, limit, allowed_*, spend totals — so any /key?id= or api_key_id reference keeps resolving. The old secret stops authenticating the moment the call returns, so update every deployment holding it before you rotate. The request takes no body; two concurrent rotates of the same key are rejected with 409 rather than silently discarding one secret.

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"]
  }'

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.