Create Message
Last updated August 31, 2026
The inference endpoint for the Anthropic Messages protocol — compatible with the official SDKs, usable with any model that supports it.
This endpoint is compatible with Anthropic's Messages API and works with the official SDKs as-is — just point base_url here.
Authenticate the Anthropic way: x-api-key: <your Amux key>.
The table below covers the main request parameters — accepted ranges, how each is handled on cross-protocol calls, and any preconditions. Anthropic-native fields are preserved where possible on the direct path, but billing-affecting fields and cross-protocol incompatibilities may still be blocked, normalized, or dropped.
https://gateway.amux.ai/v1/messagesAuthorization
headerAuthorizationstringRequiredThe Amux key created in the console. This is the header the Anthropic SDKs send natively; Authorization: Bearer is also accepted.
Content-TypestringRequiredDefault "application/json"Always application/json.
Request
application/jsonmodelstringRequiredCanonical ID shaped like vendor/model. The colon suffix pins a provider (:provider) or chooses a routing strategy (:@price and friends); the two cannot be combined. See the overview.
messagesarray<object>RequiredThe conversation messages. Only user and assistant roles; the system prompt does not go here — use the top-level system.
›messagesarray<object>
role"user" | "assistant"RequiredMessage role. Anthropic's system prompt is not here — it goes in the top-level system.
contentstringRequiredMessage content. Multimodal models accept an array of content blocks shaped like { type: "text" | "image" }.
max_tokensintegerRequiredMaximum output tokens. This endpoint requires a positive integer and rejects missing or invalid values at ingress. When converting in from another protocol without one, we fill in the model's ceiling.
systemstringTop-level system prompt. Either a string or an array of text blocks carrying cache_control.
temperaturenumberSampling temperature, 0–1 (not 0–2). Values above 1 coming from Chat or Gemini are clamped.
⚠️ Anthropic has deprecated all three sampling parameters: on models released after Claude Opus 4.6, temperature accepts only 1, top_p only ≥0.99, and top_k is rejected outright. We do not gate them on the upstream's behalf (that would mean deciding for you which model counts as "new"), so the upstream is what rejects them. The reliable move on this link is not to send them.
top_pnumberNucleus sampling. Removed when thinking is on — Anthropic's reasoning mode rejects it. See temperature for the deprecation on newer models.
top_kintegerTop-k sampling. The OpenAI protocols have no such parameter, so it is dropped when converting out. Also removed when thinking is on.
⚠️ Watch the Gemini → Anthropic link: Gemini's topK converts into this top_k, and models after Opus 4.6 reject top_k, failing the whole request with a 400. Not sending topK avoids it.
stop_sequencesarray<string>Stop sequences. Chat allows at most 4 and Gemini 5; anything beyond is truncated with a note.
streambooleanDefault falseReturn an SSE stream. Anthropic's event sequence must be strictly paired; we close any unclosed blocks when finishing.
toolsarray<object>Callable tools, shaped { name, description, input_schema }. Note the schema field is input_schema, not parameters.
tool_choiceobject{ type: "auto" | "any" | "none" | "tool" }. any corresponds to OpenAI's required. The parallel switch lives here too, as disable_parallel_tool_use.
thinkingobjectExtended thinking. A reasoning_effort level arriving from the OpenAI protocols is converted into the token budget here. The budget is fitted within max_tokens; if it cannot fit, we turn thinking off rather than letting the upstream reject the whole request.
›thinkingobject
type"enabled" | "disabled" | "adaptive"enabled needs budget_tokens; adaptive lets the model decide how long to think; disabled turns it off.
budget_tokensintegerToken budget for thinking. The minimum is 1024 and it counts towards max_tokens. Only meaningful with type: enabled.
display"summarized" | "omitted"Whether thinking comes back summarized (summarized, the default) or not at all (omitted). We do not model it and pass it through.
output_configobjectOutput configuration. effort is a level-based reasoning control — a different unit from thinking.budget_tokens — and format constrains structured output ({ type: "json_schema", schema }).
Passed through unchanged, not carried across protocols. Note that it resembles OpenAI's reasoning_effort but we do not currently map between the two: a reasoning_effort arriving from the OpenAI protocols still converts into thinking.budget_tokens.
›output_configobject
effort"low" | "medium" | "high" | "xhigh" | "max"Level-based reasoning effort. A different unit from thinking.budget_tokens, and we do not currently convert between the two.
formatobjectStructured output constraint, { type: "json_schema", schema }.
cache_controlobjectTop-level cache breakpoint, applied automatically to the last cacheable block. ttl changes the unit price of a cache write (1.25x for 5 minutes, 2x for one hour), but this is not the class we strip: usage comes back with the two write kinds counted separately (cache_creation.ephemeral_5m_input_tokens and ..._1h_...), so billing the tier that actually happened is correct. Merging them is what would undercharge.
›cache_controlobject
type"ephemeral"Only ephemeral exists today.
ttl"5m" | "1h"How long the cache lives. The two tiers have different write prices (1.25x for 5 minutes, 2x for one hour); usage counts them separately, so the tier that happened is what is billed.
containerobjectContainer reuse — either a string ID or { id, skills: [{ skill_id, type, version }] } (at most 20 skills). Anthropic-only, passed through unchanged — it is upstream-side state, so it is only dependable once you pin a provider.
inference_geo"global" | "us"Where inference runs. Not supported — we forward it to no upstream, on either path. ⚠️ Do not rely on this parameter for a regulatory locality requirement: once stripped, inference goes through global routing rather than US-only infrastructure. To bind a region, pin a provider (the :provider suffix) on a channel that is itself region-bound. What was stripped is reported back: amux.droppedParams in the body, or the x-amux-dropped-params header when streaming.
metadataobjectmetadata.user_id is the end-user identifier, matching user on the other protocols.
›metadataobject
user_idstringEnd-user identifier, matching user on the other protocols. Do not put names, email addresses or anything else identifying in it — the upstream only uses it for abuse detection, so an opaque id is enough.
service_tier"auto" | "standard_only"Service tier. Not supported — we forward it to no upstream, on either path. Little is lost: auto is Anthropic's default anyway. What was stripped is reported back: amux.droppedParams in the body, or the x-amux-dropped-params header when streaming.
Response
200responseInference succeeded. model is the canonical ID — the same value you sent.
402responseInsufficient balance. These are not retried and do not affect any provider's health.
Three differences from the OpenAI protocols
max_tokensis required. Missing or non-positive values are rejected by this endpoint before any upstream call.- The system prompt is the top-level
system, not an entry inmessages. input_tokensexcludes cache reads — the opposite convention from OpenAI'sprompt_tokens. Adding them up the OpenAI way double-counts.
Errors
Errors come back in Anthropic's error shape. For type values and retry semantics, see Errors and retries.
curl https://gateway.amux.ai/v1/messages \
-H "x-api-key: $AMUX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-opus-5",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": "Hello!"
}
]
}'{
"id": "msg_01ABC",
"type": "message",
"role": "assistant",
"model": "anthropic/claude-opus-5",
"content": [
{
"type": "text",
"text": "Hello!"
}
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 0,
"output_tokens": 0,
"cache_read_input_tokens": 0
}
}