EZAT RouterDocs

Create a message

POST
/v1/messages

Sends a conversation to a model and returns its reply, in Anthropic's Messages format. Set "stream": true to receive the reply as Server-Sent Events.

The gateway checks model, max_tokens, messages and stream. Every other field (system, tools, thinking, output_config, cache_control and the rest) is passed to the model unchanged, and the model checks it as Anthropic's API would. Two exceptions:

  • The gateway removes prompt-cache breakpoints (cache_control) for models whose capabilities.promptCaching is false in GET /api/models, because their cache is never read back. Those requests are billed as plain input instead of a cache write.
  • The anthropic-version header is accepted but not used.

The response's model (and message.model in message_start) is the name you sent, not the canonical id.

Authorization

headerx-api-key<token>

Your EZAT Router key (ezat_sk_…) in the x-api-key header, as the Anthropic SDKs send it. Accepted on every /v1 and /openai/v1 endpoint.

Header Parameters

anthropic-version?string

Accepted for compatibility with Anthropic's SDKs, which send it, but not used. You don't need to send it.

anthropic-beta?string

Anthropic beta features, comma-separated. Passed to the model provider unchanged. A beta the provider doesn't offer is refused there.

x-ezat-session?string

Names the conversation this request belongs to, so every turn goes to the same deployment and reuses its prompt cache. Any string; only the first 256 characters are used. Without it, the gateway recognises a conversation by its system prompt and first message. In the OpenAI format, prompt_cache_key does the same, and this header wins when both are sent.

x-request-id?string

Your own id for this request, echoed in the x-request-id response header (and as request_id in Anthropic-format error bodies). Used only if it is 1 to 128 characters of letters, digits and ._:-; otherwise the gateway makes a new UUID.

Match^[A-Za-z0-9._:-]{1,128}$

Request Body

application/json
  1. body

Anthropic's Messages request. The gateway checks model, max_tokens, messages and stream; any other field is passed to the model unchanged. The fields below are the ones most requests use. See Anthropic's reference for all of them.

model*ModelName

A canonical model id (anthropic/claude-sonnet-5-5) or an alias (claude-sonnet-5-5, claude-sonnet-5.5), in any letter case. Surrounding spaces are ignored.

Length1 <= length <= 128
max_tokens*integer

The most tokens the model may generate, thinking included. Up to the model's maxOutputTokens in GET /api/models.

Range1 <= value
messages*array<>

The conversation, as user and assistant turns. Content is a string or an array of content blocks (text, images, documents, tool calls and tool results).

Items1 <= items
system?|array<>

The system prompt, as a string or an array of text blocks (which can carry cache_control).

stream?boolean

Send the reply as Server-Sent Events.

tools?array<>

Tools the model may call, each with a name, description and JSON Schema input_schema. Server tools (such as web search and code execution) aren't supported.

tool_choice?

How the model may use tools: auto, any, tool (a named tool) or none.

thinking?

Extended thinking, for example {"type": "adaptive"}.

output_config?

Output settings such as effort and format (structured outputs).

temperature?number

Sampling temperature. Models without capabilities.sampling in GET /api/models only run at their default, and the provider refuses other values.

top_p?number

Nucleus sampling. Like temperature, only for models with capabilities.sampling.

top_k?integer

Top-k sampling. Like temperature, only for models with capabilities.sampling.

stop_sequences?array<string>

Strings that end the reply when the model writes them.

metadata?

Request metadata, such as user_id.

cache_control?

An Anthropic prompt-cache breakpoint. The cache lasts 5 minutes by default, or 1 hour with "ttl": "1h".

[key: string]?any

Response Body

The model's reply. With "stream": true, a text/event-stream instead: each event's data line is one of the events below, and its event line names the event's type. Events arrive in this order: message_start, then for each content block content_block_start, any number of content_block_delta and content_block_stop, then message_delta and message_stop. ping events can arrive at any time: the gateway sends one after 15 seconds without output. Ignore event types you don't know.

If the request fails before the first event, you get a normal JSON error response. If it fails after the stream started, the stream sends an error event and ends.

  1. response

The model's reply, as the provider returned it, with model set to the name you sent.

id*string
type*string
role*string
model*string

The model name exactly as you sent it.

content*array<|||>
stop_reason*|

Why the model stopped, such as end_turn, max_tokens, stop_sequence, tool_use, pause_turn or refusal. null only in message_start.

stop_sequence*|

The stop sequence that ended the reply, if one did.

usage*

Token counts for the request. You are billed for these at the model's prices.

[key: string]?any
curl -X POST 'https://api.router.ezat.io/v1/messages' \  -H "x-api-key: $EZAT_API_KEY" \  -H 'Content-Type: application/json' \  -d '{  "model": "anthropic/claude-sonnet-5-5",  "max_tokens": 1024,  "messages": [    {      "role": "user",      "content": "Hello, what can you do?"    }  ]}'
Example Response
{  "id": "msg_01XFDUDYJgAACzvnptvVoYEL",  "type": "message",  "role": "assistant",  "model": "anthropic/claude-sonnet-5-5",  "content": [    {      "type": "text",      "text": "Hello! I can answer questions, write and review code, and help with analysis."    }  ],  "stop_reason": "end_turn",  "stop_sequence": null,  "usage": {    "input_tokens": 14,    "output_tokens": 21,    "cache_creation_input_tokens": 0,    "cache_read_input_tokens": 0  }}