Streaming
Menu
Getting started

Streaming

Receive model output incrementally with Server-Sent Events.

Overview

Chat-style endpoints can stream the response as Server-Sent Events (SSE), so you can show tokens as soon as they are generated. The response has Content-Type: text/event-stream; each event is a data: line followed by a blank line.

Endpoint How to enable End of stream
POST /v1/chat/completions "stream": true data: [DONE]
POST /v1/completions "stream": true data: [DONE]
POST /v1/responses "stream": true response.completed event
POST /v1/messages "stream": true message_stop event
POST /v1beta/models/{model}:streamGenerateContent?alt=sse Use the streamGenerateContent action Connection closes

OpenAI Chat Completions

bash
curl https://rutoken.ai/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_KEY" \
  -N \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{"role": "user", "content": "Write a haiku about the sea."}],
    "stream": true,
    "stream_options": {"include_usage": true}
  }'

Each chunk carries a delta with the next piece of the message:

text
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1760000000,"model":"gpt-4o-mini","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1760000000,"model":"gpt-4o-mini","choices":[{"index":0,"delta":{"content":"Waves"},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1760000000,"model":"gpt-4o-mini","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1760000000,"model":"gpt-4o-mini","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":17,"total_tokens":31}}

data: [DONE]

Token usage

Set stream_options.include_usage to true to receive a final chunk with an empty choices array and a usage object. Without it, streamed chunks carry no usage. Billing is the same either way.

Tool calls

When the model calls a tool, delta.tool_calls arrives in pieces: the first piece has id and function.name, later pieces append to function.arguments. Concatenate the arguments by index until finish_reason is tool_calls.

OpenAI Responses

POST /v1/responses with "stream": true emits typed events. The event: line names the type:

text
event: response.created
data: {"type":"response.created","response":{"id":"resp_123","status":"in_progress"}}

event: response.output_text.delta
data: {"type":"response.output_text.delta","output_index":0,"content_index":0,"delta":"Waves"}

event: response.completed
data: {"type":"response.completed","response":{"id":"resp_123","status":"completed","usage":{"input_tokens":14,"output_tokens":17,"total_tokens":31}}}

Usage is included in response.completed. See Responses.

Claude Messages

POST /v1/messages with "stream": true follows the Anthropic event sequence: message_start, content_block_start, content_block_delta (text in delta.text, thinking in delta.thinking, tool input in delta.partial_json), content_block_stop, message_delta (with stop_reason and output usage), message_stop. ping events may appear at any time.

text
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Waves"}}

See Claude Messages.

Gemini

Call the streamGenerateContent action with alt=sse. Each event is a complete GenerateContentResponse holding the next fragment; usageMetadata is reported in the final events.

bash
curl "https://rutoken.ai/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $API_KEY" \
  -N \
  -d '{"contents": [{"role": "user", "parts": [{"text": "Write a haiku about the sea."}]}]}'
text
data: {"candidates":[{"content":{"role":"model","parts":[{"text":"Waves"}]}}],"modelVersion":"gemini-2.5-flash"}

See Gemini generateContent.

Client examples

Python
from openai import OpenAI

client = OpenAI(base_url="https://rutoken.ai/v1", api_key="sk-xxxx")
stream = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Write a haiku about the sea."}],
    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)
    if chunk.usage:
        # the last chunk carries token usage
        print("\n", chunk.usage)
Node.js
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://rutoken.ai/v1", apiKey: "sk-xxxx" });
const stream = await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: "Write a haiku about the sea." }],
  stream: true,
  stream_options: { include_usage: true },
});
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
  // the last chunk carries token usage
  if (chunk.usage) console.log("\n", chunk.usage);
}
Python (Claude)
import anthropic

client = anthropic.Anthropic(base_url="https://rutoken.ai", api_key="sk-xxxx")
with client.messages.stream(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a haiku about the sea."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
Python (Gemini)
from google import genai

client = genai.Client(api_key="sk-xxxx", http_options={"base_url": "https://rutoken.ai"})
for chunk in client.models.generate_content_stream(
    model="gemini-2.5-flash",
    contents="Write a haiku about the sea.",
):
    print(chunk.text or "", end="", flush=True)

Notes

  • If you put your own reverse proxy in front of the API, disable response buffering (e.g. proxy_buffering off in nginx), otherwise chunks arrive in bursts.
  • Long generations can take minutes; use a generous read timeout.
  • If an error occurs after the stream has started, the HTTP status stays 200. Handle error events and streams that end without a final event. See Errors.