Skip to content

Docs

Everything you need to call the gateway: base URL, authentication, endpoints, errors, troubleshooting and limits.

Quick start

  1. Sign up and verify your email: your first API Key is created for you.
  2. Top up your Balance (or redeem a Voucher).
  3. Point your tool or SDK at the base URL below with your API Key.
Your first Request
curl https://api.centrouter.com/v1/chat/completions \
  -H "Authorization: Bearer $CENTROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-6-luna", "messages": [{"role": "user", "content": "Hello"}]}'

Base URL

OpenAI-compatible clients use the URL ending in /v1. Anthropic clients (Claude Code, the Anthropic SDK) use the root without /v1; they add /v1/messages themselves.

OpenAI format
https://api.centrouter.com/v1
Anthropic format
https://api.centrouter.com

Authentication

Send your API Key with every Request. Both headers work on every endpoint; keys start with gsk_. Keep keys secret: anyone with a key spends your Balance.

Authorization: Bearer gsk_…
# or
x-api-key: gsk_…

Endpoints

Use a model’s ID from the Models or Pricing page. Streaming works on every chat endpoint.

EndpointWhat it does
POST /v1/chat/completionsChat Completions (OpenAI format), streaming or not.
POST /v1/messagesMessages (Anthropic format), used by Claude Code.
POST /v1/messages/count_tokensA free estimate of a Messages request’s input Tokens (about 4 characters per Token), which Claude Code asks for. Charges always use the usage the model reports.
POST /v1/responsesResponses (OpenAI format), used by Codex CLI.
POST /v1/embeddingsEmbeddings for models that support them.
GET /v1/modelsEvery model in the Catalog, with the prices your key is charged and what each supports.
GET /v1/balanceYour Balance and the amount held by running Requests.

Errors

Errors use the format of the endpoint you called: OpenAI endpoints return error.code, Anthropic endpoints return error.type. Every error has a message that says how to fix it. Select a code for its causes and the steps that fix it.

CodeHTTPMeaning
invalid_api_key401The key is missing, malformed, expired or revoked. Create a new one on the API Keys page.
account_blocked403The account is blocked: the gateway rejects all its API Keys.
route_not_found404No route at that method and path. Check the base URL: OpenAI format ends in /v1, Anthropic format does not.
model_not_found404No visible Catalog model has that ID. List models with GET /v1/models.
model_not_allowed403This key is restricted to other models. Change its model list on the API Keys page.
spend_limit_exceeded403The key reached its daily, monthly or total Spend Limit. Raise the limit or wait for the next period.
insufficient_balance402Your Balance cannot cover this Request. Top up and retry.
rate_limit_exceeded429Too many Requests per minute, or too many at once. Retry after a short wait.
invalid_request400The body is not valid for this endpoint. Check the message for the field.
upstream_error502No model source could answer. You were not charged; retry, and check the Status page.
upstream_rate_limited429Model sources are busy. You were not charged; retry after a short wait.
request_too_large413The body is over 32 MB, usually large images. You were not charged; send smaller or fewer images.

Once a Request is accepted, its response has an x-request-id header (req_ followed by 32 characters), whether it succeeded, streamed or failed at the model. It is the Request’s ID in Activity, where you can search for it; quote it when you ask for help. Error responses for such a Request carry it in the body too, as request_id. A Request rejected before that (wrong key, blocked account, invalid body, unknown route or model, limits, low Balance) has no ID.

Troubleshooting

Start with the error’s code (OpenAI format: error.code) or type (Anthropic format: error.type), then follow the steps. Each entry has its own link.

Common problems

The tool sent a model ID that is not in the Catalog, often its own built-in default. Tell the tool which Catalog model to use:

  • List the IDs you can call: npx centrouter models.
  • Claude Code: set both ANTHROPIC_MODEL and ANTHROPIC_DEFAULT_HAIKU_MODEL to a Catalog ID in ~/.claude/settings.json.
  • Codex CLI: set model in ~/.codex/config.toml.
  • OpenCode: set model to centrouter/ followed by the ID in opencode.json, and list the ID under the provider’s models.
  • Or let the CLI write it: npx centrouter setup claude --model ID (or codex, opencode).

A 404 that names a route, not a model, means the base URL is wrong: OpenAI-format tools need https://api.centrouter.com/v1, Anthropic-format tools https://api.centrouter.com.

The gateway did not get a valid API Key from the tool. The error message says whether no key arrived or the key is wrong.

  • Claude Code reads the key from ANTHROPIC_AUTH_TOKEN in ~/.claude/settings.json. ANTHROPIC_BASE_URL must be https://api.centrouter.com, without /v1.
  • Codex CLI and OpenCode read the key from the CENTROUTER_API_KEY environment variable. Add export CENTROUTER_API_KEY=gsk_… to your shell profile, then open a new terminal.
  • Test the key outside the tool: curl https://api.centrouter.com/v1/models -H "Authorization: Bearer $CENTROUTER_API_KEY"
  • If the key is lost or revoked, run npx centrouter login for a new one, then run setup again.

A streamed response ends early for one of these reasons:

  • The model sent nothing for 2 minutes, so the gateway ended the stream.
  • The Request reached the 10-minute limit.
  • The connection to the model source broke, or your tool cancelled the Request.
  • The answer reached the output limit (max_tokens). The response then ends normally, with a stop reason that says so.

You are charged only for the Tokens already delivered. Activity lists a stream that broke as Cancelled.

Retry the Request. If answers stop at the output limit, raise max_tokens. If one model keeps cutting off, check the Status page and quote the response’s x-request-id when you ask for help.

While a Request runs, the gateway holds the most it could cost: your prompt, counted generously, plus the whole output limit (max_tokens, or the model’s maximum when you send none). The Balance page shows the amount as “Held for running Requests”.

When the Request ends, you are charged for the Tokens actually used and the rest returns to your available Balance. A drop you see during a Request is mostly a hold, not a charge.

A hold left by a Request that never finished is released automatically within about 20 minutes.

If the charges themselves are higher than you expected, open Activity: each Request shows its Tokens by kind and its cost. Coding agents resend the conversation on every turn, so input Tokens grow as a session gets longer, and cache writes are charged at the cache-write price.

To cap what a key can spend, give it a Spend Limit on the API Keys page.

Error codes

invalid_api_key

HTTP 401Anthropic format: authentication_error

No API Key reached the gateway, or the key sent is mistyped or revoked. The message says which.

How to fix it

  • Send the key as Authorization: Bearer gsk_… or x-api-key: gsk_….
  • If your tool reads the key from an environment variable, check that it is set in the shell that starts the tool: echo $CENTROUTER_API_KEY.
  • Look at the key on the API Keys page. A revoked key cannot be restored; create a new one.
  • Test the key outside your tool: curl https://api.centrouter.com/v1/models -H "Authorization: Bearer $CENTROUTER_API_KEY"

account_blocked

HTTP 403Anthropic format: permission_error

The account is blocked, so the gateway rejects every one of its API Keys.

How to fix it

  • Write to support@centrouter.com to restore access.
  • A new API Key does not help: the block is on the account, not on a key.

route_not_found

HTTP 404Anthropic format: not_found_error

The gateway has no route for that method and path. The usual cause is the base URL.

How to fix it

  • OpenAI-format clients need the base URL that ends in /v1: https://api.centrouter.com/v1
  • Anthropic-format clients need the root without /v1: https://api.centrouter.com. With /v1 they call /v1/v1/messages.
  • Check the method: /v1/models and /v1/balance are GET, every other endpoint is POST.

model_not_found

HTTP 404Anthropic format: not_found_error

No model in the Catalog has the ID you sent.

How to fix it

  • Copy the ID from the Pricing page, or list the IDs with GET /v1/models. When a Catalog ID is close to yours, the message suggests it.
  • If you did not choose the ID, your tool sent its own default: set the model in the tool’s config (see “My tool says the model was not found”).

model_not_allowed

HTTP 403Anthropic format: permission_error

The API Key is restricted to a list of models, and this model is not on the list.

How to fix it

  • On the API Keys page, open the key’s settings and add the model, or clear the list to allow every model.
  • Or send the Request with another key.
  • A change reaches the gateway within 15 seconds.

spend_limit_exceeded

HTTP 403Anthropic format: permission_error

The API Key reached its daily, monthly or total Spend Limit; the message says which. Amounts held for running Requests count toward the limit.

How to fix it

  • Raise or remove the limit in the key’s settings on the API Keys page.
  • Or wait: a daily limit starts again at 00:00 UTC, a monthly limit on the first day of the month (UTC). A total limit never resets.
  • Or send the Request with another key.
  • Near the limit, a smaller max_tokens holds less and may still fit.

insufficient_balance

HTTP 402Anthropic format: invalid_request_error

Your available Balance is lower than the most this Request could cost. The message states both amounts.

How to fix it

  • Add Balance on the Balance page.
  • Send a smaller max_tokens: the amount needed is the worst case for your prompt and your output limit.
  • If other Requests are running, wait for them to finish. The amounts held for them are released.
  • Check with GET /v1/balance: available is what a new Request can use, reserved is held for running ones.

rate_limit_exceeded

HTTP 429Anthropic format: rate_limit_error

The API Key went over its rate limit. By default that is 60 Requests per minute, or 5 running at once.

How to fix it

  • Wait the number of seconds in the Retry-After header, then retry.
  • Run fewer Requests in parallel, for example fewer sub-agents.
  • If you need a higher limit, write to support@centrouter.com.

invalid_request

HTTP 400Anthropic format: invalid_request_error

The body is not valid JSON, a field is missing or wrong for this endpoint, or the model rejected the request. The message names the field or the status. You were not charged.

How to fix it

  • Correct the field the message names. Chat Completions and Responses follow the OpenAI format; Messages follows the Anthropic format.
  • If the model rejected the request, check that it supports what you sent (images, tools, reasoning: see its tags on the Pricing page) and that the prompt fits its context length.

upstream_error

HTTP 502Anthropic format: api_error

No model source could answer, or the answer could not be read. You were not charged.

How to fix it

  • Retry after a moment.
  • Check the model on the Status page.
  • Try the other format’s endpoint, or another model. A model can be offered in the OpenAI format only, or in the Anthropic format only.
  • If it keeps failing, write to support@centrouter.com with the x-request-id of a failed response.

upstream_rate_limited

HTTP 429Anthropic format: overloaded_error

The model’s sources are limiting requests right now. You were not charged.

How to fix it

  • Retry after a short wait, and wait longer between further retries.
  • If it continues, use another model for now and check the Status page.

request_too_large

HTTP 413Anthropic format: request_too_large

The request body is over 32 MB, usually because of large images or files. It was refused before reaching a model. You were not charged.

How to fix it

  • Send fewer or smaller images (resize or compress them) or split the work over several Requests.
  • Images sent as URLs instead of base64 keep the body small.

Spend Limits

Each API Key can have a daily, monthly and total Spend Limit, and a list of models it may call. The lower of a Spend Limit and your Balance wins, so a leaked key can only spend what you allowed. Set them on the API Keys page; periods are UTC days and months.

API features

The gateway passes your request to the model as you wrote it and bills the Tokens the model’s provider reports. These features work as the model’s own API documents them.

Tool calling
Send tools as usual (OpenAI tools / tool_choice, Anthropic tools). They pass through unchanged; tool calls and their arguments are output Tokens. Models that support tools carry the Tools tag on the Models page.
Images (vision)
Send images as image_url parts (OpenAI) or image blocks (Anthropic) to models with the Vision tag. A request body may be up to 32 MB; image URLs keep it small.
Prompt caching
Cache reads cost the cache price on the Models page, far below input. Anthropic-format requests mark what to cache with cache_control; OpenAI-format models cache long repeated prefixes on their own where they support it. Activity shows each Request as input · cache · output.
Reasoning
Pass reasoning settings as the model documents them (reasoning_effort, thinking). Reasoning Tokens are part of output and billed as output; Activity shows them separately so you can see what they cost.
Output limit and the hold
Without max_tokens a Request may write up to the model’s max output, and the gateway holds enough Balance for that while it runs; the unused part returns as soon as it ends. Each model’s details show that minimum. Set max_tokens to hold less.
What you are charged
Tokens × the Sell Price, from the counts the model’s provider reports. Saved compares each Request with the OpenRouter Price. Prompts and replies are never stored, only Tokens and prices.

SDK examples

OpenAI SDK · Python
from openai import OpenAI

client = OpenAI(base_url="https://api.centrouter.com/v1", api_key="YOUR_API_KEY")
reply = client.chat.completions.create(
    model="gpt-6-luna",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(reply.choices[0].message.content)
OpenAI SDK · TypeScript
import OpenAI from 'openai'

const client = new OpenAI({ baseURL: 'https://api.centrouter.com/v1', apiKey: 'YOUR_API_KEY' })
const reply = await client.chat.completions.create({
  model: 'gpt-6-luna',
  messages: [{ role: 'user', content: 'Hello!' }]
})
console.log(reply.choices[0].message.content)
Anthropic SDK · Python
from anthropic import Anthropic

client = Anthropic(base_url="https://api.centrouter.com", api_key="YOUR_API_KEY")
reply = client.messages.create(
    model="gpt-6-luna",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}],
)
print(next(block.text for block in reply.content if block.type == "text"))
Anthropic SDK · TypeScript
import Anthropic from '@anthropic-ai/sdk'

const client = new Anthropic({ baseURL: 'https://api.centrouter.com', apiKey: 'YOUR_API_KEY' })
const reply = await client.messages.create({
  model: 'gpt-6-luna',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello!' }]
})
const text = reply.content.find(block => block.type === 'text')
console.log(text?.type === 'text' ? text.text : '')

CLI

The CLI logs in through your browser and writes the config for Claude Code, Codex or OpenCode.

Log in once (opens a browser approval page)
npx centrouter login
Configure a tool
npx centrouter setup claude
npx centrouter setup codex
npx centrouter setup opencode
Check your Balance and models
npx centrouter balance
npx centrouter models

For coding agents

Point your coding agent at llms.txt: it describes the service, the endpoints and the model list in plain text, with a prompt that lets the agent configure itself.

Open llms.txt