Docs

Start here

Ask a question

POST/v1/chaton https://api.auray.ai/v1

Answers in the same call.

Answers in the same call. stream:false returns the finished answer; stream:true writes Server-Sent Events carrying the same frames. conversation_id is optional — omit it for a one-off and a thread is minted. A stream carries an SSE comment line whenever nothing was written for fifteen seconds. A blocking answer not ready in twenty seconds is committed as 200 at once and its body starts with spaces, which JSON parsers skip; a failure after that is the error body under that 200. Closing the connection stops the turn: it settles at what was delivered, and a turn that produced nothing — no text, no reasoning, no tool call — and reported no usage is refunded in full.

#Authentication

Authorization: Bearer auray_sk_… — text:write, or the older chat:write.

#Request

#Body

application/json, required.

FieldTypeRequiredDefaultDescription
modelstringno—Required unless conversation_id names a thread of yours, whose own model is then used — the model the thread was made with is the default for its turns, and a different one is always named here explicitly (and wins). The first three are the slots. qwen and kimi are the names these slots carried until 2026-09-14 and are still accepted, mapped to glm-5-3-flash and deepseek-v4-1-flash respectively; they named models neither slot has served since 2026-09-12 and will be withdrawn once integrations have moved. No model and no thread of yours is 400 unknown_model, as it always was. One of "glm-5-3-flash", "deepseek-v4-1-flash", "kimi-k3", "qwen", "kimi".
effortstringno"balanced"One of "light", "balanced", "deep".
textstringyes—
conversation_idstringno—
streambooleannofalse
include_reasoningbooleannofalse
idempotency_keystringno—Your own id for this turn. CHAT DOES NOT REPLAY: unlike the four job products, sending the same key twice is refused — 409 key_settled once the first turn finished, 409 in_flight while it is still running — key_settled always carries the original message_id; in_flight carries it once the turn's row exists and null before that. Read that turn rather than re-sending. Idempotency-Key: as a header is accepted as an alias, and the body's key wins when both are sent. No colon, because a credit key is <product>:<user>:<this>.

#Example request

curl -X POST https://api.auray.ai/v1/chat \
  -H "Authorization: Bearer $AURAY_API_KEY" \
  -H "content-type: application/json" \
  -d '{
  "model": "glm-5-3-flash",
  "text": "In two sentences: why does a retried request need an idempotency key?"
}'

#Responses

#200 OK

The finished turn, or an SSE stream when stream:true.

FieldTypeRequiredDefaultDescription
idstringno—
job_idstringno—The job's one id on every host: id here, request_id on the queue host (the queue protocol's name for it).
objectstringno—One of "chat.turn".
statusstringno—One of "succeeded", "failed".
conversation_idstringno—
conversation_createdbooleanno—
history_scrubbedbooleanno—True when the conversation this turn continues was scrubbed three days after its last activity: its earlier turns are gone, and this answer was written without them. Continue in a new conversation, or send the context again.
history_budget_bytesintegerno—Your plan's chat.context_budget in force (GET /plans prints it per plan): how much of the thread this turn could send, this message included, counted in bytes, not tokens — each message's UTF-8 text plus 64, and 128 a turn. This message counts first and is always sent whole, even alone over the budget; earlier messages are kept newest first while the total fits, one longer than a quarter of the budget shortened to that quarter, and the oldest past it are left out.
history_trimmedobjectno—What the history budget left out of the thread this turn re-sent, null when it sent all of it. The model answered without what was dropped; continue in a new conversation, or send the context that matters again. Also sent as the X-Auray-History-Trimmed header. May be null.
history_trimmed.droppedintegeryes—Earlier messages left out whole, oldest first.
history_trimmed.shortenedintegeryes—Earlier messages cut to a quarter of the budget to fit, each marked as shortened; a cut answer keeps its end.
message_idstringno—
contentstringno—
reasoningstringno—
usageobjectno—May be null.
finish_reasonstringno—Why the model stopped: stop when it finished, length when max_output_tokens or the ceiling stopped it — the plan's, or the model's own where it cannot write the plan's inside one turn's time (GET /openai/v1/models prints it per model) — tool_calls; null when the stream ended before it said. length beside status: failed and error: output_limit_reached means the whole limit — the token ceiling, or the time one turn may run — went on reasoning before a word of answer, and the turn was refunded — send it again with a lower effort. May be null.
credits_reservedintegerno—Chat reserves the worst case and settles down to what the model produced. 0 for a turn a promotion paid for (waived: true): nothing was taken from the wallet.
credits_chargedintegerno—What the turn cost — the ledger's net. 0 for a turn a promotion paid for (waived: true). Null, with settled_unknown: true, when the ledger could not be read. May be null.
credits_remainingintegerno—The wallet after this turn; null, with settled_unknown: true, when it could not be read. May be null.
productstringno—Always chat. One of "chat".
modelstringno—The slot that answered. A request may still name a slot by its pre-2026-09-14 alias (qwen, kimi); a response never does — it is always the slot's own name, so the old spellings are not in this enum. One of "glm-5-3-flash", "deepseek-v4-1-flash", "kimi-k3".
effortstringno—NOT THE VALUE YOU SENT. The request takes a ladder — light, balanced, deep — and this reports what that mapped to on the chosen slot, which differs between them: glm-5-3-flash and deepseek-v4-1-flash run low/medium/max, kimi-k3 runs low/high/max. Sending one of these back as effort is 400 unknown_effort. One of "low", "medium", "high", "max".
errorstringno—Present only when status is failed, and then it is the reason.
waivedbooleanno—Present, and true, when a promotion paid for the turn and the wallet was not charged.
settled_unknownbooleanno—Present, and true, when the answer was delivered and its figures could not be read.

Headers:

HeaderDescription
RateLimit-LimitBurst capacity.
RateLimit-Remaining
RateLimit-ResetSeconds until refill.
X-RateLimit-Limit
X-RateLimit-Remaining
X-RateLimit-ResetUnix seconds. The X- spelling is what client libraries read.
X-Request-Id
X-Auray-History-Trimmeddropped=<n>, shortened=<n> when your plan's history budget left part of the thread out of this turn (history_trimmed in the body); absent when it sent all of it.

#400 Bad Request

#401 Unauthorized

#402 Payment Required

#403 Forbidden

#404 Not Found

conversation_not_found — the conversation exists and belongs to somebody else. An id you have never used is NOT an error: chat mints the conversation at that id and reports conversation_created: true.

The error body: error, message, docs (the entry that explains it) and request_id.

#409 Conflict

#413 Payload Too Large

#429 Too Many Requests

#500 Internal Server Error

credit_reserve_failed or chat_start_failed — ours, not yours. Where a charge had already landed it is reversed; retry with a fresh idempotency key, since a reversal leaves the old one settled.

The error body: error, message, docs (the entry that explains it) and request_id.

#502 Bad Gateway

#503 Service Unavailable

#504 Gateway Timeout

model_timeout — the model took the request and stopped answering before its first word, or answered 408. The reserve is returned at once; retry with a new idempotency key.

The error body: error, message, docs (the entry that explains it) and request_id.

#Status codes

StatusMeaning
200The finished turn, or an SSE stream when stream:true.
400Bad Request
401Unauthorized
402Payment Required
403Forbidden
404conversation_not_found — the conversation exists and belongs to somebody else.
409Conflict
413Payload Too Large
429Too Many Requests
500credit_reserve_failed or chat_start_failed — ours, not yours.
502Bad Gateway
503Service Unavailable
504model_timeout — the model took the request and stopped answering before its first word, or answered 408.

Every refusal names its code, and every code is explained at Errors.

Start typing to search every page of the documentation.

Up arrow Down arrow to moveEnter to openEscape to close