Skip to content
RU

Chat and streaming

POST /v1/chat/completions is the main endpoint. Request and response match OpenAI, so any compatible SDK works.

Field Type Description
model string, required Catalog identifier or alias (gpt-4o, claude-opus)
messages array, required Conversation so far; the last user message is the prompt
stream boolean true streams the answer over SSE
stream_options object {"include_usage": true} appends a final chunk with token usage
temperature number As in OpenAI. Not every model takes it: GPT-5.x/5.6/6 and Claude have none — check supported_parameters in GET /models
max_tokens integer Ceiling on answer length
max_completion_tokens integer Synonym for max_tokens, for newer SDKs
reasoning_effort string Reasoning depth: off, low, medium, high, xhigh or max — the set depends on the model, see reasoning effort. For routers (typesafe/jev-router) it is a hint: the router picks the effort itself and may override it
tools array Tool descriptions in the OpenAI format; passed to the model as is — how to use
tool_choice string | object auto, none, required, or a specific tool
web_search bool | string true/"auto" — the model’s native search where available, else Exa; "native"/"exa" — explicit. Sources arrive in message.annotations; full guide — web search
response_format object {"type": "json_object"} or {"type": "json_schema", …} — guaranteed JSON — structured output
stop array Up to 4 stop sequences: generation ends as soon as one appears in the answer
seed integer Sampling seed — best-effort reproducibility
top_p number 0–1 Nucleus sampling: only the most likely tokens covering this probability mass
top_k integer Keep the K most likely tokens. Available on open-weight models
min_p number 0–1 Drop tokens below this share of the top token’s probability
frequency_penalty number −2…2 Penalty grows with how often the token already appeared
presence_penalty number −2…2 Penalty for the token appearing at all
repetition_penalty number 0–2 Penalty for repeating the prompt and the answer so far
logprobs boolean Return log probabilities of the chosen tokens
top_logprobs integer 0–20 Alternatives per position to return; requires logprobs
provider object Route selection: order, only, ignore, sort — provider routing
service_tier string flex — cheaper and slower, priority — dearer and faster; not every model has a tier
plugins array Upstream plugins as-is; for typesafe/jev-router — a custom model pool: [{"id": "jev-router", "models": ["anthropic/*", "openai/gpt-6*"]}] (fields models/allowed_models, excluded_models, cost_tier)

Models accept different parameter sets: the upstream drops what a model does not know instead of erroring. The actual list per model is in the supported_parameters field of GET /models.

typesafe/jev-router picks the model and reasoning effort for each request itself — the model that actually served the request arrives in the served_model response field (in streaming: a separate chunk with empty choices before the usage chunk). The field appears only when the served model differs from the requested one. Billing follows the chosen model’s rates.

stream = client.chat.completions.create(
model="gpt-5.6-luna",
messages=[{"role": "user", "content": "Write a haiku about deadlines"}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)

The stream is text/event-stream and ends with data: [DONE]. With include_usage, a chunk carrying usage arrives just before it — a convenient place to log spend: it also carries cost / cost_rub, what the request was charged (see Tokens and charges).

The usage also carries prompt_tokens_details.cached_tokens — how many input tokens came from the context cache. See Context caching.

Models with capabilities.vision: true accept an image inside a message:

resp = client.chat.completions.create(
model="gpt-5.6-terra",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "What's wrong with this chart?"},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KG..."}},
],
}],
)

Only data: URLs (data:image/png;base64,...) are accepted, in the last user message — external HTTP links are not supported, so base64-encode the image.

Models with capabilities.file: true take up to 5 files per request. Formats: PDF, DOCX, TXT, CSV, XLSX, PPTX — the text is extracted and handed to the model as context:

{
"role": "user",
"content": [
{"type": "text", "text": "Summarise the Risks section"},
{"type": "file", "file": {"filename": "report.pdf", "file_data": "data:application/pdf;base64,JVBERi0..."}}
]
}

Each file yields at most 150,000 characters; longer ones are cut with a [...truncated] marker appended. There is no OCR: an image-only PDF scan comes back empty — use documents with a text layer.

A model that cannot read files returns 400, so check the flag in the catalog first.

Models with audio input (in the catalog: capabilities.audio: true, e.g. google/gemini-4-argon) take sound as an input_audio content part:

{
"role": "user",
"content": [
{"type": "text", "text": "Transcribe this recording and list the agreements"},
{"type": "input_audio", "input_audio": {"data": "//uQx...", "format": "mp3"}}
]
}

The data field is raw base64 without the data:audio/...;base64, prefix (unlike images); the format is a separate field: mp3, wav, flac, pcm16. Audio tokens are billed at a separate audio-input rate (on multimodal models it can differ from the text one — see the Providers panel on the model page); repeated requests with the same audio hit the audio cache at a discount.

Some models let you dial reasoning depth. The accepted values arrive in capabilities.reasoning_efforts — usually low, medium, high, xhigh, max.

{"model": "claude-opus-4.8", "reasoning_effort": "high", "messages": [...]}

Two things to watch:

  • Reasoning consumes the max_tokens budget. If you expect long JSON from a model that reasons, set the ceiling generously or the answer gets cut mid-structure. Truncation is visible in the response: finish_reason: "length" (or stop_reason: "max_tokens" on /v1/messages), so you can detect it programmatically and continue.
  • Reasoning cannot always be switched off — check capabilities.can_disable_reasoning. Where it reads false, the model always reasons, and the price reflects that.

Models with type: search (the Perplexity Sonar family) reach the internet themselves. There is no separate endpoint or tool — just name one:

curl https://api.mixen.ai/v1/chat/completions \
-H "Authorization: Bearer $MIXEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"sonar-pro","messages":[{"role":"user","content":"What did Anthropic ship this week?"}]}'

On a scoped key these models need the search scope rather than chat.

The web_search parameter — search on any model

Section titled “The web_search parameter — search on any model”

Web search can also be enabled on any other text model with the web_search parameter:

{
"model": "google/gemini-3.8-flash",
"web_search": "native",
"messages": [{"role": "user", "content": "What is the central bank USD rate today? One line with a source"}]
}

Values: true/"auto" — the model’s native search where available, else Exa; "native" — the provider’s built-in search; "exa" — neutral search. Native search exists on OpenAI, Anthropic, Google and xAI models — the catalog marks them with capabilities.native_search: true; sources arrive in message.annotations (url_citation), same as Sonar. When streaming, they come as a separate chunk carrying delta.annotations right before the final chunk with finish_reason. "native" on a model without built-in search is silently downgraded to "auto". Billing, the balance reserve and Sonar’s behaviour are covered in the Web search guide.

Search is billed per performed request (not per token): the price sits next to the model in the catalog (web_search_rub_per_request in GET /v1/models). The model decides on its own whether and how many times to search — a question like “what is a fraction” triggers none.

Besides /v1/chat/completions, two more chat protocols run on the same key and balance:

  • POST /v1/messages — Anthropic-compatible (Claude Code, Anthropic SDK): accepts thinking.budget_tokens, cache_control and tool-use; there is also POST /v1/messages/count_tokens. See Claude Code.
  • POST /v1/responses — the OpenAI Responses API (Codex CLI): stateless, accepts reasoning.effort. See Codex CLI.