Skip to main content

What you’ll build

Instead of waiting for the full AI response, stream it token-by-token for a ChatGPT-like experience.
AI: The
AI: The capital
AI: The capital of
AI: The capital of France
AI: The capital of France is
AI: The capital of France is Paris.
[DONE]

How streaming works

When you set stream: true on the messages endpoint, the API returns a Server-Sent Events (SSE) stream instead of a JSON response. The stream emits these events:
EventDescription
message.deltaA chunk of the AI’s response (partial text)
message.completeThe full message with usage stats
errorSomething went wrong

TypeScript example

stream.ts
const API_KEY = "YOUR_API_KEY";
const BOARD_ID = "your-board-id";
const CHAT_ID = "your-chat-id";

const res = await fetch(
  `https://api.chatgrid.ai/v1/boards/${BOARD_ID}/chats/${CHAT_ID}/messages`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      content: "Explain quantum computing in simple terms",
      stream: true,
    }),
  }
);

const reader = res.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");
  buffer = lines.pop()!; // keep incomplete line in buffer

  for (const line of lines) {
    if (line.startsWith("data: ")) {
      const data = JSON.parse(line.slice(6));

      if (data.event === "message.delta") {
        process.stdout.write(data.content);
      }

      if (data.event === "message.complete") {
        console.log("\n\n--- Complete ---");
        console.log("Tokens used:", data.usage?.total_tokens);
      }
    }
  }
}
Run it:
npx tsx stream.ts

Python example

stream.py
import requests
import json

API_KEY = "YOUR_API_KEY"
BOARD_ID = "your-board-id"
CHAT_ID = "your-chat-id"

res = requests.post(
    f"https://api.chatgrid.ai/v1/boards/{BOARD_ID}/chats/{CHAT_ID}/messages",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json={"content": "Explain quantum computing simply", "stream": True},
    stream=True,
)

for line in res.iter_lines():
    if line:
        decoded = line.decode("utf-8")
        if decoded.startswith("data: "):
            data = json.loads(decoded[6:])

            if data.get("event") == "message.delta":
                print(data["content"], end="", flush=True)

            if data.get("event") == "message.complete":
                print(f"\n\nTokens: {data.get('usage', {}).get('total_tokens')}")

React hook example

Build a streaming chat component in React:
useStreamingChat.ts
import { useState, useCallback } from "react";

export function useStreamingChat(apiKey: string) {
  const [content, setContent] = useState("");
  const [isStreaming, setIsStreaming] = useState(false);

  const sendMessage = useCallback(
    async (boardId: string, chatId: string, message: string) => {
      setContent("");
      setIsStreaming(true);

      const res = await fetch(
        `https://api.chatgrid.ai/v1/boards/${boardId}/chats/${chatId}/messages`,
        {
          method: "POST",
          headers: {
            Authorization: `Bearer ${apiKey}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ content: message, stream: true }),
        }
      );

      const reader = res.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");
        buffer = lines.pop()!;

        for (const line of lines) {
          if (line.startsWith("data: ")) {
            const data = JSON.parse(line.slice(6));
            if (data.event === "message.delta") {
              setContent((prev) => prev + data.content);
            }
          }
        }
      }

      setIsStreaming(false);
    },
    [apiKey]
  );

  return { content, isStreaming, sendMessage };
}
Usage in a component:
function Chat() {
  const { content, isStreaming, sendMessage } = useStreamingChat("YOUR_KEY");

  return (
    <div>
      <p>{content}{isStreaming && "..."}</p>
      <button onClick={() => sendMessage(boardId, chatId, "Hello!")}>
        Send
      </button>
    </div>
  );
}

Tips

Use streaming for user-facing chat interfaces where perceived speed matters. Use non-streaming (stream: false) for automated pipelines where you need the complete response before proceeding.
Listen for the error event in the SSE stream. If the connection drops unexpectedly, retry the request. The message won’t be duplicated because the failed message isn’t saved.
First token typically arrives in 300-800ms depending on the model. Total streaming time depends on response length.