Core API

Streaming

Consume OpenAI-compatible server-sent events without dropping usage or terminal frames.

On this page

This page is for developers building low-latency output or a typewriter interface with Chat Completions.

Set stream: true to receive server-sent events. The gateway forwards SSE bytes without reframing them. If you omit stream_options, the gateway adds {"include_usage":true} so the final chunk can report usage.

Inspect raw SSE with curl#

BashSyntax highlighted
curl -N https://api.clssai.com/v1/chat/completions \
  -H "Authorization: Bearer $CLSSAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/gpt-5.4-nano","messages":[{"role":"user","content":"Count to three."}],"stream":true}'

Each event carries a data: line. Append choices[0].delta.content when present. The terminal chunk carries usage. Depending on the upstream provider, it may repeat the final choice or send choices: [], so always check the array length before indexing. After that chunk, data: [DONE] ends the stream.

Plain textPlain rendering
data: {"choices":[{"index":0,"delta":{"content":"One"},"finish_reason":null}],"usage":null}

data: {"choices":[{"index":0,"delta":{"content":""},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":3,"total_tokens":15}}

data: [DONE]

Stream with Python#

PythonSyntax highlighted
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.clssai.com/v1", api_key=os.environ["CLSSAI_API_KEY"])
stream = client.chat.completions.create(
    model="openai/gpt-5.4-nano",
    messages=[{"role": "user", "content": "Count to three."}],
    stream=True,
)

for chunk in stream:
    if chunk.choices:
        print(chunk.choices[0].delta.content or "", end="", flush=True)
    if chunk.usage:
        print(f"\nUsage: {chunk.usage}")

Stream with JavaScript#

JavaScriptSyntax highlighted
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.clssai.com/v1",
  apiKey: process.env.CLSSAI_API_KEY,
});
const stream = await client.chat.completions.create({
  model: "openai/gpt-5.4-nano",
  messages: [{ role: "user", content: "Count to three." }],
  stream: true,
});

for await (const chunk of stream) {
  if (chunk.choices.length > 0) process.stdout.write(chunk.choices[0].delta.content ?? "");
  if (chunk.usage) console.log("\nUsage:", chunk.usage);
}

Cancellation and retries#

Cancel with the SDK abort mechanism or an AbortController. Once any streamed bytes have reached the client, do not retry transparently: a second request can duplicate output or work. Retry only failures that occur before the first event, and apply bounded exponential backoff.

Common mistakes#

  • Check for an empty choices array before accessing choices[0].
  • Do not stop before reading the final usage chunk and [DONE].
  • Do not retry after the stream has started.
  • Include /v1 in the OpenAI SDK base URL, but omit /v1 from the Anthropic SDK base URL.
  • Run streams from your server, not browser JavaScript.
  • Preserve full author/model:free and author/model:batch IDs.
  • Use cf-ray when tracing an inference request.
Need a hand?

Find answers to common questions or diagnose a failed request.

Frequently asked questions →Troubleshoot errors →