ThinkAPI / Developer docs

API docs

Connect official clients or plain HTTP requests to ThinkAPI through https://api.thinkapi.org. This page covers base URLs, authentication, endpoints, error codes, billing, and troubleshooting.

Quick start

  1. Sign up, sign in, and add funds on Billing. Model requests need an account balance above zero.
  2. Create a key on API keys and choose a service group. The group decides which models the key can use, what they cost, and which clients are allowed. See Models & pricing for details.
  3. Configure your client as described in Client setup: Anthropic-style clients such as Claude Code use https://api.thinkapi.org, and OpenAI-compatible clients such as Codex use https://api.thinkapi.org/v1. Once signed in, you can also check your settings in Connection setup.
  4. After sending a request, save the X-Request-Id response header. In the Portal, open /app/requests/{request_id} (replace {request_id} with that value) to confirm the outcome and cost, or find the request by time and model in Requests.

Base URLs and authentication

Every endpoint is served from one gateway at https://api.thinkapi.org and authenticated with an API key created in the Portal.

Base URLs

Base URL by client type
Client typeBase URLPaths the client appends
Anthropic-style clients and SDKs, such as Claude Codehttps://api.thinkapi.org/v1/messages
OpenAI-compatible clients and SDKs, such as Codexhttps://api.thinkapi.org/v1/responses, /chat/completions, and so on

Stick to these two forms. Keep /v1 for OpenAI-compatible clients: without it, /chat/completions, /responses, /images/generations, and GET /models still work, but /embeddings returns 404 unknown_route. Anthropic-style clients add /v1 on their own, so a base URL that already ends in /v1 doubles the segment and also returns 404.

Authentication

Use a key created on the API keys page; your Portal sign-in session does not work for API requests. Recommended headers by protocol:

Recommended authentication headers by protocol
ProtocolRecommended headers
OpenAI (Chat Completions, Responses, Embeddings, Images)Authorization: Bearer <key>
Anthropic Messagesx-api-key: <key>, plus anthropic-version: 2023-06-01
Balance and model listAuthorization: Bearer <key>

These are recommendations, not requirements: the gateway accepts the same set of authentication headers on every endpoint. With an official client, keep its default behavior.

  • Only Authorization strips a Bearer prefix. Adding Bearer to x-api-key or any other header returns 401 invalid_api_key.
  • Do not put your key in URL query parameters; proxies and access logs record URLs.
  • The gateway sends no CORS headers, and browser OPTIONS preflight requests get a 404. Call the API from your server, and never ship your key in front-end code.
  • Keys look like sk-ThinkAPI_…, though older keys may use another format. You can usually copy a key again from the API keys page; some older keys cannot be revealed, so create a new key if you need the full value. Keep your keys private, and disable or delete a key right away if it leaks.

Check your balance

The two self-check commands in this section and the next are free and confirm that your key and base URL are correct. First store your key in the THINKAPI_KEY environment variable, as Connection setup does:

macOS / Linux
export THINKAPI_KEY='<your-api-key>'
Windows PowerShell
$env:THINKAPI_KEY = '<your-api-key>'

GET /v1/usage returns the amount you can currently spend and this key's credit usage. It works even for a key that has reached its credit limit.

macOS / Linux
curl -sS "https://api.thinkapi.org/v1/usage" \
  -H "Authorization: Bearer $THINKAPI_KEY"
Windows PowerShell
$headers = @{ Authorization = "Bearer $env:THINKAPI_KEY" }
Invoke-RestMethod -Uri "https://api.thinkapi.org/v1/usage" -Headers $headers | ConvertTo-Json -Depth 5
Example response
{
  "balance": 12.5,
  "isValid": true,
  "is_active": true,
  "key": {
    "limited": true,
    "quota_micros": 20000000,
    "remaining_micros": 12500000,
    "used_micros": 7500000
  },
  "quota": {
    "remaining": 12.5,
    "unit": "USD"
  },
  "remaining": 12.5,
  "unit": "USD"
}
  • remaining, balance, and quota.remaining hold the same amount: what you can spend right now, in the currency given by unit (your account currency, USD by default). If the key has a credit limit, this is the lower of your account balance and the key's remaining credit; otherwise it equals your account balance, shown as 0 when the balance is negative.
  • key.limited: whether this key has a credit limit.
  • key.quota_micros, key.used_micros, and key.remaining_micros: the key's credit limit, amount used, and credit remaining, in micros (1,000,000 micros = 1 currency unit). Without a credit limit, key.remaining_micros is 0, which does not mean nothing is left.
  • Responses from this endpoint do not include X-Request-Id.

List models

GET /v1/models lists the models currently available to this key's service group. It uses the THINKAPI_KEY variable set above.

macOS / Linux
curl -sS "https://api.thinkapi.org/v1/models" \
  -H "Authorization: Bearer $THINKAPI_KEY"
Windows PowerShell
$headers = @{ Authorization = "Bearer $env:THINKAPI_KEY" }
(Invoke-RestMethod -Uri "https://api.thinkapi.org/v1/models" -Headers $headers).data | Select-Object id, owned_by
Example response
{
  "object": "list",
  "data": [
    {
      "id": "<model-id>",
      "object": "model",
      "owned_by": "anthropic",
      "display_name": "<model name>"
    }
  ]
}
  • The format does not depend on the protocol you use: it is always the OpenAI-style list above. owned_by, display_name, and description may be omitted.
  • Results are filtered by the key's service group, so moving the key to another group changes the list. See Models & pricing for prices and supported protocols.
  • It is free and works even when your account balance is negative.
  • It lists the models the platform has synchronized and enabled. It does not query upstream providers, so it answers quickly, and it reflects the platform's latest synchronization rather than live upstream state, so do not use it as a health check. If the model list cannot be read, it returns 502 models_unavailable.

Client setup

This section shows how to connect the official Claude Code and Codex clients to ThinkAPI, and how to import the settings from the Portal in one step with CC Switch. Check the Client access field in the model's details on Models & pricing, then pick a setup from the table below.

Choosing a setup by client
ClientRecommended setupGroups it works with
Claude Code (CLI, JetBrains plugin, VS Code extension, desktop app)Set the gateway URL and API key; for the CLI, put them in ~/.claude/settings.json. See Claude Code: recommended setupNative client, Standard API
Codex (CLI, IDE extension)Option 1: point the built-in provider at ThinkAPI and sign in with your API key. See option 1Native client, Standard API
Codex, keeping your ChatGPT sign-inOption 2: a custom provider. See option 2Native client, Standard API (switch to option 1 on 403 non_client_disabled)
CC Switch for Claude CodeChoose Import to CC Switch in the Portal. See One-click import with CC SwitchNative client, Standard API
CC Switch for CodexChoose Import to CC Switch in the Portal. See importing into CodexNative client, Standard API

The last column refers to the Client access field in a model's details. Groups marked Native client accept only official clients; groups marked Standard API also accept other requests that follow the protocol; for Unconfirmed, contact support first. See Client restrictions by group.

Claude Code: recommended setup

Claude Code connects through two environment variables: set ANTHROPIC_BASE_URL to https://api.thinkapi.org and ANTHROPIC_AUTH_TOKEN to your API key. Do not add /v1 to the URL: Claude Code appends /v1/messages itself, so another /v1 duplicates the path and returns 404.

Where each Claude Code surface is configured
SurfaceWhere to configureSupported
Claude Code CLIThe env block in ~/.claude/settings.json (recommended), or shell environment variablesYes
JetBrains pluginThe plugin runs the CLI, so it uses the CLI settingsYes
VS Code extensionclaudeCode.environmentVariables in your VS Code user settings; see other surfacesYes
Code tab in the Claude desktop appHelp → Troubleshooting → Enable Developer Mode, then Developer → Configure Third-Party Inference; see other surfacesYes
Claude Code on the web (claude.ai/code), mobile, Slack, Remote ControlWeb, mobile and Slack always use Anthropic's own service; Remote Control needs a claude.ai sign-in and is unavailable once the gateway is setNo

We recommend putting both in your user settings file, ~/.claude/settings.json (%USERPROFILE%\.claude\settings.json on Windows). If the file already exists, merge the two keys into its env block instead of replacing your other settings. Save it and start a new Claude Code session.

~/.claude/settings.json
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.thinkapi.org",
    "ANTHROPIC_AUTH_TOKEN": "sk-ThinkAPI_xxxxxxxx"
  }
}

Why this setup:

  • Values in a settings file's env block take precedence over shell variables of the same name, and background agents may not inherit shell variables, while the settings file reaches them too.
  • ANTHROPIC_AUTH_TOKEN is sent as an Authorization: Bearer header and takes effect without a confirmation prompt.
  • You can use ANTHROPIC_API_KEY instead. It is sent as an x-api-key header, which the gateway also accepts, but interactive mode asks you to approve it once.
  • Do not put your key in a project's .claude/settings.json; that file is usually committed to the repository.
  • A project's .claude/settings.json and .claude/settings.local.json, and managed settings from your administrator, take precedence over user settings, so leftover variables such as ANTHROPIC_BASE_URL there override yours. Use /status to see the URL and credential in effect.

Claude Code: environment variables, VS Code and desktop

To try it in the current terminal only, set environment variables as the official docs show. They last for that terminal session, and values in a settings file override them.

macOS / Linux
export ANTHROPIC_BASE_URL=https://api.thinkapi.org
export ANTHROPIC_AUTH_TOKEN=sk-ThinkAPI_xxxxxxxx
claude
Windows PowerShell
$env:ANTHROPIC_BASE_URL = "https://api.thinkapi.org"
$env:ANTHROPIC_AUTH_TOKEN = "sk-ThinkAPI_xxxxxxxx"
claude

VS Code extension: run Preferences: Open User Settings (JSON) from the Command Palette and add claudeCode.environmentVariables. The extension's own sign-in check does not read ~/.claude/settings.json, so with only that file it may still ask you to sign in.

VS Code user settings
{
  "claudeCode.environmentVariables": [
    { "name": "ANTHROPIC_BASE_URL", "value": "https://api.thinkapi.org" },
    { "name": "ANTHROPIC_AUTH_TOKEN", "value": "sk-ThinkAPI_xxxxxxxx" }
  ]
}

The Code tab in the Claude desktop app does not take its gateway settings from ANTHROPIC_BASE_URL or ~/.claude/settings.json. Open Help → Troubleshooting → Enable Developer Mode, then Developer → Configure Third-Party Inference. In Connection, set Inference provider to Gateway, enter https://api.thinkapi.org as the Gateway base URL and your API key as the Gateway API key, and leave the rest at their defaults. If your administrator has distributed a configuration, the form is read-only.

Claude Code: choosing a model

Claude Code does not switch to your group's models on its own, and its default model may not be in your group. Choose a model in one of these ways, copying the model ID exactly as shown on Models & pricing or returned by List models:

  • Run /model in a session and pick or enter the model ID.
  • Pass it at startup: claude --model <model-id>.
  • Make it the default: add ANTHROPIC_MODEL to the env block in ~/.claude/settings.json, as in the example below. If CC Switch manages that file, edit the provider in CC Switch instead; see Importing into Claude Code.

Optional: set CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY to 1, and Claude Code asks the gateway for your group's models at startup and adds them to the /model list. Note that:

  • Only models whose ID contains claude or anthropic are listed.
  • The gateway answers from the models the platform has synchronized, usually well within the default 3-second timeout. On a timeout, Claude Code silently falls back to the previously cached list or its built-in list; on a slow network, raise the timeout with CLAUDE_CODE_GATEWAY_MODEL_DISCOVERY_TIMEOUT_MS (in milliseconds; requires Claude Code v2.1.269 or later).
  • It only adds entries; it does not change the default model.
~/.claude/settings.json (choosing a model)
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.thinkapi.org",
    "ANTHROPIC_AUTH_TOKEN": "sk-ThinkAPI_xxxxxxxx",
    "ANTHROPIC_MODEL": "<model-id>",
    "CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY": "1",
    "CLAUDE_CODE_GATEWAY_MODEL_DISCOVERY_TIMEOUT_MS": "10000"
  }
}

Model IDs with a [1m] suffix, such as <model-id>[1m], also work, and Requests shows the ID without the suffix. Whether you actually get a 1M-token context depends on the model, group and upstream provider, and is not guaranteed.

Claude Code: checking the setup

  1. Run /status in Claude Code and check that it shows an "Anthropic base URL" line with https://api.thinkapi.org and an "Auth token" line.
  2. Send a real message, then find the request by time and model in Requests and check its status and cost.

Common errors: 403 non_client_disabled (shown as "Please upgrade your Claude client."), 400 unsupported_client_platform, and 400 unsupported_client_feature or unsupported_client_profile are covered in Client restrictions by group. For 401 (invalid key) and 402 (insufficient balance), see Error codes.

Codex: surfaces and setup options

This applies to the Codex CLI and the Codex IDE extension (openai.chatgpt) in VS Code, Cursor and Windsurf. Codex in the ChatGPT desktop app reads the same configuration. Codex cloud, /cloud delegation and Realtime voice do not go through ThinkAPI.

Put the settings in your user-level ~/.codex/config.toml (%USERPROFILE%\.codex\config.toml on Windows; a CLI running in WSL uses the Linux ~/.codex, which is not shared with Windows). Provider-related keys in a project's .codex/config.toml are ignored, so do not put them there. Top-level keys such as model must come before any table header, such as [model_providers.thinkapi].

Two ways to connect Codex
OptionHow it worksGroups it works withChatGPT sign-in
Option 1 (recommended)Point the built-in provider at ThinkAPI with openai_base_url and sign in with your API keyNative client, Standard APITurned off on this machine (for that CODEX_HOME)
Option 2A custom thinkapi provider that reads the key from the THINKAPI_KEY environment variableNative client, Standard API (switch to option 1 on 403 non_client_disabled)Both can be used side by side

If in doubt, use option 1. Both options need the model ID filled in by hand; see Codex: models, checks and troubleshooting.

Codex option 1: API key sign-in

Add these three lines at the top of ~/.codex/config.toml, before any table header. If the file already has a model, openai_base_url or forced_login_method line, change its value instead of adding another line; a duplicate key stops Codex from starting. If you have ever picked a model with /model, the file usually has a model line already.

~/.codex/config.toml
model = "<model-id>"
openai_base_url = "https://api.thinkapi.org/v1"
forced_login_method = "api"

Then sign in with your API key. Store the key in the THINKAPI_KEY environment variable as shown in Check your balance, then run:

macOS / Linux
printenv THINKAPI_KEY | codex login --with-api-key
Windows PowerShell
$Env:THINKAPI_KEY | codex login --with-api-key

The official docs have no PowerShell example; this version passes the key through standard input in the same way. If you see No API key provided via stdin., THINKAPI_KEY is empty. You can also sign in without the command line: in the IDE extension, choose "Use API Key" on the sign-in screen; in the desktop app, choose "Sign in another way"; then paste your key.

To keep your ChatGPT sign-in in the CLI as well, create a separate directory for ThinkAPI to use as CODEX_HOME (the directory must already exist), put the three lines above in the config.toml inside it, sign in with that CODEX_HOME, and pass it every time you start Codex. In this setup, leave ~/.codex/config.toml unchanged; Codex started without CODEX_HOME keeps using your ChatGPT sign-in. In Windows PowerShell, create the directory, run $Env:CODEX_HOME = "$HOME\.codex-thinkapi", then sign in and start Codex in the same terminal (the variable lasts only for that session).

macOS / Linux: separate CODEX_HOME
mkdir -p ~/.codex-thinkapi
# Put the three lines above in ~/.codex-thinkapi/config.toml, then sign in once:
printenv THINKAPI_KEY | CODEX_HOME="$HOME/.codex-thinkapi" codex login --with-api-key

# Start Codex with ThinkAPI; add this prefix every time, or save it as an alias:
CODEX_HOME="$HOME/.codex-thinkapi" codex
  • Do not leave out forced_login_method = "api"; without it, a cached ChatGPT sign-in token would be sent to the gateway.
  • A red "OpenAI base URL is overridden …" warning when you open /model in Codex is expected. That list shows Codex's built-in models, not the models in your group. Do not pick from it: your choice is saved to model in config.toml and replaces the model ID you entered. To switch models for one run, use codex -m <model-id>.
  • See Codex authentication in the official docs.

Codex option 2: custom provider

Option 2 leaves your Codex sign-in alone, so it can coexist with a ChatGPT subscription sign-in. Add the following to ~/.codex/config.toml:

~/.codex/config.toml
model = "<model-id>"
model_provider = "thinkapi"

[model_providers.thinkapi]
name = "ThinkAPI"
base_url = "https://api.thinkapi.org/v1"
env_key = "THINKAPI_KEY"
wire_api = "responses"
  • model and model_provider are top-level keys and must come before any table header. If the file already has a model or model_provider line, change its value instead of adding another line; a duplicate key stops Codex from starting.
  • You do not need codex login, and do not add requires_openai_auth. codex login status showing Not logged in is expected.
  • To go back to ChatGPT, delete the top-level model_provider and model lines; your sign-in is untouched.

Codex reads the key from the THINKAPI_KEY environment variable. On macOS or Linux, add it to your shell startup file; on Windows, set a user environment variable:

macOS / Linux
# Add to ~/.zshrc (zsh) or ~/.bashrc (bash), then open a new terminal
export THINKAPI_KEY="sk-ThinkAPI_xxxxxxxx"
Windows PowerShell
# Saved for your Windows user; takes effect in new terminals
[Environment]::SetEnvironmentVariable('THINKAPI_KEY', 'sk-ThinkAPI_xxxxxxxx', 'User')

# Current PowerShell session only
$Env:THINKAPI_KEY = 'sk-ThinkAPI_xxxxxxxx'

The IDE extension and desktop app may not see shell variables. In that case, put the key in ~/.codex/.env (%USERPROFILE%\.codex\.env on Windows) and restart the editor or desktop app:

~/.codex/.env
THINKAPI_KEY=sk-ThinkAPI_xxxxxxxx
  • .env is plain text; never commit or share it.
  • Values in .env override shell variables of the same name, and variable names starting with CODEX_ are ignored.
  • For more, see Codex advanced configuration in the official docs.

Codex: models, checks and troubleshooting

With either option, fill in model with a model ID from your group, copied exactly from Models & pricing or List models. Codex does not read the gateway's model list, so the startup notice "Model metadata for <model-id> not found. Defaulting to fallback metadata" means the ID is not in Codex's built-in model catalog and Codex falls back to default model settings.

  • To switch models for one run: codex -m <model-id>. Do not switch with /model: it lists Codex's built-in models, and your choice is saved to config.toml, replacing the model you entered.
  • Newer models may require a recent Codex version, so keep Codex on the latest release.

By default Codex passes its environment variables, including THINKAPI_KEY, to the commands it runs. To prevent that, add the filter below to ~/.codex/config.toml (do not also use the older exclude or include_only arrays in the same file; Codex rejects that combination):

~/.codex/config.toml
[shell_environment_policy.filters]
"THINKAPI_KEY" = "exclude"

To check the setup with option 1, first run this command in a terminal; it should show Logged in using an API key.

Terminal (option 1 only)
codex login status

Then start Codex and run /status to check the Model and Model provider entries: openai for option 1, thinkapi for option 2.

Type in Codex
/status

The real test is sending a message and finding the request in Requests. Codex does not show the X-Request-Id. Option 1 sends over WebSocket by default; each turn still appears in Requests but has no request ID returned to the client. Find the request by time and model.

When troubleshooting:

  • Start Codex with codex --strict-config to have unknown configuration keys reported as errors, which catches typos. A configuration imported by CC Switch may contain keys Codex no longer recognizes, such as disable_response_storage, and they are reported too. Such keys do not affect a normal start without --strict-config, so you can ignore that error or delete the line.
  • Do not set an OPENAI_BASE_URL environment variable; current Codex versions do not read it.
  • Do not write wire_api = "chat"; that value has been removed and causes a configuration error.
  • Do not write [model_providers.openai]: built-in providers cannot be overridden, and Codex fails to start with "model_providers contains reserved built-in provider IDs".
  • Do not use [profiles.<name>]; Codex stopped reading it in 0.134.0.
  • Do not point model_catalog_url at the gateway; its model list format is not compatible with Codex.
  • On managed work computers, an administrator may restrict sign-in methods or settings, in which case option 1 may not be available.

One-click import with CC Switch

CC Switch is a desktop app that manages provider settings for Claude Code, Codex and other clients. The Portal can hand it your base URL and API key through a ccswitch:// link, so you do not have to edit configuration files by hand.

  • Install: download it from GitHub Releases or the official site, ccswitch.io. On macOS you can also run brew install --cask cc-switch.
  • Version: v3.16.0 or later is required, or the Portal's Claude Code options are lost on import. The latest release is recommended.
  • Key: its status must be Ready and it must be revealable. If an older key says it cannot be revealed, create a new one.
  • Group: the key must belong to a Claude or an OpenAI / Codex group, which imports into CC Switch's Claude or Codex panel respectively.

Start the import from either place:

  • On API keys, choose Setup on the key, then Import to CC Switch. Pick the API URL and options in the dialog, then choose Import to CC Switch.
  • In Connection setup, set Client to Native client in step 01, then choose Import to CC Switch in step 02.

Then:

  1. Allow your browser to open CC Switch when it asks.
  2. Review the name, endpoint and configuration in CC Switch's import confirmation dialog, then choose Import.
  3. In CC Switch's Claude or Codex panel, choose Enable on the newly imported provider card. The Portal does not enable it for you; it is enabled automatically only if it is the first provider in that panel.
  4. Start a new Claude Code session, or restart Codex.

CC Switch: importing into Claude Code

For a key in a Claude group, CC Switch writes ANTHROPIC_BASE_URL (https://api.thinkapi.org) and ANTHROPIC_AUTH_TOKEN to ~/.claude/settings.json, the same as the recommended setup. The four options under Claude Code settings in the dialog are all checked by default:

Claude Code import options
OptionWhat it does
Enable 1-hour cachingRequests 1-hour prompt caching. Writes to the 1-hour cache are billed at a separate rate, usually higher than regular cache writes. The price table in a model's details does not list it separately and only notes that the model has additional pricing dimensions; the settled amount in Requests is final.
Discover available modelsQueries the gateway for your group's models at startup and adds them to the /model list without changing the default model, and the Portal does not set a default model for you either. Choose one in Claude Code with /model or claude --model; see Choosing a model. To set a default, edit the provider in CC Switch and add ANTHROPIC_MODEL to the env block of its configuration rather than editing ~/.claude/settings.json directly.
Disable ArtifactsTurns off the Artifact tool that publishes content to claude.ai.
Disable client telemetryTurns off client analytics, error reports and OpenTelemetry export. It also stops feature-flag fetching, so features that depend on it, such as starting in auto mode by default and skills sync, stop working, and Claude Code no longer leaves out MCP tools with an invalid input schema, so requests that include such a tool return 400 (Remote Control is already unavailable once the gateway is set). Whether to check it depends on whether you need these features.

The ~/.claude/settings.json that CC Switch writes applies to the Claude Code CLI and the JetBrains plugin. The VS Code extension still needs the same two variables in claudeCode.environmentVariables, and the Claude desktop app needs its own Third-Party Inference setup; see other surfaces.

CC Switch: importing into Codex

For a key in an OpenAI / Codex group, CC Switch writes a custom provider to ~/.codex/config.toml and saves the key in ~/.codex/auth.json. It also works with groups that accept only native clients, which has been confirmed in the ChatGPT client. If a client returns 403 non_client_disabled, set up option 1 by hand instead.

  • Unlike option 2, it does not coexist with a ChatGPT sign-in: enabling the provider makes CC Switch overwrite ~/.codex/auth.json with your ThinkAPI key, and your previous ChatGPT sign-in is not kept. To go back to ChatGPT, switch to the official login preset in CC Switch and sign in again.
  • The model is always set to gpt-5.5 with high reasoning effort, regardless of the model you chose in Connection setup, and requests fail if your group does not offer that model. After importing, edit the provider in CC Switch and change model in its config.toml (model_reasoning_effort is in the same place), or use codex -m <model-id> for one run.
  • The URL CC Switch writes has no trailing /v1, unlike the manual setup. Keep the imported value as is.
  • Restart Codex after changing its configuration.

CC Switch: balance and caveats

CC Switch refreshes the balance every 30 minutes through GET /v1/usage (see Check your balance), but only while that provider is the one currently enabled. It shows the lower of your account balance and the key's remaining credit.

  • When you enable or switch providers, CC Switch rewrites the whole of ~/.claude/settings.json, or ~/.codex/config.toml and auth.json, from that provider's settings plus its shared config, so other settings you added to the original file by hand, such as permissions or hooks, do not carry over. Back up the original files before you enable a provider, and keep settings you want in every provider in CC Switch's shared config snippet.
  • CC Switch ignores CLAUDE_CONFIG_DIR and CODEX_HOME. If you set either one, point CC Switch's configuration directory setting at the same path, or the import has no effect.
  • If Claude Code still does not pick up the import, check whether a project's .claude/settings.json or .claude/settings.local.json sets the same variables, and run /status in Claude Code to see the URL and credential in effect.
  • With groups that accept only native clients, let the client connect to the gateway directly and do not turn on CC Switch features that proxy requests.

If nothing happens when you choose Import to CC Switch, make sure CC Switch is installed and registered for the ccswitch:// protocol. On macOS, run this command to register it again:

macOS
/usr/bin/open -a "CC Switch" --args --register-protocol

Client restrictions by group

Open a model's details on Models & pricing; the Client access field shows what the group requires. Native client means only official clients are accepted; Standard API means other requests that follow the protocol are accepted too; Unconfirmed means compatibility is not settled yet, so contact support first. The field is a guide, and actual request results take precedence.

In groups that accept only native clients:

  • Only the official Claude Code and Codex work, including setups imported with CC Switch. When configuring Codex by hand, option 1 is recommended.
  • Requests must be sent unmodified by the official client: do not change the User-Agent or other headers, and do not route through proxies or third-party tools that rewrite headers.
  • Use a recent official release.
  • The online test in Connection setup is not available. Make a real request from your client, then find it by time and model in Requests (Claude Code and Codex do not show the X-Request-Id, and Codex uses WebSocket by default). To check it in step 03 of Connection setup, copy the request ID from the request details and select the same key, group and model in step 01.
Client errors
CodeWhat you seeWhat to do
non_client_disabled (403)Claude Code shows "Please upgrade your Claude client." and Codex shows "Unknown client is not supported." It is not only about old versions: usually the request was not recognized as coming from an official client, for example because the User-Agent or headers were changed, or it went through a proxy or third-party tool.Connect directly with an unmodified, current official release; switch Codex to option 1; or use a Standard API group.
unsupported_client_platform (400)The group does not support your operating system. Claude Code shows the same "Please upgrade your Claude client." message, but the version is not the cause.Use a group that supports your operating system, or open a ticket.
unsupported_client_feature (400)While rebuilding the request in the Claude client's format, the gateway found a field it does not support yet or that does not meet the format's requirements. The message names the field path (such as thinking.display). Both third-party requests and official clients can hit this; for official clients it is most common right after a new release.Retrying unchanged will not help. For a third-party request, change or remove the field the message names. For an official client, note the time, your client version, and the X-Request-Id if you have one, then open a ticket.
unsupported_client_profile (400)The target client configuration the platform set for your group or its upstream credentials cannot currently be used to rebuild this request. Your local client version is not the cause.Retrying unchanged will not help, and neither will upgrading or downgrading your client. Note the time and the X-Request-Id if you have one, then open a ticket.
external_client_scope_blocked (403)Requests from this client are blocked for this key; other clients and keys are unaffected.Use the official native client instead. To have the block lifted, open a ticket.
unsupported_client (403)The platform does not support this client ("This client is not supported.").Switch to a supported client; retrying unchanged will not help.

See Error codes for the full list.

Endpoint reference

All paths are relative to https://api.thinkapi.org. The protocols shown in a model's details on Models & pricing are a guide to how to call it; if your group has cross-protocol translation turned on, other protocols may work too, as described below.

Endpoints served by the gateway
ProtocolMethod and pathStreaming
Anthropic MessagesPOST /v1/messagesSet "stream": true in the body
Anthropic token countingPOST /v1/messages/count_tokens—
OpenAI Chat CompletionsPOST /v1/chat/completionsSet "stream": true in the body
OpenAI ResponsesPOST /v1/responsesSet "stream": true in the body
OpenAI Responses token counting (gateway estimate)POST /v1/responses/input_tokens—
OpenAI Responses compactionPOST /v1/responses/compactNot supported; always JSON
OpenAI Responses WebSocketGET /v1/responses with Upgrade: websocketSee Responses WebSocket
OpenAI EmbeddingsPOST /v1/embeddings—
OpenAI ImagesPOST /v1/images/generationsNot supported; returns 400 unsupported_image_streaming
Model listGET /v1/models—
Codex standalone searchPOST /v1/alpha/search—
BalanceGET /v1/usage—

When the Codex client calls GET /v1/models it adds client_version, and the reply uses Codex's model manifest format; without it you get the usual OpenAI list format. A model ID can carry a reasoning-effort suffix: <model>-high calls <model> with the reasoning effort set to high (an effort set in the request still wins). This only applies when the suffixed name is not itself an available model.

Whether you can call a model through another protocol's endpoint depends on whether your service group has cross-protocol translation set up for it. If a request needs translation and the group does not allow it, you get 403 translate_disabled. Protocol-specific fields and streaming events are not guaranteed to translate exactly, and parameters that cannot be translated return 400 unsupported_parameter.

Unsupported endpoints

Sub-resource endpoints such as GET /v1/models/{id}, GET /v1/responses/{id}, and /v1/messages/batches are not supported. They, like any other path the gateway does not recognize, return 404 unknown_route.

Responses WebSocket

Send a GET request to /v1/responses with Upgrade: websocket to open a WebSocket connection. The handshake checks your key and account balance, and failures come back as ordinary HTTP errors.

  • Send {"type":"response.create", ...} to start a turn; apart from type, the fields match the POST /v1/responses request body. Send {"type":"response.cancel"} to cancel the current turn.
  • The server sends each Responses streaming event as a JSON frame. Every turn ends with a response.completed, response.incomplete, response.failed, or error event.
  • Each connection handles turns one at a time. While a turn is running, one more can wait in the queue; further requests return 429 response_queue_full.
  • Every turn is authenticated, rate limited, and billed separately. A failed turn returns an error frame shaped like {"type":"error","status":N,"error":{...}}, and the connection stays open.
  • A single frame can be up to 32 MiB; a larger frame closes the connection.
  • Cross-origin browser connections are rejected based on their Origin header.
  • Individual turns do not expose an X-Request-Id. For troubleshooting, note the time (with time zone) and the key name.

Response headers

Gateway response headers
HeaderDescription
X-Request-IdThe ID of this request, 32 hexadecimal characters. Open /app/requests/{request_id} in the Portal to see the request, and include the ID in support tickets. Header names are case-insensitive; if two values appear, use the first.
X-ThinkAPI-Error-CodeThe error code. It appears only on some errors, mainly when the error body is in the upstream provider's format.
X-ThinkAPI-Error-ActionSent with the error code to suggest what to do next, such as correct_request (fix the request) or restore_history (restore the full conversation history or start a new session).
X-Should-Retry: falseThe gateway advises against automatic retries. Handle the error based on its code.
Retry-AfterThe minimum number of seconds to wait before retrying, calculated by the gateway from current limits.
X-ThinkAPI-Local-ProbeThe gateway answered the request itself. It was not sent to a model and is not billed.
X-Accel-Buffering: noSent on streaming responses to tell intermediate proxies not to buffer.
Other headersUpstream response headers are passed through. Which ones appear is not guaranteed.

Errors and rate limits

Every error comes with an HTTP status and an error code. Learn the error body formats first, then look up the code below.

Error formats

Error bodies come in two formats. When the gateway rejects a request itself, the format is the same whichever protocol you call:

Gateway error
{
  "error": {
    "type": "Unauthorized",
    "code": "invalid_api_key",
    "message": "The API key is not valid."
  }
}

error.type is the HTTP status phrase. Limit errors such as 429 user_rpm_exceeded also include error.reason and error.details.

When you call a model through its own protocol, request errors (4xx) from the upstream provider keep the provider's original status and body. For example, with Anthropic Messages:

Upstream format (Anthropic)
{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "<upstream error message>"
  }
}

These responses carry X-Should-Retry: false, X-ThinkAPI-Error-Code (for example invalid_request_error), and X-ThinkAPI-Error-Action (for example correct_request). With cross-protocol translation, upstream errors are converted to the format of the protocol you called, and their type fields are not the provider's original values.

Identifying errors

  • Identify errors by the HTTP status plus error.code. Do not rely on error.type.
  • When the body is in the upstream format, error.code may be missing or hold the provider's own value, so check the X-ThinkAPI-Error-Code header instead. That header appears only on some errors; when it is absent, go by error.code.
  • One status can have different causes. A 429, for example, may mean your account hit a rate limit, the platform is protecting capacity, or the key reached its credit limit, and each calls for a different response.
  • A misspelled or unavailable model can return 403 model_not_allowed, 400 model_not_supported or model_disabled, a 503 (such as no_account_available) or a 502, or an upstream 404 in the provider's own format (such as Anthropic's not_found_error). A 404 means the path does not exist only when the body is in the gateway format and error.code is unknown_route.

Error codes

The table lists common error codes and how to handle them. Filter by category to narrow it down.

All error codes (72)
StatusCodeMeaningWhat to do
401missing_api_keyAuthenticationThe request carried no API key, or put it somewhere the gateway does not look.Send Authorization: Bearer <key> for OpenAI protocols or x-api-key: <key> for Anthropic, and check that your client config or environment variable is actually loaded.
401invalid_api_keyAuthenticationThe gateway could not match the key ("The API key is not valid."). It may be truncated or deleted, or carry a Bearer prefix in a header other than Authorization.Copy the full key again from API keys. Only the Authorization header takes the Bearer prefix.
403api_key_disabledAuthenticationThis key has been disabled.Re-enable it in API keys, or use another active key.
403api_key_expiredAuthenticationThis key is past its expiry date.Re-enabling it does not extend the expiry. Create a new key in API keys and update your client.
403group_unavailableAuthenticationThe key's service group is unavailable: the key has no group, the group was disabled or removed, or you no longer have access to that dedicated group.Assign an available group to the key in API keys. For access to a dedicated group, open a ticket.
403user_unavailableAuthenticationThe account that owns this key is not active.Contact us to check your account status.
500authorization_failedAuthenticationThe gateway hit an internal error while checking the key ("Could not authorize the request."). It does not mean the key is wrong.Retry shortly. If it keeps happening, open a ticket with the time and the key name.
402insufficient_balanceBalance & creditYour account balance is zero or below, so new requests are refused; the message is a short notice in Chinese. All keys share the balance, and in-flight requests can push it below zero.Top up in Billing; requests work again once the balance is positive. Retrying alone will not help.
429api_key_quota_exhaustedBalance & creditThis key has used up its credit limit ("This API key has reached its usage limit."). The limit counts settled charges and is separate from your account balance.Retrying will not help, and a top-up does not reset key usage. Raise the credit limit in API keys or switch keys, and turn off automatic retries for this code.
429user_rpm_exceededRate limitsYour account hit its requests-per-minute (RPM) limit. Every API key on the account shares it, so switching keys will not get around it.Wait for Retry-After, then retry at a lower rate. Your limits are under API request limits in Settings; open a ticket to ask for a change.
429user_concurrency_exceededRate limitsYour account already has as many requests in flight as its maximum concurrency allows. All your keys share this limit too.Let in-flight requests finish and retry after Retry-After, or lower your client's concurrency. Your limit is shown in Settings.
503coordination_unavailableRate limitsThe gateway briefly could not check your account's RPM or concurrency limits ("Request limits could not be verified. Retry shortly."). Only accounts with such limits are affected.Retry shortly. If it persists, open a ticket.
403model_not_allowedModels & groupsThe group offers a fixed set of models, and the one you asked for is not among them ("The requested model is not enabled for this group.").Find the model IDs your group offers in Models & pricing or with GET /v1/models, and use one of those. For other models, move the key to another group.
400model_not_supportedModels & groupsThe key's group does not support the requested model.Use a model listed for your group in Models & pricing, or move the key to another group.
400model_disabledModels & groupsThe requested model is disabled ("The requested model is disabled in the provider catalog."). The same code appears when the endpoint does not match the group's protocol, so the model itself may be fine.Check the model ID, and make sure the request path matches a protocol shown in the model's details (see the endpoint list).
400provider_not_supportedModels & groupsThe key's group does not serve the endpoint you called.Call an endpoint for a protocol shown in the model's details, or move the key to another group.
403translate_disabledModels & groupsCalling this model through the current protocol needs cross-protocol translation, which the group has not enabled ("Cross-provider translation is not enabled for this group.").Call the model through a protocol shown in its details, or use a group with translation enabled.
400capability_unsupportedModels & groupsNothing serving this endpoint supports the requested operation ("No provider serving this route supports the requested operation."). This depends on the endpoint, not on the model you chose.Check the endpoint list and use an endpoint that supports the operation. If it persists, open a ticket.
503model_route_unavailableModels & groupsThe gateway briefly could not resolve this model's configuration ("Could not resolve the configured model route.").Retry shortly. If it persists, open a ticket.
403plan_excludes_modelModels & groupsThe upstream service behind your group does not include the selected model.Use another model or group. If you need this model, open a ticket.
400invalid_reasoning_effortModels & groupsThe reasoning effort is not one the gateway recognizes (none, minimal, low, medium, high, xhigh, max, adaptive, enabled); the message reads unsupported reasoning effort "...".Use one of the values above, or leave the reasoning effort out. When a model has a value disabled, you get reasoning_effort_disabled instead.
400reasoning_effort_disabledModels & groupsThat reasoning effort is disabled in your group ("The requested reasoning effort is disabled for every eligible model target.").Pick another reasoning effort, or leave it out.
403reasoning_effort_deniedModels & groupsThe group's request policy does not allow this reasoning effort: a mapping rule denies it, or it is above the group's limit and the limit is set to deny. The message reads like reasoning effort "xhigh" exceeds this group's limit of "high".Lower the reasoning effort, or leave it out.
403service_tier_not_allowedModels & groupsThe group's request policy does not allow the requested service_tier (for example priority). The message is the platform's explanation, or reads like service_tier=priority is not allowed for model gpt-5.5 when none is set.Drop service_tier, or use a value the message allows.
409 / 400response_chain_unavailableModels & groupsThe response that previous_response_id points to cannot be continued. A 409 means the upstream that produced it is gone; a 400 means it can no longer be replayed and the full input history is needed.Drop previous_response_id and send the full conversation history, or start a new conversation.
403non_client_disabledClientsThe group only accepts native clients, and this request did not come from a supported one. The message is "Unknown client is not supported." or "Please upgrade your Claude client."Despite the wording, this does not necessarily mean your client is out of date. Usually the request was not sent unmodified by an official client, for example because the User-Agent or headers were changed, or a proxy or third-party tool rewrote them. Connect directly with an unmodified, current release of Claude Code or Codex, or move to a group that allows standard API clients. See the Client access field in the model's details and client restrictions.
403unsupported_clientClientsThe platform does not support this client ("This client is not supported."). The request was not forwarded and is not billed.Switch to a supported client; retrying unchanged will not help. If you think this is a mistake, open a ticket.
403external_client_scope_blockedClientsRequests from this client are blocked for this key; other clients and keys are unaffected. This usually follows an upstream third_party_extra_usage_required response, and whether and when the block lifts depends on the group's settings.Use the official native client instead. To have the block lifted, open a ticket.
400unsupported_client_platformClientsThe upstream service behind your group does not support the operating system your client runs on (some groups support only macOS or only Windows; Linux counts as macOS). The message is the same as for non_client_disabled, so Claude Code also shows "Please upgrade your Claude client.", but the cause has nothing to do with the version.Use a group that supports your operating system, or open a ticket.
400unsupported_client_featureClientsWhile rebuilding the request in the Claude client's format, the gateway found a field it does not support yet or that does not meet the format's requirements. Both third-party requests and official clients can hit this. The message names the field path, such as thinking.display, tools[0].eager_input_streaming, or tools[0].type. For official clients it is most common right after a new release.Retrying unchanged will not help. For a third-party request, change or remove the field the message names. For an official client, note the time, your client version and the X-Request-Id if you have one, then open a ticket.
400unsupported_client_profileClientsThe target client configuration the platform set for your group or its upstream credentials cannot currently be used to rebuild this request. It has nothing to do with your local client version, and both official clients and third-party requests can hit it.Retrying unchanged will not help, and neither will upgrading or downgrading your client. Note the time and the X-Request-Id if you have one, then open a ticket.
503client_policy_unavailableClientsThe gateway briefly could not confirm whether your client is allowed.Retry later. If it keeps failing, open a ticket.
400third_party_extra_usage_requiredHeaderClientsThe upstream refused this third-party client request and asked for separately metered extra usage. The body is the upstream's own error, so identify it by the X-ThinkAPI-Error-Code header; X-ThinkAPI-Error-Action is check_extra_usage.Retrying unchanged will not help; switch to the official native client. Depending on the group's settings, this client may then be blocked for this key (external_client_scope_blocked).
429all_accounts_busyPlatform capacityThe group's platform capacity is momentarily full. This is platform-side capacity protection, not your own limit.Retry after Retry-After. If it persists, open a ticket.
429upstream_rate_limitedPlatform capacityThe upstream rate limits on the platform side are used up; this has nothing to do with your RPM.Retry after Retry-After. If it persists, open a ticket.
429upstream_usage_limit_reachedPlatform capacityThe platform's usage protection for this group has kicked in. The limit and used values in the items of details.reasons[], when present, are platform-side figures, not your credit.Retry after Retry-After. If it persists, open a ticket.
429upstream_quota_exhaustedPlatform capacityThe upstream quota on the platform side is temporarily exhausted.Retry later, waiting for Retry-After when it is present. If it persists, open a ticket.
503no_account_availablePlatform capacityThe group has no service capacity available right now. It is also the final code when upstream errors use up automatic failover. It can also mean no upstream in the group can serve the requested model, for example because the model ID is mistyped.First check that model is a model ID your group offers (Models & pricing or GET /v1/models). If it is, retry later (no Retry-After is sent) and check Service status. If it persists, open a ticket.
503quota_observation_unavailablePlatform capacityThe platform needs fresh capacity data before it can accept the request.Retry after Retry-After.
503model_access_unavailablePlatform capacityThe platform cannot currently confirm access to this model.Retry later or use another model. If it persists, open a ticket.
503coordinator_unavailablePlatform capacityThe gateway briefly cannot enforce platform-side concurrency controls ("Concurrency limits cannot be enforced right now. Retry shortly.").Retry after Retry-After.
500selection_failedPlatform capacityThe gateway hit an internal error while allocating capacity for the request. The message is "Please contact the administrator."Retry later. If it persists, open a ticket with the X-Request-Id.
502upstream_unavailableUpstream & timeoutsThe upstream kept failing after the gateway's automatic retries and failover. The message is a short normalized summary.Retry later and check Service status. If it persists, open a ticket with the X-Request-Id.
502upstream_attempt_budget_exhaustedUpstream & timeoutsThe request used up the gateway's upstream retry budget without succeeding ("The request exhausted its upstream retry budget.").Retry later. If it persists, open a ticket with the X-Request-Id.
502upstream_delivery_uncertainUpstream & timeoutsThe connection dropped before an upstream response arrived, so it is unclear whether the upstream ran the request ("The upstream connection ended before a response could be confirmed. Retry the request explicitly."). The gateway does not replay it, and this request is not billed.Decide for yourself whether to retry. A retry may run the request twice, so check first if it has side effects such as tool actions.
503upstream_overloadedUpstream & timeoutsEvery available upstream is temporarily overloaded ("the upstream is temporarily overloaded; retry shortly"), and the gateway already tried switching. The response carries Retry-After.Retry after Retry-After. If it persists, open a ticket.
504upstream_idle_timeoutUpstream & timeoutsThe upstream sent nothing for too long, so the gateway ended the request before sending response headers ("The upstream response was idle for too long. Retry the request."). If a stream had already started, it is cut off instead.You can retry. If it persists, open a ticket.
504upstream_first_output_timeoutUpstream & timeoutsWith first-output protection enabled on the platform (streaming requests only), the upstream produced no usable output in time. The request is not replayed.Retry yourself if needed; a retry may run the request twice.
502upstream_first_output_invalidUpstream & timeoutsWith first-output protection enabled on the platform, the upstream's first output was unusable. The request is not replayed.Retry yourself if needed; a retry may run the request twice.
502upstream_first_output_limitUpstream & timeoutsWith first-output protection enabled on the platform, the upstream's first output exceeded what the gateway can inspect. The request is not replayed.Retry yourself if needed; a retry may run the request twice.
502upstream_response_invalidUpstream & timeoutsThe gateway could not decode the upstream response ("Could not decode the upstream response."). The upstream may already have run the request, so the response usually carries X-Should-Retry: false.Do not retry automatically. Retry by hand only once you are sure it should run again; if it persists, open a ticket.
200bps_protocol_errorUpstream & timeoutsIt only appears in a response.failed event of a streaming Responses request, with HTTP status 200. On some upstream routes the gateway translates tool calls; when the model's call cannot be mapped back to a tool you declared (for example an undeclared tool, or broken arguments), the turn ends with this code instead of sending a partial tool call.You can retry the turn. If it keeps happening, declare fewer tools at once, or open a ticket with the X-Request-Id.
502models_unavailableUpstream & timeoutsOnly returned by the model list endpoints (GET /v1/models, and GET /models without /v1): the gateway could not fetch the live upstream model list, and it never returns a partial list.Retry later, and do not poll it as a health check. You can also see available models in Models & pricing.
503gateway_drainingMaintenanceThe gateway is restarting ("The gateway is restarting."). This response has no X-Request-Id.Retry in a moment.
503billing_integrity_unavailableMaintenanceBilling records are temporarily unavailable, so the gateway pauses new requests rather than serve them unbilled.Retry later, waiting for Retry-After when it is present.
503billing_recovery_backlogMaintenanceSome of your account's usage is still being recorded ("Usage recovery is pending. Retry shortly."), and new requests are refused until that finishes.Retry after Retry-After.
503usage_tracking_unavailableMaintenanceThe gateway could not open a usage record for this request, so it was not forwarded ("The request could not be tracked safely. Retry shortly.").Retry shortly.
404unknown_routeRequest contentNothing serves this method and path ("No provider serves this method and path."). Common causes: a typo, an unsupported sub-resource such as /v1/models/{id}, a browser OPTIONS preflight, or /embeddings without /v1. These responses include an X-Request-Id but are not recorded in Requests.Check the method and path against the endpoint list. OpenAI-compatible clients should use https://api.thinkapi.org/v1 as the base URL.
413body_too_largeRequest contentThe request body is over the 32 MiB limit. With input security auditing enabled, the audit's own input limit can also return this code first.Shrink the request body, for example by compressing images or trimming history.
400unreadable_bodyRequest contentThe gateway could not read the request body ("Could not read the request body.").Check your client and network, then retry.
400invalid_request_metadataRequest contentA request field is longer than allowed; model, for example, is capped at 128 bytes. The message names the field.Shorten that field and retry.
400request_rejectedRequest contentThe request failed the gateway's checks. The message gives the reason, such as a missing required field or a field clients are not allowed to set.Fix the request as the message describes; retrying unchanged will not help.
400unsupported_parameterRequest contentA parameter in the request cannot be expressed in the target protocol, typically during cross-protocol translation.Remove the parameter, or call the model through a protocol shown in its details.
400unsupported_image_streamingRequest contentImage generation does not support streaming.Remove "stream": true from the request body.
400invalid_thinking_signatureRequest contentThe conversation contains a thinking signature the upstream has already rejected, so the gateway refuses it; retrying unchanged will not fix it.Restore the complete original thinking blocks with their signatures, or start a new session.
406response_encoding_not_acceptableRequest contentThe request's Accept-Encoding accepts neither the upstream's compression nor uncompressed content (identity).Relax Accept-Encoding so it allows at least identity, or drop the header.
400 / 403content_policy_violationContent safetyPlatform screening or the upstream content policy rejected the request. Upstream refusals stop the request without switching accounts or denying account model access. Same-protocol errors retain the upstream body; see X-ThinkAPI-Error-Code for classification. An HTTP 200 stream may contain an error event, with classification in the final request record.Revise the content before sending again. If you think it is a false positive, open a ticket with the request ID.
429account_security_cooldownContent safetyYour account is in a security cooldown and all its API keys are paused ("This account is temporarily unavailable. Try again later."). Retry-After gives the time left.Retrying before the cooldown ends will not help. Wait it out, and turn off automatic retries for this code.
403account_security_bannedContent safetyThe account is banned under a security restriction, and none of its API keys work ("This account is unavailable. Contact an administrator.").Open a ticket or contact us.
503input_audit_unavailableContent safetyInput security auditing is temporarily unavailable, so the request was not processed ("The request could not be processed. Try again later."). It can appear even when content screening is off, and it does not mean your content broke a rule.Retry later. If it persists, open a ticket.
400 / 403cyber_policyContent safetyThe upstream refused this conversation's content under its cyber-security policy. The gateway preserves the reason without switching accounts or denying account model access. Same-protocol errors may still use upstream permission_error; see X-ThinkAPI-Error-Code. HTTP 200 streams may contain an error or response.failed refusal, with classification in the final request record.Revise the content and start a new session; do not retry unchanged. Your group may refuse the same session for a while, see session_blocked_by_cyber_policy.
403session_blocked_by_cyber_policyContent safetyThe upstream's cyber-security policy refused this session earlier, and your group blocks such sessions for a while, so requests in it are refused without reaching the upstream ("This session is blocked by the upstream cyber-security policy. Start a new session.").Start a new session. Retrying the same session during the block will not help.

Retries and rate limits

  • If a response includes Retry-After, wait at least that many seconds before retrying.
  • If a response includes X-Should-Retry: false, the gateway advises against automatic retries. Handle it based on the error code.
  • Official SDKs and clients retry 429 and 5xx responses by default. Retrying does not help with 429 api_key_quota_exhausted or 429 account_security_cooldown: the first needs a higher credit limit or another key, and the second clears only when the cooldown ends.
  • Requests per minute (RPM) and maximum concurrency apply to your whole account and are shared by all its API keys, so switching keys does not help. Find your limits under API request limits in Settings.
  • Capacity errors such as 429 all_accounts_busy and 429 upstream_rate_limited mean the platform is protecting its capacity. Retry after Retry-After, and open a ticket if they persist. The limit and used values in the items of their details.reasons[], when present, describe platform capacity, not your account limits.
  • If your service group queues requests, a request waits for capacity first, so you see higher latency instead of an immediate 429.

Failover and timeouts

  • When an upstream provider fails, the gateway may retry or switch to another available upstream within the same request. This is transparent to you and X-Request-Id stays the same, though latency may increase.
  • Once a streaming response has started, the gateway no longer switches. If the stream breaks, you are billed for the usage produced so far.
  • 502 upstream_delivery_uncertain and first-output timeout errors (when the platform enables them, such as 504 upstream_first_output_timeout) are not replayed automatically. The request may already have run upstream, so retrying it yourself can run it twice.
  • A request with no data flowing in either direction for a long time is cut off: before the response starts you get 504 upstream_idle_timeout, and after it starts the stream ends early. Give your client a generous read timeout.

Billing and credit

Balance and credit limits

  • Your account balance is a wallet shared by all your API keys. Add funds and review transactions on Billing; available payment methods depend on platform settings.
  • A credit limit caps spending for a single key. Set it when you create or edit a key on API keys; 0 means no limit. It counts settled charges, and once reached, requests return 429 api_key_quota_exhausted. A top-up does not reset key usage, so raise the limit or use another key.
  • Billing is postpaid: new requests need a balance above zero, and requests already in progress can push it below zero. At zero or below, requests return 402 insufficient_balance until you top up.
  • Credit limits are also checked only when a request starts, so requests in progress can take a key slightly past its limit.
  • Use GET /v1/usage to check what you can spend at any time; see Check your balance.

Cost breakdown

Cost per request ≈ model unit price × usage in each billing dimension × group multiplier. Dimensions include input, output, cache reads, and cache writes. Some models add dimensions such as cache write duration, reasoning, or long context. Model details on Models & pricing only note that a model has additional pricing dimensions and do not list those rates; the settled amount in Requests is final.

  • Charges are in your account currency (USD by default).
  • Models & pricing shows a snapshot of current prices with your group multiplier applied. It is not a price lock, and a price shown as “—” does not mean free.
  • The settled amount in Requests is the final charge.

What is not billed

  • Requests the gateway rejects before forwarding them, such as authentication failures, insufficient balance, rate limits, and malformed requests.
  • Upstream attempts that fail before the gateway switches to another upstream.
  • 502 upstream_delivery_uncertain.
  • GET /v1/models, GET /v1/usage, and Anthropic's POST /v1/messages/count_tokens (which still needs a balance above zero).
  • POST /v1/responses/input_tokens: the gateway estimates it locally from the request text, and the response carries X-ThinkAPI-Token-Count: estimated. The number is approximate (a balance above zero is still needed).
  • Connectivity probes answered locally: a bare greeting may get a reply from the gateway itself, with the X-ThinkAPI-Local-Probe header, and appear in Requests as “Probe request · Not forwarded”. It only proves you can reach the gateway, not that the model is available. It still needs a balance above zero and counts toward your RPM.

Service status and troubleshooting

Service status

Service status shows the health of public service groups over the last 24 hours. It refreshes about every 30 seconds, and intervals without requests count as healthy. For dedicated groups, sign in and open Service status in your workspace.

Tracing a request

  • Model responses normally include an X-Request-Id header (except 503 gateway_draining and individual Responses WebSocket turns). Save it in your logs.
  • Open /app/requests/{request_id} in the Portal (replace {request_id} with the request ID) to see the request details, which show the execution status, HTTP status, billing status, and error details. Opening /app/usage?request_id={request_id} shows only that request in the Requests list.
  • If you have questions about the outcome or the charge, choose Get help with this request on the details page. The ticket is linked to that request automatically.
  • Some HTTP clients merge repeated headers into one comma-separated value. If you see two request IDs, use the first 32-character hexadecimal value.

Missing request records

These requests do not appear in Requests:

  • Errors in the Authentication category of Error codes (401, 403, and 500 authorization_failed), plus 429 api_key_quota_exhausted. They include an X-Request-Id but return before a record is written.
  • 404 unknown_route: the method or path is not recognized (for example because of a wrong base URL). It includes an X-Request-Id but returns before authentication and is never recorded.
  • Model list requests (GET /v1/models, GET /models): they include an X-Request-Id but are never recorded.
  • 503 gateway_draining: the gateway is restarting, and this response has no X-Request-Id.

In these cases, include the time (with time zone), the key name, and the error code in your ticket.

Clients such as Claude Code and Codex usually do not show you the X-Request-Id, and individual Responses WebSocket turns do not receive that header at all; the req_… in Claude Code errors is an upstream ID. These requests are still recorded, so look them up in Requests by time, model, and key.

Contacting support

When you open a ticket in Support, include as much of the following as you can:

  • X-Request-Id
  • When it happened, with time zone
  • HTTP status
  • error.code and error.reason, if present
  • Key name (never paste the key itself)
  • Model ID
  • Client name and version
  • Whether the request was streaming

If you cannot sign in, reach support through the channels on Contact us.

Glossary

These terms match the wording used in the Portal.

Service group
Every API key belongs to one service group, which sets the models it can call, the price multiplier and any client restrictions. Groups are either Shared or Dedicated; Dedicated groups are open only to authorized accounts.
Group multiplier
The factor a group applies to a model's base price; ×1 means the base price. Models & pricing shows it for each group, and the prices listed there already include it.
Credit limit
A spending cap on a single API key, counted against settled charges; 0 means no limit. It is checked when a request starts, so in-flight requests can take usage slightly past it. A top-up does not reset key usage.
Account balance
Your account's wallet, shared by all API keys and held in the account currency (USD by default). New requests need a balance above zero; charges settle after each request, so in-flight requests can take it below zero.
Requests
The Portal's log of your API calls, with outcome, usage and cost for each; see Requests. If you have a request ID, open /app/requests/{request_id} to see that call directly.
Billing status
Whether a call's charge is confirmed, shown in its request details as Settled, Awaiting pricing, Not billed and so on; the list's Billing column shows the same. Only a settled zero is a confirmed zero charge.
X-Request-Id
The request ID the gateway returns as a response header (32 hex characters). Use it to open /app/requests/{request_id} for the call's details, and include it in support tickets. Requests that fail authentication, requests to unknown paths (404 unknown_route) and model list requests are not recorded; see Missing request records. If two values appear, use the first.
Native client
A model vendor's official client, such as Claude Code or Codex. Some groups only accept native clients; the Client access field in a model's details is a guide, and other clients get non_client_disabled.
Protocol
The request and response format, such as Anthropic's Messages or OpenAI's Chat Completions and Responses. The protocols a model supports are listed in its details; see Endpoint reference for the paths of each protocol.
Streaming
Returning output as it is generated. Turn it on with "stream": true in the request body for Messages, Chat Completions and Responses.
RPM
Requests per minute. The limit is shared by all API keys on your account and shown under API request limits in Settings. Going over it returns user_rpm_exceeded.
Maximum concurrency
How many requests your account can have in flight at once, shared by all API keys and shown in Settings. Going over it returns user_concurrency_exceeded.
Cross-protocol translation
When you call a model served over a different protocol, the gateway converts the request and response between formats. It only happens if the group enables it; otherwise you get translate_disabled.