Claude Code via the gateway
Claude Code is Anthropic's official command-line AI coding assistant. By default it calls https://api.anthropic.com, but by pointing its base URL at the gateway via the ANTHROPIC_BASE_URL environment variable, you can route all requests through the gateway — either to an Anthropic upstream (same protocol, sent directly) or cross-protocol to OpenAI / Gemini / Bedrock and other upstreams (translated by the gateway).
What you'll build
- An
anthropicupstream + a model aligned with Claude Code's default model ID (this tutorial usesclaude-sonnet-4-5; cross-protocol usesgpt-4oetc.) - A gateway access key
- Claude Code calling successfully through the gateway and seeing a reply
Prerequisites
- The gateway is running (
http://localhost:7890) and you can log in to the Console ENCRYPTION_KEYis set — the upstream API key and access key saved below are encrypted before being stored; if it's not set, saving reportsencryption_key not set in config. See Docker single node → Prerequisites- An Anthropic API key (or, if the upstream is OpenAI / Gemini / Bedrock etc., the corresponding credentials)
- Claude Code installed (
npm install -g @anthropic-ai/claude-codeor similar)
1. Create an anthropic upstream
Console → Upstreams → New:
| Field | Value | Description |
|---|---|---|
| Name | anthropic | Unique upstream identifier |
| Protocol | anthropic | Determines the executor and request schema |
| Base URL | https://api.anthropic.com | The real upstream address, no trailing / |
| API Key | Anthropic key | Click "Add" to add multiple keys, distributed by weight |
| Enabled | ✓ |
Save.
2. Create a claude model
On the anthropic upstream row, click Expand → model sub-table → New model:
| Field | Value | Description |
|---|---|---|
| Name | claude-sonnet-4-5 | The model name exposed to clients |
| Upstream | anthropic | Select the upstream you just created |
| Upstream model ID | claude-sonnet-4-5 | The real Anthropic model name |
| Enabled | ✓ |
Save.
Why name the model directly
claude-sonnet-4-5? Claude Code sends requests with its own configured default model ID (e.g.claude-sonnet-4-5), not an arbitrary gateway name you made up. If the gateway model has a different name (e.g.claude-sonnet), Claude Code's first message will 404model_not_found. Naming the gateway model the model ID Claude Code will actually request is the easiest way to align — you can also skip this and useANTHROPIC_MODELto align, see Step 5. The "upstream model ID" must be a model name that actually exists on Anthropic; see the Anthropic official model list for the available list.
3. Configure a key group to allow access
Console → Access Keys → Key Groups tab → New:
| Field | Value | Description |
|---|---|---|
| Name | default | Group name |
| Models | Select claude-sonnet-4-5, or * (all) | Determines which models this group's keys can call |
| Enabled | ✓ |
4. Issue an access key
Console → Access Keys → New:
| Field | Value | Description |
|---|---|---|
| Name | claude-code-key | The key's identifier, used for management and audit |
| API key | Click "Generate" | Auto-generates a string; the credential clients send when calling |
| Group | default | Determines which models this key can access |
| Enabled | ✓ |
5. Configure Claude Code
Claude Code reads the following environment variables:
export ANTHROPIC_BASE_URL=http://localhost:7890
export ANTHROPIC_API_KEY=<your access key>
# Note: fill base_url to the root (without /v1), because Claude Code appends /v1/messages itselfOr write it into your shell config (~/.zshrc / ~/.bashrc) to persist.
Align the model name (key step): Claude Code sends requests with its own configured default model ID, not an arbitrary gateway model name. The two must match, otherwise the first message 404s model_not_found. Choose one of two ways to align:
Method A (recommended, zero extra config): name the gateway model directly as the model ID Claude Code will request. Step 2 of this tutorial does exactly this (
claude-sonnet-4-5), no further variables needed.Method B: if the gateway model uses a custom name (e.g.
claude-sonnet), setANTHROPIC_MODELto point to that gateway name:bashexport ANTHROPIC_MODEL=claude-sonnet # your custom model name on the gateway(You can also switch with the
/modelcommand inside Claude Code, but the environment variable is less hassle.)
Start Claude Code:
claudeSend a message and see the model reply, and it's working. All of Claude Code's requests go through the gateway.
Cross-protocol upstream
If the upstream is OpenAI / Gemini / Bedrock, protocol translation is needed — Claude Code speaks the Anthropic protocol (/v1/messages), the gateway translates to the upstream protocol and sends it upstream, then translates the response back into Anthropic format.
For example, using an OpenAI upstream as the Claude Code backend:
- Create an upstream
openai(protocolopenai, URLhttps://api.openai.com/v1) - Create a model
claude-sonnet-4-5(upstreamopenai, upstream model IDgpt-4o) — the client's Anthropic requests are automatically translated by the gateway into the OpenAI upstream protocol, with no model-level protocol override needed. Still recommend aligning the model name with Claude Code's default model ID (as in Step 2), otherwise align withANTHROPIC_MODEL.
Combinations where the client and upstream protocols differ need to be a supported direction in the Protocol interop matrix. Anthropic → OpenAI via chat translation is supported.
When crossing protocols, note:
- Tool calls:
tool_call_idmust keep its original value across the cross-protocol round trip - Streaming: the gateway translates the upstream SSE stream into an Anthropic SSE stream; when the upstream takes long to reason, it inserts
:keep-alivecomments - Stream errors: when the upstream stream breaks mid-way, it inserts a
_gateway_warningextension field telling you the reason for the interruption
Inject a session cache key (optional)
Claude Code injects an x-claude-code-session-id header in the conversation. You can use a request_payload expression to inject that header value into the upstream's private cache-key field, so multiple requests of the same session hit the upstream cache:
[
{
"path": "prompt_cache_key",
"mode": "overwrite",
"value": "{{header:x-claude-code-session-id|system_prompt_hash}}"
}
]Degrades level by level: has a session header → use the header (same session, same key); no header but a system prompt exists → use the system hash; both empty → omit the write. See Template variable reference for the full variable list.
FAQ
Q: Claude Code reports connection refused? Check that ANTHROPIC_BASE_URL points to the correct gateway address and that the gateway is listening. For a Docker-deployed gateway, use http://host.docker.internal:7890 or the LAN IP.
Q: Claude Code reports 401?ANTHROPIC_API_KEY isn't set correctly. Check that it's the gateway access key (not Anthropic's sk-...).
Q: Claude Code reports 404 model_not_found? The model name isn't aligned. Claude Code sends its own default model ID (e.g. claude-sonnet-4-5), and the gateway must have a model with the same name. Two fixes: ① name the gateway model the model ID Claude Code will request; ② set ANTHROPIC_MODEL=<your gateway model name>. See Step 5.
Q: Claude Code reports 403 model_access_denied? The key group the key belongs to doesn't include claude-sonnet-4-5 in its "Models" list. Go back to the key group, add that model, or change it to *.
Q: Claude Code reports 400 unsupported_feature? The cross-protocol combination has no translator. Check the supported directions in the Protocol interop matrix.
Q: Tool calls get lost in cross-protocol calls?tool_call_id must keep its original value across the cross-protocol round trip — check that the tool_call_id returned in multi-turn tool conversations exactly matches what the gateway gave you.
Q: How do I configure model switching for plan mode? See Switch models by Claude Code plan mode with a script. Claude Code's plan mode injects Plan mode is active / Exited Plan Mode markers into the conversation, which a script can use to compare the last position and switch routing.
Next: Endpoints · auth · protocol interop for the full endpoint list; Client integration and gateway differences for SDK integration and gateway-specific behavior; Protocol interop matrix for all protocol-pair support.
