Messages API Compatibility Reference
Sibling protocols in the inference-apis plugin: chat-completions-api is
the baseline surface every server implements and the target this one is most
often translated to or from; responses-api is the third, with the
thinnest backend coverage of the three.
The Anthropic Messages API (POST /v1/messages) is now the second open
compatibility surface after Chat Completions: every major local inference
server serves it natively (verified by source examination 2026-07-19 —
vLLM, SGLang, llama.cpp, Ollama, mistral.rs, Llama Stack/OGX, Lemonade), and
gateways (LiteLLM, Bifrost, Superagent Gateway) adapt it to everything else.
Claude Code is the driving client; Ollama, Lemonade, and Superagent all ship
Claude Code-specific affordances.
Fleet property: stateless by protocol. No previous_response_id
equivalent exists — full history is resent every turn, so load-balanced
same-model fleets cannot hit wrong-replica session errors (contrast the
Responses API's server-side state; see the responses-api skill).
Last refreshed: 2026-07-19 (source-examined at commits of 2026-07-16..18;
provenance in references/sources.md).
Critical Gotchas
- The thinking-signature seam: third-party backends fabricate or omit
thinking-block signatures. Replaying such thinking to the REAL Anthropic
API fails signature validation — keep conversations on one side of the
boundary or strip thinking when crossing. Per-implementation signature
table:
references/translation-mapping.md.
- Never rely on
stop_sequence: roughly half the implementations never
emit it. end_turn/max_tokens/tool_use is the reliable subset;
refusal/pause_turn never come from third-party backends. Divergence table:
references/translation-mapping.md.
anthropic-beta headers arrive whether supported or not — opencode
always sends interleaved-thinking + fine-grained-tool-streaming betas.
Servers must no-op unknown betas, never 400.
- vLLM silently ignores the
thinking request param (not in its pydantic
model); SGLang accepts budget_tokens but does not enforce it.
- LiteLLM fleet configuration:
model_info.supported_endpoints: ["/v1/messages"] on a deployment forwards Anthropic bodies UNTRANSLATED to
Messages-native backends — full fidelity, no bridge. Without it,
hosted_vllm/ etc. take the chat-completions bridge (works, but unsigned
thinking + no ping + 64-char tool-name truncation).
ping events: only mistral.rs emits them locally; Anthropic's real API
does — clients must not require pings, proxies must not choke on them.
- count_tokens is inconsistent: real tokenization (vLLM) vs approximation
(LiteLLM, Superagent chars/4) vs absent (Ollama, Lemonade). opencode never
calls it; Claude Code uses it when present.
- baseURL convention: Anthropic SDKs append only
/messages — configure
http://host/v1 (Bifrost is the exception: needs its /anthropic prefix).
Quick Reference
When invoked with a topic argument (backends, gateways, translation,
clients), load that reference file first and answer from it. Without an
argument, pick by question shape: which-server-supports-what → backends;
routing/proxy behavior → gateways; wrong output/mapping bugs → translation;
client config → clients.
- Backends:
references/backend-implementations.md — support matrix and
per-server notes for the 7 native implementations
- Gateways:
references/gateways.md — LiteLLM routing cascade, Bifrost,
Superagent Gateway
- Translation:
references/translation-mapping.md — field mapping,
stop_reason divergence table, thinking-signature seam, streaming
divergences, client-side requirements, Claude Code hacks
- Clients:
references/clients.md — opencode deep-dive, Claude Code
behaviors, ecosystem launchers
- Sources:
references/sources.md — dated per-URL index with commits
examined and the live-verification log
Procedures
Pointing an Anthropic-format client at a local backend
- Confirm the backend serves
/v1/messages (all 7 in the matrix do; check
references/backend-implementations.md for its quirks first).
- Set the base URL to
http://host:port/v1 (SDK appends /messages).
Sanity-check: curl -sS http://host:port/v1/messages -H "Content-Type: application/json" -H "x-api-key: x" -H "anthropic-version: 2023-06-01" -d '{"model":"<name>","max_tokens":32,"messages":[{"role":"user","content":"Say OK."}]}'
- opencode: declare under
provider.anthropic.models with explicit
npm: "@ai-sdk/anthropic". Claude Code: ANTHROPIC_BASE_URL (origin, no
/v1 — the client appends it) + ANTHROPIC_API_KEY; isolate all state
non-destructively with CLAUDE_CONFIG_DIR=<scratch-dir>; pin
ANTHROPIC_SMALL_FAST_MODEL to the served model.
Context budget: Claude Code's prompt is ~18k tokens (system + 17 tool
schemas) and it reserves 32k output tokens by default — backends under
~52k max_model_len reject turn 1. Fix:
CLAUDE_CODE_MAX_OUTPUT_TOKENS=8192. Live-verified 2026-07-19
(v2.1.214 → vLLM v0.25.1, 50k ctx: failed by exactly 1 token until
capped, then 3-turn tool loop passed).
- If reasoning models misbehave, check the backend's thinking handling in
the matrix (param ignored? blocks dropped on input?).
Serving Messages through LiteLLM to a fleet
- Prefer per-deployment native passthrough: add
model_info: {supported_endpoints: ["/v1/messages"]} to Messages-native backends.
- Otherwise the chat-completions bridge applies — expect unsigned thinking,
no ping, tool-name truncation at 64 chars; see
references/gateways.md.
- Statelessness makes any replica valid — no affinity needed (unlike
Responses
previous_response_id; see responses-api skill).
Debugging a Messages streaming issue against a third-party backend
- Capture raw SSE:
curl -sN http://host:port/v1/messages -H "Content-Type: application/json" \
-H "x-api-key: x" -H "anthropic-version: 2023-06-01" \
-d '{"model":"<name>","max_tokens":64,"stream":true,"messages":[{"role":"user","content":"hi"}]}' | head -40
- Expect
message_start → content_block_start → *_delta → content_block_stop → message_delta (stop_reason+usage) → message_stop, each as
event: X\ndata: {json}.
- Check the streaming-divergences section in
references/translation-mapping.md for the backend's known deviations
(id formats, ping, tool_use triple vs incremental args).
1---2name: messages-api3description: Reference for the Anthropic Messages API (/v1/messages) as a third-party compatibility protocol — the 7 inference servers that implement it natively (vLLM, SGLang, llama.cpp, Ollama, mistral.rs, Llama Stack/OGX, Lemonade), gateways that adapt it (LiteLLM, Bifrost, Superagent Gateway), client behavior (Claude Code, opencode anthropic provider), Messages ↔ Chat Completions translation, the thinking-signature seam, stop_reason divergences, and streaming quirks. NOT for official Anthropic API usage (models, pricing, SDK) — that is the claude-api skill.4---56# Messages API Compatibility Reference78Sibling protocols in the `inference-apis` plugin: **`chat-completions-api`** is9the baseline surface every server implements and the target this one is most10often translated to or from; **`responses-api`** is the third, with the11thinnest backend coverage of the three.1213The Anthropic Messages API (`POST /v1/messages`) is now the second open14compatibility surface after Chat Completions: **every major local inference15server serves it natively** (verified by source examination 2026-07-19 —16vLLM, SGLang, llama.cpp, Ollama, mistral.rs, Llama Stack/OGX, Lemonade), and17gateways (LiteLLM, Bifrost, Superagent Gateway) adapt it to everything else.18Claude Code is the driving client; Ollama, Lemonade, and Superagent all ship19Claude Code-specific affordances.2021**Fleet property: stateless by protocol.** No `previous_response_id`22equivalent exists — full history is resent every turn, so load-balanced23same-model fleets cannot hit wrong-replica session errors (contrast the24Responses API's server-side state; see the responses-api skill).2526**Last refreshed**: 2026-07-19 (source-examined at commits of 2026-07-16..18;27provenance in `references/sources.md`).2829## Critical Gotchas3031- **The thinking-signature seam**: third-party backends fabricate or omit32 thinking-block signatures. Replaying such thinking to the REAL Anthropic33 API fails signature validation — keep conversations on one side of the34 boundary or strip thinking when crossing. Per-implementation signature35 table: `references/translation-mapping.md`.36- **Never rely on `stop_sequence`**: roughly half the implementations never37 emit it. end_turn/max_tokens/tool_use is the reliable subset;38 refusal/pause_turn never come from third-party backends. Divergence table:39 `references/translation-mapping.md`.40- **`anthropic-beta` headers arrive whether supported or not** — opencode41 always sends interleaved-thinking + fine-grained-tool-streaming betas.42 Servers must no-op unknown betas, never 400.43- **vLLM silently ignores the `thinking` request param** (not in its pydantic44 model); SGLang accepts `budget_tokens` but does not enforce it.45- **LiteLLM fleet configuration**: `model_info.supported_endpoints:46 ["/v1/messages"]` on a deployment forwards Anthropic bodies UNTRANSLATED to47 Messages-native backends — full fidelity, no bridge. Without it,48 `hosted_vllm/` etc. take the chat-completions bridge (works, but unsigned49 thinking + no ping + 64-char tool-name truncation).50- **`ping` events**: only mistral.rs emits them locally; Anthropic's real API51 does — clients must not require pings, proxies must not choke on them.52- **count_tokens is inconsistent**: real tokenization (vLLM) vs approximation53 (LiteLLM, Superagent chars/4) vs absent (Ollama, Lemonade). opencode never54 calls it; Claude Code uses it when present.55- **baseURL convention**: Anthropic SDKs append only `/messages` — configure56 `http://host/v1` (Bifrost is the exception: needs its `/anthropic` prefix).5758## Quick Reference5960When invoked with a topic argument (`backends`, `gateways`, `translation`,61`clients`), load that reference file first and answer from it. Without an62argument, pick by question shape: which-server-supports-what → backends;63routing/proxy behavior → gateways; wrong output/mapping bugs → translation;64client config → clients.6566- **Backends**: `references/backend-implementations.md` — support matrix and67 per-server notes for the 7 native implementations68- **Gateways**: `references/gateways.md` — LiteLLM routing cascade, Bifrost,69 Superagent Gateway70- **Translation**: `references/translation-mapping.md` — field mapping,71 stop_reason divergence table, thinking-signature seam, streaming72 divergences, client-side requirements, Claude Code hacks73- **Clients**: `references/clients.md` — opencode deep-dive, Claude Code74 behaviors, ecosystem launchers75- **Sources**: `references/sources.md` — dated per-URL index with commits76 examined and the live-verification log7778## Procedures7980### Pointing an Anthropic-format client at a local backend811. Confirm the backend serves `/v1/messages` (all 7 in the matrix do; check82 `references/backend-implementations.md` for its quirks first).832. Set the base URL to `http://host:port/v1` (SDK appends `/messages`).84 Sanity-check: `curl -sS http://host:port/v1/messages -H "Content-Type:85 application/json" -H "x-api-key: x" -H "anthropic-version: 2023-06-01"86 -d '{"model":"<name>","max_tokens":32,"messages":[{"role":"user","content":"Say OK."}]}'`873. opencode: declare under `provider.anthropic.models` with explicit88 `npm: "@ai-sdk/anthropic"`. Claude Code: `ANTHROPIC_BASE_URL` (origin, no89 /v1 — the client appends it) + `ANTHROPIC_API_KEY`; isolate all state90 non-destructively with `CLAUDE_CONFIG_DIR=<scratch-dir>`; pin91 `ANTHROPIC_SMALL_FAST_MODEL` to the served model.92 **Context budget**: Claude Code's prompt is ~18k tokens (system + 17 tool93 schemas) and it reserves 32k output tokens by default — backends under94 ~52k `max_model_len` reject turn 1. Fix:95 `CLAUDE_CODE_MAX_OUTPUT_TOKENS=8192`. Live-verified 2026-07-1996 (v2.1.214 → vLLM v0.25.1, 50k ctx: failed by exactly 1 token until97 capped, then 3-turn tool loop passed).984. If reasoning models misbehave, check the backend's thinking handling in99 the matrix (param ignored? blocks dropped on input?).100101### Serving Messages through LiteLLM to a fleet1021. Prefer per-deployment native passthrough: add `model_info:103 {supported_endpoints: ["/v1/messages"]}` to Messages-native backends.1042. Otherwise the chat-completions bridge applies — expect unsigned thinking,105 no ping, tool-name truncation at 64 chars; see `references/gateways.md`.1063. Statelessness makes any replica valid — no affinity needed (unlike107 Responses `previous_response_id`; see responses-api skill).108109### Debugging a Messages streaming issue against a third-party backend1101. Capture raw SSE:111 ```bash112 curl -sN http://host:port/v1/messages -H "Content-Type: application/json" \113 -H "x-api-key: x" -H "anthropic-version: 2023-06-01" \114 -d '{"model":"<name>","max_tokens":64,"stream":true,"messages":[{"role":"user","content":"hi"}]}' | head -40115 ```1162. Expect `message_start → content_block_start → *_delta → content_block_stop117 → message_delta (stop_reason+usage) → message_stop`, each as118 `event: X\ndata: {json}`.1193. Check the streaming-divergences section in120 `references/translation-mapping.md` for the backend's known deviations121 (id formats, ping, tool_use triple vs incremental args).