> Raw Markdown twin (generated at build time from the source Markdown). Rendered page: https://docs.gatellm.io/en/quickstart/claude-code-via-gateway · Doc index: https://docs.gatellm.io/en/llms.txt


# 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 `anthropic` upstream + a model aligned with Claude Code's default model ID (this tutorial uses `claude-sonnet-4-5`; cross-protocol uses `gpt-4o` etc.)
- 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_KEY` is set — the upstream API key and access key saved below are encrypted before being stored; if it's not set, saving reports `encryption_key not set in config`. See [Docker single node → Prerequisites](/en/quickstart/docker-single-node.md#prereq)
- 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-code` or 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 404 `model_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 use `ANTHROPIC_MODEL` to align, see [Step 5](#configure-claude-code). The "upstream model ID" must be a model name that actually exists on Anthropic; see the [Anthropic official model list](https://docs.anthropic.com/en/docs/about-claude/models) 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 {#configure-claude-code}

Claude Code reads the following environment variables:

```bash
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 itself
```

Or 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`), set `ANTHROPIC_MODEL` to point to that gateway name:

  ```bash
  export ANTHROPIC_MODEL=claude-sonnet  # your custom model name on the gateway
  ```

  (You can also switch with the `/model` command inside Claude Code, but the environment variable is less hassle.)

Start Claude Code:

```bash
claude
```

Send 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:

1. Create an upstream `openai` (protocol `openai`, URL `https://api.openai.com/v1`)
2. Create a model `claude-sonnet-4-5` (upstream `openai`, upstream model ID `gpt-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 with `ANTHROPIC_MODEL`.

> Combinations where the client and upstream protocols differ need to be a supported direction in the [Protocol interop matrix](/en/reference/protocol-matrix.md). Anthropic → OpenAI via chat translation is supported.

When crossing protocols, note:

- Tool calls: `tool_call_id` must 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-alive` comments
- Stream errors: when the upstream stream breaks mid-way, it inserts a `_gateway_warning` extension field telling you the reason for the interruption

## Inject a session cache key (optional) {#session-cache-key}

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:

```json
[
  {
    "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](/en/reference/template-variables.md) for the full variable list.

## FAQ {#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](#configure-claude-code).

**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](/en/reference/protocol-matrix.md).

**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](/en/howto/script-switch-model-by-plan-mode.md). 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](/en/reference/endpoints.md) for the full endpoint list; [Client integration and gateway differences](/en/reference/clients-and-gateway-diffs.md) for SDK integration and gateway-specific behavior; [Protocol interop matrix](/en/reference/protocol-matrix.md) for all protocol-pair support.
