Skip to main content
Lesson 13 of 16 · Responses API: Primary Endpoint

Streaming SSE

Lesson 13 of 16 Updated July 30, 2026 Developer
On this page
  1. Real-time responses
  2. Enable streaming
  3. Event types
  4. Streaming in Python
  5. Streaming with tools
  6. Frontend integration
  7. Streaming and billing
  8. Key takeaways

Real-time responses

In normal mode, you wait for the model to finish generating the complete response before receiving it. With SSE streaming (Server-Sent Events), tokens arrive as they are generated. This is essential for conversational interfaces where users want to see the response appear progressively.

SSE
Server-Sent Events
~50ms
First token visible
text/event-stream
Content-Type
stream: true
Single parameter

Enable streaming

Add "stream": true to your request:

curl https://api.x.ai/v1/responses \
  -H "Authorization: Bearer $XAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-4.20-0309-reasoning",
    "input": "Write a poem about programming.",
    "stream": true
  }'

The response arrives as an SSE stream:

data: {"type": "response.created", "response": {...}}
data: {"type": "response.output_item.added", ...}
data: {"type": "response.content_part.added", ...}
data: {"type": "response.output_text.delta", "delta": "La "}
data: {"type": "response.output_text.delta", "delta": "programmation "}
data: {"type": "response.output_text.delta", "delta": "est "}
...
data: {"type": "response.completed", "response": {...}}

Event types

EventDescription
response.createdGeneration starts
response.output_item.addedNew item in output
response.content_part.addedNew content part
response.output_text.deltaText fragment (most frequent)
response.output_text.doneComplete text of an item
response.completedResponse finalized with usage
response.failedError during generation

Streaming in Python

stream = client.responses.create(
    model="grok-4.20-0309-reasoning",
    input="Explain how a compiler works.",
    stream=True
)

full_text = ""
for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)
        full_text += event.delta
    elif event.type == "response.completed":
        usage = event.response.usage
        print(f"\n\nTokens: {usage.total_tokens}")
        print(f"Cost: {usage.cost_in_nano_usd / 1e9:.6f} USD")

flush=True forces immediate display of each fragment.

Streaming with tools

When the model uses tools in streaming mode, you receive additional events:

data: {"type": "response.output_item.added", "item": {"type": "web_search_call"}}
data: {"type": "response.web_search_call.in_progress", ...}
data: {"type": "response.web_search_call.completed", ...}
data: {"type": "response.output_text.delta", "delta": "Selon les résultats..."}

For client function calls, you receive arguments progressively:

data: {"type": "response.function_call.arguments.delta", "delta": "{\"city\""}
data: {"type": "response.function_call.arguments.delta", "delta": ": \"Paris\"}"}
data: {"type": "response.function_call.arguments.done", ...}

Frontend integration

For a web application, send the SSE stream to the browser via a server endpoint:

const response = await fetch('/api/chat', {
  method: 'POST',
  body: JSON.stringify({ message: userInput })
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const text = decoder.decode(value);
  outputElement.textContent += text;
}

Streaming and billing

Streaming doesn’t change billing. The cost is identical whether it’s enabled or not—only the delivery mode differs. The complete usage object is available in the response.completed event.

Key takeaways

  • stream: true enables SSE streaming—tokens arrive as they are generated
  • The response.output_text.delta event contains each text fragment
  • The response.completed event contains the final response with usage metadata
  • Streaming works with tools (web_search, functions)
  • Cost is identical with or without streaming