Custom API Endpoint for Claude Code, Codex and OpenCode
Claude Code takes a custom API endpoint through two environment variables: ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN. Codex and OpenCode instead declare a "provider" in their own config files, with a base URL and a source for the key. If something breaks after the change, the cause is usually a wrong URL path, the wrong kind of key, or a network problem. The troubleshooting table below lets you check each one in turn.
This article covers only settings that appear in the official documentation. These tools update quickly and field names can change, so wherever it says "check the official docs," verify against the docs for your current version before you start.
What does the endpoint URL need to satisfy?
First, make sure the service you are connecting to speaks the same API format as the tool.
| Tool | Default API format | Your URL must be compatible with |
|---|---|---|
| Claude Code | Anthropic Messages API | Anthropic format |
| Codex | OpenAI API | OpenAI format (whether it uses Chat Completions or Responses depends on the official Codex docs) |
| OpenCode | Set by the provider config | Whatever format you declare in the config |
An address that only supports the OpenAI format will not work in Claude Code, and the reverse is also true. This is a common source of 404 errors.
Two more points:
- The base URL usually ends at the root path or
/v1. The tool appends/messagesor/chat/completionsitself. Whether to include/v1depends on the provider's setup instructions. - Never put keys in a project repository. Keep them in your shell config, a config file in your home directory, or a system secret manager.
How do you set a custom API endpoint in Claude Code?
The official Claude Code documentation lists three relevant environment variables:
| Variable | Purpose |
|---|---|
ANTHROPIC_BASE_URL | Overrides the default API address |
ANTHROPIC_AUTH_TOKEN | A token sent as the Authorization: Bearer header, commonly used with gateways or proxies |
ANTHROPIC_API_KEY | A key sent as the X-Api-Key header |
ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY use different request headers. Set whichever one your provider requires, and do not set both.
Option 1: set it temporarily in the terminal
export ANTHROPIC_BASE_URL="https://your-endpoint.example.com"
export ANTHROPIC_AUTH_TOKEN="sk-xxxxxxxx"
claude
This is good for a quick test. It stops applying when you close the terminal.
Option 2: put it in settings.json
settings.json supports an env field, and the variables in it take effect at the start of every session. The user-level config is ~/.claude/settings.json:
{
"env": {
"ANTHROPIC_BASE_URL": "https://your-endpoint.example.com",
"ANTHROPIC_AUTH_TOKEN": "sk-xxxxxxxx"
}
}
You can also place a .claude/settings.json in a project directory, but that file is usually committed to the repository, so do not put keys in it. For private project-level settings, use .claude/settings.local.json and make sure it is in .gitignore.
How to confirm it took effect
After launching, run /status inside Claude Code to see the current API address and where authentication comes from. If it still shows the default address, check whether your shell has another variable with the same name.
How do you configure a custom base URL in Codex?
Codex reads its configuration from ~/.codex/config.toml. The documented approach is to declare a custom provider under model_providers and point model_provider at it. Example:
model_provider = "mygateway"
[model_providers.mygateway]
name = "My Gateway"
base_url = "https://your-endpoint.example.com/v1"
env_key = "MYGATEWAY_API_KEY"
Put the key in an environment variable:
export MYGATEWAY_API_KEY="sk-xxxxxxxx"
codex
Notes:
env_keyis the name of the environment variable, not the key itself. Codex reads that variable at startup.- The provider section also has fields such as
wire_api, which selects which OpenAI API to use. The allowed values and defaults have changed between versions, so check the official Codex docs. - Set the model with
model = "...", using a name your provider supports.
How do you add a custom provider in OpenCode?
OpenCode's global config is usually at ~/.config/opencode/opencode.json, and you can also put one in a project root. To connect an OpenAI-compatible service, use the provider field. The official docs show roughly this form:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"mygateway": {
"npm": "@ai-sdk/openai-compatible",
"name": "My Gateway",
"options": {
"baseURL": "https://your-endpoint.example.com/v1"
},
"models": {
"your-model-id": {}
}
}
}
}
You can enter the key interactively with opencode auth login, or reference an environment variable in options. For exact field names, and for how to declare an Anthropic-format provider, check the official OpenCode docs.
What changes with an aggregator gateway? AGI Plan as an example
Using an aggregator gateway follows the same steps as above, except the URL and key come from the gateway. Take AGI Plan as an example (AGI Plan is a commercial partner of cdnping). It is compatible with both the OpenAI and Anthropic API formats, so Claude Code, Codex and OpenCode can all connect to it. Setup takes three steps: register with an emailed verification code, pick a plan and create a key, and change one setting. Per-tool addresses and step-by-step guides are at agiplan.dev. AGI Plan states that it is not an officially authorized channel, and some models are marked "overseas only." See the models page for specifics. Read the notes before you use it, and follow each service's terms and local regulations.
How do you troubleshoot 401, 404 and timeouts?
If you get an error after changing the config, work through the table from top to bottom.
| Symptom | Common causes | How to check |
|---|---|---|
| 401 / 403 | Wrong, expired or exhausted key; wrong header type (in Claude Code, AUTH_TOKEN and API_KEY swapped) | Send one request with curl using the same key; in Claude Code, use /status to see where auth comes from |
| 404 | Extra or missing /v1 in the base URL; API format mismatch (an OpenAI-format address in Claude Code); model name not supported by the provider | Check the full path and model name against the provider's docs |
| Connection timeout / endless spinner | No network path from your machine to the endpoint; proxy does not cover the terminal; DNS resolution problems | First check whether the other side is down, then check your own network (next section) |
| Occasional 5xx, 429 | Server-side failure or rate limiting | Check /en/status and /en/down for problems in the same time window |
| Config change has no effect | A same-named environment variable in your shell overrides it; you edited project-level rather than user-level config | env | grep -i anthropic or env | grep -i base_url |
A generic curl self-check (Anthropic format; swap in the headers your provider requires):
curl -sS -o /dev/null -w "HTTP %{http_code} connect %{time_connect}s total %{time_total}s\n" \
"$ANTHROPIC_BASE_URL/v1/messages" \
-H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"your-model-id","max_tokens":16,"messages":[{"role":"user","content":"hi"}]}'
A 200 means the URL and key are correct and the problem is in the tool's config. A 401 or 404 points you to the table above. If the command hangs without returning, it is a network problem.
Is a timeout the server's fault or your network's?
A timeout has two possible causes: the other service is failing, or your route to it is broken. Checking them separately is much faster.
Step 1: check whether the provider is up. Open the API status page. It probes each vendor's official API entry point from the Cloudflare edge every 5 minutes and also syncs some official status pages. If you use AGI Plan, you can go straight to /en/status/agiplan. For Claude Code, see /en/down/claude-code, which combines the official status page, API probes and user reports.
For reference: in cdnping's edge probes from the Cloudflare Denver node (DEN) on October 17, 2026 (a window of about 85 minutes, 242 probes, source: cdnping /status), the p50 for api.anthropic.com was 73 ms and for api.openai.com 96 ms, with no failures in the window. cdnping only began collecting data that day, and this is a short window of data center to data center measurements. It does not represent your own experience. It only shows that the servers were responding normally at the time. If the status page looks normal and you still time out, the problem is most likely your local network.
Step 2: check your local network. Open IP & environment check and focus on three items:
- Exit IP and type: confirm where your terminal's traffic actually exits, and whether it is a data center, residential or mobile network.
- Mainland China split-routing check: determines whether you are on "mainland split routing / global proxy / direct domestic connection." It is common for the browser to go through a proxy while the terminal does not.
- Multi-exit detection and DNS leak: see whether the exit stays the same across different services, and whether DNS goes through the resolver you expect.
After the check you can generate a watermarked result image and optionally hide the IP address. Attach that image when you send results to a colleague or ask for help in a group chat, and your exit IP stays private. The fingerprint is computed locally and is not uploaded.
Step 3: measure latency. The online speed test on the home page measures "first connect" (including DNS and TLS handshake) and "round trip" times to 15 AI model APIs from your browser. If first connect is clearly high but round trip is normal, the problem is usually in DNS or the handshake. If both are high, the path itself is slow. For the causes of latency, see Why AI API latency is high.
Your browser and your terminal do not necessarily take the same network path. If the browser test works but the terminal fails, first check whether the terminal has variables such as HTTPS_PROXY set, and whether your split-routing rules cover the API domain. For the principle, see how split tunneling works.
Putting it together: from configuration to self-check
- Pick one tool, set it up temporarily with environment variables, and run the curl self-check above.
- Once it works, write it into the config file, and make sure the key file is not in a repository.
- The next time you hit an error, check /en/status to confirm the server side, then open /en/ip to check your own machine. When you ask for help, attach the result image with the IP hidden.