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
anthropicupstream (pointing to the Anthropic API) - A
claude-sonnetmodel (upstream protocolanthropic) - Call
claude-sonnetwith 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_KEYis set — the upstream API key and access key you're about to save are encrypted before storage; if unset, saving reportsencryption_key not set in config. See Docker single node → Prerequisites- 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.
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
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:
- Receives the OpenAI-format request
- Translates it to Anthropic Messages format and sends it to
https://api.anthropic.com/v1/messages - 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
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_idmust keep its original value across the cross-protocol round trip — thetool_call_idyou pass back in a multi-turn tool conversation must be exactly what the gateway gave you, otherwise the upstream cannot match it.- The
tool_useid in responses is synthesized by the gateway — the gateway assigns eachtool_useblock a globally uniquetoolu_id (it does not pass through the original id the upstream assigned). You just echo it back verbatim as the next turn'stool_use_id/tool_call_id; no need to care about the upstream's original id. tool_useids in the request history must be globally unique — the gateway validates/v1/messagesrequests the same way the Anthropic official API does; a history containing duplicatetool_useids returns400 invalid_request_error(with a message liketool_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_warningextension field into the SSE stream, telling you the reason for the interruption (includingreason/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.
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 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-sonnethashide_nameset
Next: Endpoints · auth · protocol interop for the full endpoint list; Protocol interop matrix for support across all protocol pairs; Client integration and gateway differences for each SDK's connection method.
