API
Streaming
Server-sent events in OpenAI's chunk format, with usage in the last chunk.
Pass "stream": true to /v1/chat/completions and the reply arrives as server-sent events in OpenAI's chat.completion.chunk format, ending with data: [DONE]. For Anthropic events, see Anthropic Messages.
Stream a reply
curl -N https://api.azrouter.dev/v1/chat/completions \
-H "Authorization: Bearer $AZROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen/qwen3.8-flash",
"messages": [{"role": "user", "content": "Reply with exactly: Hello from AZRouter"}],
"max_tokens": 200,
"stream": true,
"stream_options": {"include_usage": true}
}'The end of the stream, with each chunk trimmed to the fields that matter. A reasoning model sends its thinking first, in delta.reasoning, then the answer in delta.content:
data: {"object":"chat.completion.chunk","model":"qwen/qwen3.8-flash","choices":[{"index":0,"delta":{"content":"Hello from AZ","role":"assistant"},"finish_reason":null}]}
data: {"object":"chat.completion.chunk","model":"qwen/qwen3.8-flash","choices":[{"index":0,"delta":{"content":"Router","role":"assistant"},"finish_reason":null}]}
data: {"object":"chat.completion.chunk","model":"qwen/qwen3.8-flash","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop"}]}
data: {"object":"chat.completion.chunk","model":"qwen/qwen3.8-flash","choices":[{"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":"stop"}],"usage":{"prompt_tokens":69,"completion_tokens":38,"total_tokens":107}}
data: [DONE]Usage in the stream
With "stream_options": {"include_usage": true}, the last chunk before [DONE] carries usage. On AZRouter that chunk also repeats the finish_reason in choices, where OpenAI sends an empty choices array, so read usage whenever it is present rather than only when choices is empty.
With the OpenAI SDK
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.azrouter.dev/v1",
apiKey: process.env.AZROUTER_API_KEY,
});
const stream = await client.chat.completions.create({
model: "qwen/qwen3.8-flash",
messages: [{ role: "user", content: "Reply with exactly: Hello from AZRouter" }],
max_tokens: 200,
stream: true,
stream_options: { include_usage: true },
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
if (chunk.usage) console.log("\n", chunk.usage);
}Save it as an ES module (stream.mts) and run npx tsx stream.mts; top-level await fails in a CommonJS .ts file.
A stream is billed like the same request without streaming: by the tokens in its usage.