Documentation
API reference
Streaming
Set stream:true to receive the completion as a Server-Sent Events stream of delta chunks, terminated by a [DONE] sentinel.
Enabling streaming
Add "stream": true to a chat completions request. The response content type becomes text/event-stream and the body is delivered as SSE events instead of a single JSON object. Everything else about the request is unchanged.
Pass --no-buffer to curl so the terminal prints each chunk as it arrives rather than waiting for the connection to close.
curl https://api.advancedmind.ai/v1/chat/completions \
-H "Authorization: Bearer $AMAI_API_KEY" \
-H "Content-Type: application/json" \
--no-buffer \
-d '{
"model": "Klara-base-preview-v1",
"messages": [
{ "role": "user", "content": "Outline a literature review on the topic." }
],
"max_tokens": 1024,
"stream": true
}'Reading delta chunks
Each event is a line beginning with data: followed by a JSON object of type chat.completion.chunk. Events are separated by a blank line. The first chunk carries the assistant role; subsequent chunks carry incremental delta.content. Concatenate the delta.content values in order to assemble the full message.
When generation stops, a chunk arrives with a non-null finish_reason (for example stop or length). A final chunk then carries the usage totals and the advancedmind object (route, access, and cost), the same record a non-streaming call returns. The stream then ends with the sentinel line data: [DONE].
data: {"id":"chatcmpl_8sQ2f1Kd9vTb","object":"chat.completion.chunk","model":"Klara-base-preview-v1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl_8sQ2f1Kd9vTb","object":"chat.completion.chunk","model":"Klara-base-preview-v1","choices":[{"index":0,"delta":{"content":"A literature"},"finish_reason":null}]}
data: {"id":"chatcmpl_8sQ2f1Kd9vTb","object":"chat.completion.chunk","model":"Klara-base-preview-v1","choices":[{"index":0,"delta":{"content":" review on"},"finish_reason":null}]}
data: {"id":"chatcmpl_8sQ2f1Kd9vTb","object":"chat.completion.chunk","model":"Klara-base-preview-v1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl_8sQ2f1Kd9vTb","object":"chat.completion.chunk","model":"Klara-base-preview-v1","choices":[],"usage":{"prompt_tokens":58,"completion_tokens":212,"total_tokens":270},"advancedmind":{"request_id":"req_b4f01c9a2e7d","public_model":"Klara-base-preview-v1","provider":"advancedmind-ai","route":{"public_model":"Klara-base-preview-v1","provider":"advancedmind-ai","region":"managed","custom_customer_min_charge_usd":59.3},"access":{"tier":"standard","research_mode":false},"cost":{"input_tokens":58,"output_tokens":212,"customer_charge_usd":59.3,"currency":"USD"}}}
data: [DONE]The [DONE] sentinel
data: [DONE] is the literal end marker. It is not JSON; do not attempt to parse it. Treat it as the signal to stop reading and close the stream. Always read until [DONE] so the usage chunk is captured and the connection is released cleanly. If your client aborts first, it will not receive the final usage chunk; use the usage page and request id for the settled record.
Errors during a stream
Credits are checked before the provider is called, so most failures (insufficient_credits, invalid_api_key, research_access_required, model_not_allowed) arrive before any chunk, as a normal JSON error body with the matching status code. Check res.ok before reading the stream. See Errors for the full list.
Reading the stream in JavaScript
Use fetch with a ReadableStream reader. Buffer the bytes, split on the blank-line event boundary, and parse each data: line. Keep the request_id from the final chunk for tracing.
const controller = new AbortController();
const res = await fetch("https://api.advancedmind.ai/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AMAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "Klara-base-preview-v1",
messages: [{ role: "user", content: "Outline a literature review on the topic." }],
max_tokens: 1024,
stream: true,
}),
signal: controller.signal,
});
if (!res.ok || !res.body) {
// Errors arrive as a normal JSON body, not as a stream.
throw new Error(await res.text());
}
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let requestId;
read: while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// SSE events are separated by a blank line.
let boundary;
while ((boundary = buffer.indexOf("\n\n")) !== -1) {
const event = buffer.slice(0, boundary);
buffer = buffer.slice(boundary + 2);
for (const line of event.split("\n")) {
if (!line.startsWith("data:")) continue;
const payload = line.slice(5).trim();
if (payload === "[DONE]") break read;
const chunk = JSON.parse(payload);
const delta = chunk.choices?.[0]?.delta?.content;
if (delta) process.stdout.write(delta);
// The final chunk carries usage and the advancedmind object.
if (chunk.advancedmind) requestId = chunk.advancedmind.request_id;
}
}
}
// Stop early at any time:
// controller.abort();Stopping and aborting
To stop reading locally, abort the connection. With fetch, call controller.abort() on the AbortController whose signal you passed in. This closes your client connection; it does not cancel server-side settlement. The gateway continues reading the provider result so it can capture exact terminal usage, and the final charge still appears in your usage records. For Klara Base Preview, the published request minimum still applies even when the client disconnects.
Next
- Chat completions: the full request and response shape.
- Errors: status codes and how to recover.