Integration Guides

OpenAI SDK with Claude: Setup and What Gets Ignored (2026)

Kenji Watanabe

Yes, you can use the OpenAI SDK with Claude. Anthropic runs an official compatibility layer: point the SDK's base_url at https://api.anthropic.com/v1/, swap in a Claude API key, and use a Claude model ID such as claude-sonnet-5. Chat completions, streaming and tool calls work; several OpenAI-only parameters are silently ignored.

That last clause is the part worth reading carefully. This guide covers the setup, the exact fields the layer honours or drops according to Anthropic's own compatibility reference, and the one thinking example from the docs that returns a 400 if you paste it unchanged onto a Claude 5 model.

What the OpenAI SDK compatibility layer is

Anthropic exposes an OpenAI-shaped Chat Completions endpoint next to its native Messages API. You keep the official openai package, keep calling client.chat.completions.create(), and Anthropic translates the request into a Messages call on its side.

Anthropic is explicit about what it is for. Its documentation describes the layer as primarily intended to test and compare model capabilities, and says it is not considered a long-term or production-ready solution for most use cases. It is meant to stay functional without breaking changes, but the native Claude API gets priority. Read that as: the fastest way to try Claude inside existing OpenAI code, not the place to build features that depend on Claude-specific behaviour.

Two consequences follow from the design:

  • Rate limits are the Messages API limits. According to Anthropic, requests through the compatibility layer follow the standard limits for /v1/messages, not a separate pool.
  • Errors keep OpenAI's format, not OpenAI's wording. The error shape is consistent with the OpenAI API, but the messages differ. Anthropic advises using them for logging and debugging only, so do not branch your code on error text.

Setup: base_url, API key, and model ID

Three values change. Nothing else in your call site has to.

Setting

Value for Claude

Base URL

https://api.anthropic.com/v1/

API key

A Claude API key (read from ANTHROPIC_API_KEY in the examples below)

Model

A Claude model ID: claude-opus-5, claude-sonnet-5, or claude-haiku-4-5

Python:

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["ANTHROPIC_API_KEY"],
    base_url="https://api.anthropic.com/v1/",
)

response = client.chat.completions.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    messages=[
        {"role": "system", "content": "You are a concise code reviewer."},
        {"role": "user", "content": "Review this function name: getData2()"},
    ],
)

print(response.choices[0].message.content)

Node.js:

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.ANTHROPIC_API_KEY,
  baseURL: "https://api.anthropic.com/v1/",
});

const response = await client.chat.completions.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  messages: [
    { role: "system", content: "You are a concise code reviewer." },
    { role: "user", content: "Review this function name: getData2()" },
  ],
});

console.log(response.choices[0].message.content);

Three setup details that cause most first-call failures:

  • Model IDs are Claude IDs, not aliases for GPT names. Anthropic's reference says the model field takes Claude model names, so a GPT model name left over in config will not be translated for you. Copy the ID from Anthropic's models overview rather than typing it from memory.
  • Workspace header for multi-workspace keys. If your key is a personal or service-account key with access to more than one workspace, Anthropic requires an anthropic-workspace-id header on every request. With the OpenAI SDK that goes in default_headers (Python) or defaultHeaders (Node).
  • Only official OpenAI SDKs are in scope. Anthropic's instructions start with using an official OpenAI SDK. Third-party wrappers may add their own parameters or rewrite paths.

If the base URL itself is giving you 404s or a doubled /v1, the checks in OpenAI-compatible base URL: what to set apply here unchanged.

Which parameters are supported, capped, or ignored

This is the table to keep open while you port code. It summarises Anthropic's field-by-field compatibility reference for request parameters.

Parameter

Behaviour on Claude

model

Must be a Claude model ID

max_tokens, max_completion_tokens

Fully supported

stream, stream_options

Fully supported

top_p

Fully supported

parallel_tool_calls

Fully supported

stop

Supported for non-whitespace stop sequences

temperature

Accepted between 0 and 1; values above 1 are capped at 1

n

Must be exactly 1

tools[].function.strict

Ignored, so tool arguments are not guaranteed to match the schema

response_format

Ignored

seed, logprobs, top_logprobs, logit_bias

Ignored

presence_penalty, frequency_penalty

Ignored

reasoning_effort

Ignored

metadata, store, user, service_tier, prediction

Ignored

audio, modalities

Ignored

The important word in that table is ignored. Anthropic notes that most unsupported fields are silently ignored rather than producing errors. Your request succeeds, you get a normal completion, and the feature you asked for simply did not happen. The general pattern is covered in OpenAI compatibility issues; on this endpoint the three that bite hardest are:

  • response_format ignored. JSON mode is not enforced. If your parser assumes valid JSON, add validation, or move that call to the native API's structured outputs. Background on that route is in Claude API structured output.
  • strict on tools ignored. Tool-call arguments usually follow your schema, but nothing guarantees it. Validate arguments before executing a tool.
  • seed ignored. Anything that relied on reproducible sampling for tests will not be reproducible.

Message content has its own gaps. User messages support text and image_url (the detail sub-field is ignored), while input_audio and file content parts are ignored. The name field is ignored on every role.

Behaviour that changes your results

Beyond individual parameters, four behaviours differ from what OpenAI code tends to assume.

System and developer messages are hoisted. OpenAI lets you place system or developer messages anywhere in the conversation. Claude supports a single initial system prompt, so the compatibility layer collects every system and developer message, joins them with a single newline, and sends the result as one system prompt at the start. A mid-conversation instruction such as "from now on, answer in French" no longer sits at that point in the dialogue; it becomes part of the opening instructions.

Prompt caching is not available. Anthropic lists prompt caching as unsupported through the compatibility layer but supported in its own SDKs. For long, repeated system prompts this can be a significant cost difference between the two paths; see prompt caching with the Claude API.

Some response fields are always empty. choices always has length 1. usage.prompt_tokens, usage.completion_tokens and usage.total_tokens are populated, but usage.prompt_tokens_details and usage.completion_tokens_details are always empty, as are logprobs, system_fingerprint and service_tier. Dashboards that read cached-token or reasoning-token counts from those detail objects will show nothing.

Prompts tuned for GPT may need rework. Anthropic's own guidance is that heavily tuned prompts are likely tuned to OpenAI specifically, and it points to its prompting best practices for adapting them.

Thinking through the OpenAI SDK

The OpenAI SDK has no thinking argument, so you pass Claude's thinking configuration as an extra body field. In Python that is extra_body; in Node you add the key to the request object directly (TypeScript needs a type suppression comment).

What you send depends on the model, and this is where the docs example can trip you up. Anthropic's compatibility page illustrates thinking with {"type": "enabled", "budget_tokens": 2000} on an older Sonnet model. According to Anthropic's thinking troubleshooting table:

Model

Thinking by default

Rejected with a 400

claude-opus-5

On (adaptive)

"enabled"; "disabled" only at effort xhigh or max

claude-sonnet-5

On (adaptive)

"enabled"

claude-haiku-4-5

Off (extended thinking only)

"adaptive"

So on the Claude 5 models you usually send nothing: thinking is already on. Copying the budget_tokens example onto claude-sonnet-5 returns a 400. On Haiku 4.5 the legacy form is the right one:

# Claude 5: thinking is on by default. Turn it off for a cheap, simple call.
fast = client.chat.completions.create(
    model="claude-sonnet-5",
    max_tokens=512,
    messages=[{"role": "user", "content": "Rename getData2() to something clearer."}],
    extra_body={"thinking": {"type": "disabled"}},
)

# Haiku 4.5: thinking is off by default and uses extended thinking.
deliberate = client.chat.completions.create(
    model="claude-haiku-4-5",
    max_tokens=4096,
    messages=[{"role": "user", "content": "Find the edge cases in this date parser."}],
    extra_body={"thinking": {"type": "enabled", "budget_tokens": 2000}},
)

One limitation holds regardless of model: Anthropic states that the OpenAI SDK does not return Claude's detailed thought process. You get the improved answer, not the reasoning text. If you need to read or log thinking output, use the native API.

Streaming and tool calls

Both of the paths agent code depends on are supported.

  • Streaming. stream=True and stream_options are fully supported, so the SDK's normal iterator works. If you parse raw server-sent events yourself instead of using the SDK, test against this endpoint rather than assuming byte-identical chunks.
  • Tools. Tool name, description and parameters are fully supported, as are tool_calls on assistant messages, tool_call_id on tool messages, tool_choice, and parallel_tool_calls. The legacy functions field is also accepted. The gap is strict, covered above.
const stream = await client.chat.completions.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  stream: true,
  stream_options: { include_usage: true },
  messages: [{ role: "user", content: "List three risks of silent parameter drops." }],
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

When to move to the native SDK or a gateway

The compatibility layer is the right tool while you evaluate Claude inside an OpenAI codebase. Anthropic recommends the native Claude API for its full feature set, and names PDF processing, citations, thinking and prompt caching as features you get there. Move a code path to the native Anthropic SDK when it needs any of those, or guaranteed schema conformance. How to use the Claude API walks through the native request shape.

A third option applies when the goal is one OpenAI-compatible client for several model families: put a gateway in front. That is what LiteLLM with Claude does as self-hosted software, and what a hosted endpoint such as ROIBest AI does as a service; the trade-offs are laid out in what an OpenAI-compatible API is. A gateway sits in the same translation position, so the same rule holds: check which parameters it forwards, drops or maps before relying on them. ROIBest AI's base URL and current model list are in its documentation.

A quick verification pass

Before trusting a port, run the calls your code actually depends on and look at the fields, not just the text.

r = client.chat.completions.create(
    model="claude-sonnet-5",
    max_tokens=256,
    temperature=0.2,
    messages=[{"role": "user", "content": "Reply with the word ok."}],
)

print(r.model)                       # the model that actually answered
print(r.choices[0].finish_reason)    # was the answer cut off by max_tokens?
print(r.usage.prompt_tokens, r.usage.completion_tokens)
print(len(r.choices))                # always 1 on this endpoint

Then, for each optional parameter your code sends, ask one question: is it in the ignored list above? If yes, either remove it so nobody assumes it works, or move that call to the native API. That single review catches most porting bugs before they reach production.

FAQ

Can I use the OpenAI Python SDK with Claude?

Yes. Set base_url to https://api.anthropic.com/v1/, pass a Claude API key, and use a Claude model ID such as claude-sonnet-5. The same approach works in the official Node, Go, Java, C# and Ruby OpenAI SDKs.

Is Anthropic's OpenAI compatibility layer meant for production?

Anthropic describes it as primarily for testing and comparing models and not a long-term or production-ready solution for most use cases. It is kept functional, but the native Claude API has priority.

Does response_format JSON mode work with Claude through the OpenAI SDK?

No. response_format is ignored, and so is strict on tool definitions. For guaranteed schema conformance, Anthropic points to structured outputs on the native Claude API.

Why does my thinking request return a 400 on claude-sonnet-5?

Claude Sonnet 5 supports only adaptive thinking, which is on by default, and rejects {"type": "enabled"} with budget_tokens. Omit the thinking field, or send {"type": "disabled"} to turn it off.