> ## Documentation Index
> Fetch the complete documentation index at: https://developer.swytcho.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Stream AI Responses in Real Time with the Swytcho API

> Enable token-by-token streaming via server-sent events. Reduce latency and build chat interfaces that display AI output as it is generated in real time.

By default, the Swytcho API waits until the model finishes generating before returning a response. Streaming changes that: the API sends each token as it is produced using server-sent events (SSE), so your application can begin displaying output immediately. This dramatically reduces perceived latency for long responses and is essential for building chat interfaces that feel fast and alive.

## How Streaming Works

Set `"stream": true` in your request body. The API responds with a stream of newline-delimited events, each prefixed with `data: `. Each event contains a partial response chunk in JSON. When generation is complete, the stream sends a final `data: [DONE]` sentinel and closes.

A raw stream looks like this:

```text theme={null}
data: {"id":"chatcmpl-abc","choices":[{"delta":{"role":"assistant","content":""},"index":0}]}

data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"The"},"index":0}]}

data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":" quick"},"index":0}]}

data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":" brown"},"index":0}]}

data: [DONE]
```

Each `delta.content` field contains the next piece of text. Concatenate them in order to reconstruct the full response.

## Code Examples

<CodeGroup>
  ```python Python theme={null}
  import os
  import json
  import requests

  response = requests.post(
      "https://api.swytcho.com/v1/chat/completions",
      headers={
          "Authorization": f"Bearer {os.environ['SWYTCHO_API_KEY']}",
          "Content-Type": "application/json",
      },
      json={
          "model": "swytcho-1",
          "stream": True,
          "messages": [
              {"role": "user", "content": "Explain how neural networks learn in simple terms."}
          ],
      },
      stream=True,  # Keep the connection open on the requests side
  )

  response.raise_for_status()

  for line in response.iter_lines():
      if not line:
          continue  # Skip keep-alive blank lines

      # Strip the "data: " prefix
      text = line.decode("utf-8")
      if not text.startswith("data: "):
          continue

      payload = text[len("data: "):]

      if payload == "[DONE]":
          print()  # Final newline
          break

      chunk = json.loads(payload)
      delta = chunk["choices"][0]["delta"]

      if "content" in delta:
          print(delta["content"], end="", flush=True)
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.swytcho.com/v1/chat/completions", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SWYTCHO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "swytcho-1",
      stream: true,
      messages: [
        {
          role: "user",
          content: "Explain how neural networks learn in simple terms.",
        },
      ],
    }),
  });

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${await response.text()}`);
  }

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

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split("\n");

    // Keep the last partial line in the buffer
    buffer = lines.pop() ?? "";

    for (const line of lines) {
      if (!line.startsWith("data: ")) continue;

      const payload = line.slice("data: ".length).trim();
      if (payload === "[DONE]") break;

      const chunk = JSON.parse(payload);
      const content = chunk.choices[0]?.delta?.content;
      if (content) process.stdout.write(content);
    }
  }
  ```
</CodeGroup>

## Streaming Response Format

Each chunk follows this structure:

```json theme={null}
{
  "id": "chatcmpl-abc123",
  "object": "chat.completion.chunk",
  "model": "swytcho-1",
  "choices": [
    {
      "index": 0,
      "delta": {
        "content": " quick"
      },
      "finish_reason": null
    }
  ]
}
```

The final chunk before `[DONE]` sets `finish_reason` to `"stop"`, `"length"`, or another terminal value — the same reasons as non-streaming responses. Use this to detect truncation.

## End of Stream

The stream terminates with:

```text theme={null}
data: [DONE]
```

Always check for this sentinel explicitly in your parsing loop. Do not rely solely on the connection closing, as network proxies can sometimes close the stream prematurely.

## Error Handling

Errors that occur before streaming begins are returned as standard HTTP error responses (4xx or 5xx) with a JSON body. Errors that occur mid-stream are delivered as a final SSE event with an `error` field instead of `choices`.

```python Python theme={null}
for line in response.iter_lines():
    if not line:
        continue

    text = line.decode("utf-8")
    if not text.startswith("data: "):
        continue

    payload = text[len("data: "):]
    if payload == "[DONE]":
        break

    chunk = json.loads(payload)

    # Check for a mid-stream error
    if "error" in chunk:
        raise RuntimeError(f"Stream error: {chunk['error']['message']}")

    delta = chunk["choices"][0]["delta"]
    if "content" in delta:
        print(delta["content"], end="", flush=True)
```

<Note>
  Streaming is supported for the `/v1/chat/completions` and `/v1/completions` endpoints. The `/v1/embeddings` endpoint does not support streaming — embedding requests always return a complete response in a single JSON payload.
</Note>
