From an OpenAI client
Two lines:/v1/chat/completions, /v1/completions, /v1/models and /v1/models/{model} all
behave as the SDK expects. The model name is the one thing that must change — ours are not
OpenAI’s. See Models and resource names.
From an Anthropic client
Give the SDK the origin, not the/v1 base — it appends /v1/messages itself:
x-api-key is accepted, so the SDK’s auth code is untouched. Claude Code works by
changing base_url alone.
Two differences from Anthropic’s own API:
- No
claude-*aliasing. Model names stay ours. max_tokensis optional. Anthropic requires it; here, omitting it falls back to the model’s default rather than failing the call.
Ignored, or rejected
A parameter this API does not implement is ignored, not rejected — your existing request bodies will not start failing because they carry something extra. The exceptions are the handful that would change the answer if ignored. Those returnINVALID_REQUEST:
The reasoning is the same one behind tool calling and
structured outputs: silently ignoring a parameter that changes the
shape of the answer produces a response that looks right and is not. An error you cannot
miss is the better failure.
top_k on /v1/messages is
accepted so Anthropic clients do not break, and not passed to the model. The per-parameter
truth is on each endpoint page in the API reference.
What to check after switching
Model names
The only change that is not configuration. Look them up rather than translating.
Retry logic
Branch on
error.code, not on the status — three codes share 429 and one never
succeeds.Usage parsing
Streaming carries
usage on the last event without include_usage.Provider assumptions
Nothing in a response names who served it. Code that branched on that has nothing to
branch on.