# Streaming

> Set stream to true for SSE output, cutting time-to-first-token from seconds to hundreds of milliseconds.

Add `"stream": true` to the request body and the response becomes `text/event-stream`: one
`data: {json}` line per event, ending with `data: [DONE]`.

```bash
curl https://api.tokrouter.dev/v1/chat/completions \
  -H "Authorization: Bearer $TOKROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.4-mini",
    "messages": [{"role": "user", "content": "Write a four-line poem"}],
    "stream": true
  }'
```

```
data: {"id":"...","choices":[{"delta":{"content":"Spring"}}]}

data: {"id":"...","choices":[{"delta":{"content":" sleeps"}}]}

data: [DONE]
```

## With an SDK

Most SDKs handle SSE framing, keep-alive comments and `[DONE]` for you:

```python
for chunk in client.chat.completions.create(..., stream=True):
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
```

## If you parse SSE yourself

1. **Split on `\n\n`**, not on lines — one event can span several network packets
2. Skip comment lines starting with `:` (keep-alive heartbeats)
3. Close the connection on `[DONE]`; do not wait for EOF

## When not to stream

- You need a complete JSON document (structured output) — streaming only complicates parsing
- The server caches the whole answer and first-token latency does not matter
- Non-chat endpoints such as `/v1/systemone` **do not support streaming**; `stream` has no effect

<Callout type="warn" title="Streaming and billing">
Streamed requests bill on generated tokens. If the client disconnects mid-stream, tokens already
generated are still billed.
</Callout>
