Can you call Claude and Gemini with the OpenAI SDK? Yes. Point the client at Anthropic's https://api.anthropic.com/v1/ or Google's https://generativelanguage.googleapis.com/v1beta/openai/, use that provider's API key and model name, and Chat Completions calls work12. Both providers are also clear about the cost: Anthropic says its layer is "primarily intended to test and compare model capabilities" and is not considered a long-term or production-ready solution for most use cases1, and Google labels its support beta2.
This guide shows the setup for each, lists what each layer ignores, and gives a rule for when to use it and when not to.
Claude through the OpenAI SDK
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["ANTHROPIC_API_KEY"],
base_url="https://api.anthropic.com/v1/",
)
reply = client.chat.completions.create(
model="claude-sonnet-5-5",
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Name three uses of a message queue."},
],
)
print(reply.choices[0].message.content)A key with access to several workspaces must also send the anthropic-workspace-id header on every request1.
What Anthropic's layer ignores or changes
| OpenAI feature | Through the compatibility layer |
|---|---|
strict on function schemas | Ignored: tool JSON is not guaranteed to match the schema |
response_format | Ignored |
| Prompt caching | Not supported (supported in Anthropic's SDKs) |
| System and developer messages | Hoisted and concatenated into one top-level system prompt |
| Audio input, file parts | Ignored or stripped |
reasoning_effort, seed, logprobs, user, metadata | Ignored |
n | Must be 1 |
temperature, top_p | Non-default values return 400 on Claude 4.7 and later |
Forced tool_choice | Returns an error on Opus 5.5, Sonnet 5.5 and Fable 5.1; use auto |
usage.prompt_tokens_details | Always empty |
Three of these change production behaviour more than they look:
- No guaranteed JSON. With
strictandresponse_formatignored, code that relied on OpenAI's structured outputs gets well-formed JSON most of the time and not always. Anthropic points to Structured Outputs on its native API for guaranteed conformance1. Structured outputs across providers compares the options. - No prompt caching. A long system prompt or document context is billed at the full input rate on every request through this layer, where the native API could read it from cache for a small fraction of that rate.
- Thinking is invisible. Thinking can be switched on with
extra_body, but the OpenAI SDK does not return Claude's thinking1.
Most unsupported fields are silently ignored rather than rejected1, so a migration that "works" on the first test can still be running without the behaviour you assumed.
Gemini through the OpenAI SDK
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["GEMINI_API_KEY"],
base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
)
reply = client.chat.completions.create(
model="gemini-3.8-flash",
reasoning_effort="low",
messages=[{"role": "user", "content": "Name three uses of a message queue."}],
)
print(reply.choices[0].message.content)Google's layer is broader than Anthropic's. Its page covers chat completions with streaming, function calling, structured output and image and audio input; image generation; video generation through an asynchronous /videos endpoint; embeddings; batch jobs (with file upload and download through Google's own SDK); and model listing2.
Things to know:
- Thinking maps to
reasoning_effort. Valuesminimal,low,mediumandhighmap to Gemini's thinking levels;noneworks only on 2.5 models, because reasoning cannot be turned off on 2.5 Pro or Gemini 3 models. Do not combinereasoning_effortwith Gemini's own thinking settings2. - Gemini-only features go in
extra_body. Thinking configuration with thought summaries,cached_contentfor context caching, Google Search grounding (Gemini 3 or newer) and video options are passed that way2. - Unlisted image parameters are silently ignored, and the whole layer is labelled beta2.
When the compatibility layers are the right tool
| Situation | Use the compatibility layer? |
|---|---|
| Comparing models on your own prompts this week | Yes: fastest way to try them |
| A prototype or internal tool | Usually yes |
| Production traffic that needs guaranteed JSON | No, on Claude |
| Long repeated prompts where caching matters | No, on Claude; check extra_body on Gemini |
| Features that exist only natively (Claude's citations, PDFs, thinking blocks) | No |
| A product that may move between providers | Not on its own: see below |
The layers solve "I want to try another model without rewriting my client". They do not solve "my product should run on several providers and fail over between them": each layer only reaches its own provider, each has different gaps, and a request that fails on one has nowhere to go.
A checklist for comparing models through these layers
Compatibility layers are a good way to run a quick comparison, provided the comparison is fair:
- Same prompts, adapted once. Anthropic notes that a prompt tuned heavily for OpenAI's models may need reworking for Claude1. Give each model one honest prompt pass, then freeze the prompts.
- Same output contract. If your code relies on JSON, validate every answer against the schema yourself during the test, because neither layer guarantees it the way OpenAI's strict mode does.
- Same sampling settings where the model accepts them. Claude 4.7 and later reject non-default
temperatureandtop_p1, so remove them for every model rather than comparing different settings. - Cost in dollars, not tokens. Tokenizers differ, and the usage details these layers return can be empty; compute cost from each provider's own token counts and rates.
- Latency from your region. Measure time to first token and total time from where your application runs.
- A reason to stop. Decide in advance what result would make you move a workload, so the comparison ends in a decision.
Once a model wins, move that workload to the provider's native API or to a gateway that calls it natively, and re-run the comparison there: caching and structured outputs can change both the cost and the reliability you measured.
Two production patterns for multiple providers
Native SDKs behind your own interface. Write a thin internal interface — complete(messages, schema, model_class) — and implement it with each provider's own SDK. You get every native feature, including caching and structured outputs, at the cost of maintaining the adapters. Multi-model API architecture covers the design.
A gateway that speaks each provider's own API. Your application speaks one dialect to the gateway; the gateway translates to each provider's native API and can fail over between them. Ask any gateway exactly which fields it translates and which it drops per provider, because that list is the real product.
Using INFRO
INFRO is a gateway on provider accounts you connect. Your application calls https://api.infro.io/v1 in OpenAI's shape and names a model such as anthropic/claude-sonnet-5.5 or google/gemini-3.8-flash; INFRO calls each provider's own API with your key, so you are not limited to the compatibility layers above. Parameters a model does not accept are adjusted per model and named in the X-INFRO-Params-Dropped header rather than dropped silently. For code that wants Anthropic's own API, INFRO also answers POST /v1/messages in Anthropic's shape, sent to Anthropic as written. Routes can fail over from one provider to another for the same request, and every request is recorded with an estimated provider cost.
Summary
Use Anthropic's and Google's OpenAI-compatible endpoints to try models quickly. Before shipping on them, read each provider's list of ignored fields against the features you depend on — JSON guarantees and prompt caching above all — and for production multi-provider code, either own the adapters or use a gateway that calls each provider natively.
