Skip to main content

API keys

Create and revoke keys in the dashboard under API Keys. Each secret is a single string:
  • Prefix: rk_
  • Then 64 hexadecimal characters (256 bits)
Example shape (not a real key):
rk_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Use one key per environment (laptop, CI, product) so you can revoke a leak without rotating everything.

Passing your API key

curl -sS https://api.routing.run/v1/chat/completions \
  -H "X-API-Key: ${ROUTING_RUN_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"model": "route/deepseek-v3.2", "messages": [{"role": "user", "content": "Hi"}]}'
OpenAI and Anthropic SDKs send Authorization: Bearer by default; routing.run treats that the same as X-API-Key for rk_ secrets.

Managing API keys over HTTP

POST /v1/user/key, GET /v1/user/key, and DELETE /v1/user/key/ require Authorization: Bearer <access JWT> — the HS256 access token from the routing.run auth flow (POST /auth/login/verify, OAuth completion, or POST /auth/refresh), not an rk_ inference key. The access token payload includes sub (user id) and plan.
If the header is missing or does not start with Bearer , the handler raises RateLimitError today, which returns HTTP 429 with body Authentication required and X-Error-Code: RATE_LIMIT_ERROR. Treat that as “missing user session” until the API distinguishes it from real rate limits.

Create an API key

Response includes the full secret once in key (same rk_ + 64 hex format):
curl -sS -X POST https://api.routing.run/v1/user/key \
  -H "Authorization: Bearer ${ROUTING_RUN_ACCESS_JWT}" \
  -H "Content-Type: application/json" \
  -d '{"name": "ci-deploy-bot"}'

List your API keys

Returns {"data": [ ... ]} with id, key_prefix, name, plan_tier, created_at, last_used_at — never the full secret.
curl -sS https://api.routing.run/v1/user/key \
  -H "Authorization: Bearer ${ROUTING_RUN_ACCESS_JWT}"

Revoke an API key

curl -sS -X DELETE "https://api.routing.run/v1/user/key/${KEY_ID}" \
  -H "Authorization: Bearer ${ROUTING_RUN_ACCESS_JWT}"
KEY_ID is the id from list or create. Success body: {"message":"API key revoked"}. Unknown id → 404 with plain-text body and X-Error-Code: NOT_FOUND.

Plan tiers

Your workspace plan tier decides which route/… IDs you may call and how many requests and credits you have. Exact numbers live in the dashboard (they can change as plans update).
TierModel accessWhere to see limits
FreeFree-tier models in ModelsDashboard usage and daily cap
LiteFree + Lite modelsSame
PremiumAdds Premium modelsSame
MaxFull catalog including Max-only modelsSame
The tier field on each object in GET /v1/models comes from routing config for the resolved plan.

Error responses

Most application errors use ExceptionHandlerMiddleware: the response body is plain text (the message string), and the machine code is in the X-Error-Code header. There is no JSON {"error":{...}} wrapper for these in the current API. Example (daily cap):
HTTP/1.1 429 Too Many Requests
X-Error-Code: DAILY_REQUEST_LIMIT_EXCEEDED
Content-Type: text/plain

Daily request limit exceeded
Example (model not allowed on plan):
HTTP/1.1 403 Forbidden
X-Error-Code: MODEL_NOT_ALLOWED
Content-Type: text/plain

Model 'route/deepseek-r1' is not available on your plan
JSON bodies still appear for:
  • 401 from auth middleware when no credentials: {"message":"Authentication required"} or invalid JWT: {"message":"Invalid or expired token"}.
  • 429 from IP rate-limit middleware: {"message":"Rate limit exceeded. Please try again later.", "retry_after": …} plus Retry-After and X-RateLimit-* headers.
  • POST /v1/chat/completions streaming errors: SSE data: {"error":{"message":"…","type":"api_error"}}.
  • GET /v1/models/ unknown id: {"error":"Model not found"}.
  • Some image error paths: {"error":{"message":"…","type":"api_error"}} or {"error":"Model not found"}.
Inference routes (POST /v1/chat/completions, POST /v1/messages, …) validate the rk_ key in the handler: wrong key → 401 plain text Invalid API key with X-Error-Code: AUTHENTICATION_ERROR.
Never share your API key publicly or commit it to version control.

Common X-Error-Code values (plain-text body)

StatusX-Error-CodeTypical body text
401AUTHENTICATION_ERRORInvalid API key / Authentication failed
402INSUFFICIENT_CREDITSInsufficient credits for this request
403MODEL_NOT_ALLOWEDModel '…' is not available on your plan
429DAILY_REQUEST_LIMIT_EXCEEDEDDaily request limit exceeded
429RATE_LIMIT_ERRORIP limit or (misleading today) missing Bearer on /v1/user/key*
502PROVIDER_ERRORUpstream-specific message
504PROVIDER_TIMEOUTTimeout message
503CIRCUIT_BREAKER_OPENCircuit breaker open for an upstream
400INVALID_MODELInvalid model: '…'