Amux

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.

POSThttps://gateway.amux.ai/v1/messages

Authorization

header
AuthorizationstringRequired

The 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/json
modelstringRequired

Canonical 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>Required

The conversation messages. Only user and assistant roles; the system prompt does not go here — use the top-level system.

messagesarray<object>
role"user" | "assistant"Required

Message role. Anthropic's system prompt is not here — it goes in the top-level system.

contentstringRequired

Message content. Multimodal models accept an array of content blocks shaped like { type: "text" | "image" }.

max_tokensintegerRequired

Maximum 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.

systemstring

Top-level system prompt. Either a string or an array of text blocks carrying cache_control.

temperaturenumber

Sampling 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_pnumber

Nucleus sampling. Removed when thinking is on — Anthropic's reasoning mode rejects it. See temperature for the deprecation on newer models.

top_kinteger

Top-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 false

Return 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.

thinkingobject

Extended 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_tokensinteger

Token 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_configobject

Output 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.

formatobject

Structured output constraint, { type: "json_schema", schema }.

cache_controlobject

Top-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.

containerobject

Container 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.

metadataobject

metadata.user_id is the end-user identifier, matching user on the other protocols.

metadataobject
user_idstring

End-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

200response

Inference succeeded. model is the canonical ID — the same value you sent.

402response

Insufficient balance. These are not retried and do not affect any provider's health.

Three differences from the OpenAI protocols

  • max_tokens is 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 in messages.
  • input_tokens excludes cache reads — the opposite convention from OpenAI's prompt_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
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
  }
}