EZAT RouterDocs

Create a chat completion

POST
/openai/v1/chat/completions

Sends a conversation to a model and returns its reply, in OpenAI's Chat Completions format. Set "stream": true to receive chat.completion.chunk events.

The request is translated to Anthropic's Messages format and runs through the same gateway as POST /v1/messages: the same limits, routing, failover and prices.

  • Messages. system and developer messages are joined into the system prompt, wherever they appear. Assistant tool_calls and tool messages become tool calls and tool results, and consecutive messages from the same side are merged.
  • Images and PDFs. image_url parts accept base64 data URLs and http(s) URLs, which the gateway downloads (JPEG, PNG, GIF or WebP; public hosts only; up to 10 MB per image, 32 MB and 20 URLs per request; 15 seconds and 3 redirects per download). PDFs go in file parts as a base64 file_data data URL.
  • Prompt caching is automatic. When the model supports caching and the request marks no breakpoints of its own, the gateway adds up to two: one at the end of the system prompt (or of the tools, when there is no system prompt) and one on the newest message, which the next turn reads back. Send x-ezat-cache: off to opt out. To place breakpoints yourself, add Anthropic's cache_control to content parts or tools.
  • Refused with 400, because they would change the result and have no equivalent: n other than 1, logprobs, top_logprobs, a non-empty logit_bias, audio (modalities other than text, audio, input_audio parts), web_search_options, the legacy functions and function_call, the function role, response_format of type json_object, and file_id.
  • Ignored: every field not listed in the request schema, such as user, seed, presence_penalty, frequency_penalty, store, metadata and service_tier.
  • Not returned: the model's thinking text. Thinking tokens are counted in usage.

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

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-ezat-cache?"off"

Send off (in any letter case) to stop the gateway from adding prompt-cache breakpoints to this request. Breakpoints you place yourself with cache_control still apply.

Value in"off"
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

OpenAI's Chat Completions request. The gateway translates the fields below; it ignores any other field.

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
messages*array<|||>

The conversation. It must contain at least one user or assistant message.

Items1 <= items
stream?|

Send the reply as chat.completion.chunk events.

stream_options?|null
max_completion_tokens?|

The most tokens the model may generate, thinking included. Takes precedence over max_tokens. With neither, the limit is 32,000 tokens, or the model's maxOutputTokens when that is lower.

Range1 <= value
max_tokens?|

The older name for max_completion_tokens.

Range1 <= value
temperature?|

Values above 1 are sent as 1. Used only by models with capabilities.sampling in GET /api/models, and only while thinking is off; otherwise dropped.

Range0 <= value <= 2
top_p?|

Used only below 1, by models with capabilities.sampling, and only while thinking is off; otherwise dropped.

Range0 <= value <= 1
stop?|array<string>|

Stop sequences. The reply ends when the model writes one.

tools?array<>|

Function tools. strict and Anthropic's cache_control (on the tool) are passed on.

tool_choice?||

auto, none, required (the model must call a tool) or {"type": "function", "function": {"name": …}}. Dropped when there are no tools. Some models refuse a forced tool choice.

parallel_tool_calls?|

false allows at most one tool call per reply.

response_format?||

text, or json_schema for JSON that follows a schema (objects need "additionalProperties": false). json_object is refused with 400: use json_schema.

reasoning_effort?|

Turns on the model's thinking at this effort. none and minimal run at the lowest effort without thinking. Thinking is also left off when tool_choice forces a tool call. Not every model offers every level (the provider refuses the others).

Value in"none""minimal""low""medium""high""xhigh""max"null
prompt_cache_key?|

Names the conversation, like the x-ezat-session header, so its turns reuse one prompt cache.

Lengthlength <= 256
n?|

Only 1 is supported.

Range1 <= value
logprobs?|

Not available; true is refused.

top_logprobs?|

Not available; any value other than 0 is refused.

logit_bias?|

Not supported; a non-empty object is refused.

modalities?array<string>|

Only text output is supported.

[key: string]?any

Response Body

The completion. With "stream": true, a text/event-stream instead: each data: line is a chat.completion.chunk, and the stream ends with data: [DONE]. The first chunk carries delta.role and the last choice chunk carries finish_reason. With stream_options.include_usage, one more chunk with empty choices and the usage comes just before [DONE]. Lines starting with : are keep-alive comments: the gateway sends one after 15 seconds without output.

If the request fails before the first chunk, you get a normal JSON error response. If it fails after the stream started, the stream sends a data: line with an error object, then data: [DONE].

  1. response
id*string

chatcmpl- followed by the request-id.

object*string
created*integer

Unix time in seconds.

model*string

The model name exactly as you sent it.

choices*array<>
Items1 <= items <= 1
usage*
curl -X POST 'https://api.router.ezat.io/openai/v1/chat/completions' \  -H "Authorization: Bearer $EZAT_API_KEY" \  -H 'Content-Type: application/json' \  -d '{  "model": "anthropic/claude-sonnet-5-5",  "messages": [    {      "role": "system",      "content": "You are a concise assistant."    },    {      "role": "user",      "content": "Hello, what can you do?"    }  ]}'
Example Response
{  "id": "chatcmpl-019a3f2e-8c41-7d2b-9e57-3b6f0c1d2a4e",  "object": "chat.completion",  "created": 1793376000,  "model": "anthropic/claude-sonnet-5-5",  "choices": [    {      "index": 0,      "message": {        "role": "assistant",        "content": "Hello! I can answer questions, write and review code, and help with analysis.",        "refusal": null      },      "logprobs": null,      "finish_reason": "stop"    }  ],  "usage": {    "prompt_tokens": 25,    "completion_tokens": 21,    "total_tokens": 46,    "prompt_tokens_details": {      "cached_tokens": 0,      "cache_write_tokens": 0    },    "completion_tokens_details": {      "reasoning_tokens": 0    }  }}