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


# Call Anthropic Claude with the OpenAI SDK

This chapter teaches you how to call Anthropic's Claude models with an OpenAI SDK — the client protocol (OpenAI Chat Completions) and the upstream protocol (Anthropic Messages) differ, so the gateway translates in both directions. This is a typical example of the gateway's cross-protocol capability.

## What you'll accomplish

- An `anthropic` upstream (pointing to the Anthropic API)
- A `claude-sonnet` model (upstream protocol `anthropic`)
- Call `claude-sonnet` with the OpenAI Python SDK and see the model's 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 you're about to save are encrypted before storage; if unset, saving reports `encryption_key not set in config`. See [Docker single node → Prerequisites](/en/quickstart/docker-single-node.md#prereq)
- An Anthropic API key

## 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 upstream's real address, no trailing `/` |
| API Key | Anthropic's key | Click "Add" to add more, distributed by weight |
| Enabled | ✓ | |

Save.

## 2. Create a claude model

In the `anthropic` upstream row, click **Expand** → model sub-table → **New model**:

| Field | Value | Description |
|------|-----|------|
| Name | `claude-sonnet` | The model name exposed to clients |
| Upstream | `anthropic` | Select the upstream you just created |
| Upstream model ID | `claude-sonnet-4-5` | Anthropic's real model name |
| Enabled | ✓ | |

Save. When clients call using `claude-sonnet`, the gateway routes to `claude-sonnet-4-5` on the `anthropic` upstream.

> "Upstream model ID" must be a real model name that exists on Anthropic (in this example `claude-sonnet-4-5`); a wrong or discontinued model name yields a 404. For the full list of available models, see [Anthropic's official model list](https://docs.anthropic.com/en/docs/about-claude/models).

## 3. Configure a key group to allow it

Console → **Access Keys** → **Key Groups** tab → **New**:

| Field | Value | Description |
|------|-----|------|
| Name | `default` | Group name |
| Models | Select `claude-sonnet`, 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 | `my-app-key` | The key's identifier, used for management and auditing |
| API Key | click "Generate" | Auto-generates a string; the credential the client carries when calling |
| Group | `default` | Determines which models this key can access |
| Enabled | ✓ | |

## 5. Call with the OpenAI SDK

```python
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:7890/v1",
    api_key="<your access key>",
)

resp = client.chat.completions.create(
    model="claude-sonnet",
    messages=[{"role": "user", "content": "hello"}],
)
print(resp.choices[0].message.content)
```

The request body is in OpenAI Chat Completions format. The gateway:

1. Receives the OpenAI-format request
2. Translates it to Anthropic Messages format and sends it to `https://api.anthropic.com/v1/messages`
3. Translates the Anthropic response back to OpenAI format and returns it

The client is unaware and sees a standard OpenAI response.

## 6. Or use curl

```bash
curl http://localhost:7890/v1/chat/completions \
  -H "Authorization: Bearer <your access key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet",
    "messages": [{"role":"user","content":"hello"}]
  }'
```

Receiving Claude's reply means it works.

## Cross-protocol translation details

### Tool calls

For cross-protocol tool calls (OpenAI tools → Anthropic tools), the gateway automatically translates the `tools` / `tool_choice` / `tool_calls` fields. Key constraints:

- **`tool_call_id` must keep its original value across the cross-protocol round trip** — the `tool_call_id` you pass back in a multi-turn tool conversation must be exactly what the gateway gave you, otherwise the upstream cannot match it.
- **The `tool_use` id in responses is synthesized by the gateway** — the gateway assigns each `tool_use` block a globally unique `toolu_` id (it does not pass through the original id the upstream assigned). You just echo it back verbatim as the next turn's `tool_use_id` / `tool_call_id`; no need to care about the upstream's original id.
- **`tool_use` ids in the request history must be globally unique** — the gateway validates `/v1/messages` requests the same way the Anthropic official API does; a history containing duplicate `tool_use` ids returns `400 invalid_request_error` (with a message like `tool_use ids must be unique`). Echoing back the gateway's synthesized ids normally won't trigger this.

### Streaming

Streaming requests are also translated: the gateway converts Anthropic's SSE event stream into OpenAI's `data: {...}` block stream. If the upstream inference takes a long time, the gateway inserts `:keep-alive` SSE comments to keep the connection alive. Standard SSE client implementations ignore these automatically; no special handling is needed.

### Mid-stream interruption

When an upstream stream is interrupted mid-transfer, the gateway doesn't just error out and break the conversation. Instead, it:

- Closes the content blocks that haven't finished
- Inserts a `_gateway_warning` extension field into the SSE stream, telling you the reason for the interruption (including `reason` / `detail` / `last_finish_reason` / `timestamp`)
- Sends the normal termination sequence so the client can finish cleanly

If you see `_gateway_warning` while parsing the stream, it means this response had a problem mid-way; you can log or alert on it.

## Reverse: call OpenAI with the Anthropic SDK

You can also do the reverse: the upstream is OpenAI (`openai` protocol), and the client uses the Anthropic SDK to call `/v1/messages`. The gateway translates the Anthropic request to an OpenAI request and sends it to the upstream, then translates the response back to Anthropic. For the specific connection method, see [Client integration and gateway differences](/en/reference/clients-and-gateway-diffs.md).

## FAQ

**Q: Cross-protocol calls lose tool calls / upstream reports 400 invalid tool_call_id?**
Check whether the `tool_call_id` you pass back in a multi-turn tool conversation is exactly what the gateway gave you. In cross-protocol translation, `tool_call_id` must keep its original value.

**Q: Calling `/v1/messages` reports 400 `tool_use ids must be unique`?**
The conversation history you sent has two `tool_use` blocks using the same `id` — the Anthropic contract requires `tool_use` ids to be globally unique, and the gateway rejects it just like the official API. Check whether your history-construction logic reuses ids across turns; echoing back the gateway's synthesized `toolu_` ids normally won't collide.

**Q: A `_gateway_warning` field is mixed into the response?**
It's not from the upstream; the gateway added it. It means the upstream stream was interrupted mid-way. Look at its `reason`/`detail` to decide whether to retry.

**Q: Client reports 400 unsupported_feature?**
There's no translator for that "client protocol → upstream protocol" pair. Check the [Protocol interop matrix](/en/reference/protocol-matrix.md) for the support matrix.

**Q: Client reports 401 / 403 / 404?**
- 401: the access key isn't right
- 403 model_access_denied: the key group's "models" list doesn't include `claude-sonnet`
- 404 model_not_found: the model name is misspelled, or `claude-sonnet` has `hide_name` set

**Next**: [Endpoints · auth · protocol interop](/en/reference/endpoints.md) for the full endpoint list; [Protocol interop matrix](/en/reference/protocol-matrix.md) for support across all protocol pairs; [Client integration and gateway differences](/en/reference/clients-and-gateway-diffs.md) for each SDK's connection method.
