Skip to content
API referenceStreaming (SSE)

Streaming (SSE)

Streaming replies across three APIs and termination on error or limit.

Model protocol

stream: true works on /v1/messages, /v1/chat/completions and /v1/responses with and without a server prompt. The format depends on the API: Anthropic SSE, OpenAI Chat chunks or Responses events respectively.

A stream and its terminal events
Your application
stream: true
GUARD API
SSE
Messages
Content deltas
content_block_delta
Completion
message_stop
Chat Completions
Response chunks
chat.completion.chunk
Completion
data: [DONE]
Responses
Text deltas
response.output_text.delta
Completion
response.completed
With stream: true, the response arrives in parts. The sequence and terminal event depend on the endpoint: Messages, Chat Completions or Responses.
EndpointTerminal eventNotes
/v1/messages without a server promptmessage_stopNative text/tool/thinking/signature/citation deltas
/v1/messages with an applied promptmessage_stopText and client tools; no signed thinking or citation deltas
/v1/chat/completionsdata: [DONE]OpenAI-compatible chunks
/v1/responsesresponse.completedResponses events; at the output limit the final object has status: incomplete

Request

bash
curl -N https://api.guardrelay.ai/v1/messages \
  -H "x-api-key: $GUARD_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5-5",
    "max_tokens": 256,
    "stream": true,
    "messages": [{"role": "user", "content": "Write a haiku about the sea"}]
  }'

Claude Messages event types without an applied server prompt:

  • message_start — start of the response, metadata.
  • content_block_start / content_block_delta / content_block_stop — content chunks.
  • message_delta — top-level changes (e.g. stop_reason).
  • message_stop — end of the response.

Without an applied server prompt, content_block_delta may also contain thinking_delta, signature_delta, input_json_delta, and citations_delta. Ignore unknown event types safely — Anthropic may add more.

Codex: SSE and WebSocket

Responses SSE uses stream: true at /v1/responses and /codex/v1/responses. Native WebSocket uses wss://api.guardrelay.ai/v1/responses or the retained wss://api.guardrelay.ai/codex/v1/responses: the client sends response.create events and receives Responses events. Chat Completions and Messages support SSE, but are not renamed into Responses events.

Kimi, Composer and Grok

Kimi streams on all three surfaces; the plain Chat Completions frames and the repeated usage are covered on Kimi: streaming and usage. Composer and Grok stream on all three surfaces, each in its native format.

The Kimi stream

Pass stream: true and the answer arrives as SSE frames in the ordinary OpenAI shape. Every frame is a chat.completion.chunk, the piece of text sits in choices[0].delta.content, and the line data: [DONE] closes the stream.

bash
curl -N -X POST https://api.guardrelay.ai/v1/chat/completions \
  -H "Authorization: Bearer gd-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "k3",
    "messages": [{"role": "user", "content": "Write a haiku about the sea"}],
    "max_tokens": 256,
    "stream": true
  }'

Kimi puts the final statistics into the closing frame next to finish_reason, even when stream_options.include_usage was not asked for. With include_usage: true the same statistics arrive once more as a separate frame with an empty choices. It is the same number — do not add them up.

EndpointComposer and Grok events
/v1/messagesmessage_start, content_block_start, content_block_delta, content_block_stop, message_delta with the final usage, message_stop
/v1/chat/completionschat.completion.chunk frames, the last one carrying finish_reason: "stop" and usage, then data: [DONE]
/v1/responsesresponse.created, response.output_text.delta, response.output_text.done, response.completed with usage

Check the stream

bash
curl -N -X POST https://api.guardrelay.ai/v1/chat/completions \
  -H "Authorization: Bearer gd-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "cursor-grok-4.6-low",
    "messages": [{"role": "user", "content": "Write a haiku about the sea"}],
    "max_tokens": 256,
    "stream": true
  }'
bash
curl -N -X POST https://api.guardrelay.ai/v1/chat/completions \
  -H "Authorization: Bearer gd-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "composer-2.5",
    "messages": [{"role": "user", "content": "Write a haiku about the sea"}],
    "max_tokens": 256,
    "stream": true
  }'

SSE on all three GLM APIs

Add stream: true to the same body. Events remain native to the selected API: Guard does not translate Messages, Chat, and Responses into one another.

bash
curl -N https://api.guardrelay.ai/glm/v1/responses \
  -H "Authorization: Bearer $GUARD_API_KEY" \
  -H "content-type: application/json" \
  -d '{"model":"glm-5.3","input":"Explain 2+2 briefly","max_output_tokens":4096,"store":false,"stream":true}'
APITextSuccessful terminalCapped terminal
Messagescontent_block_deltamessage_delta + message_stopstop_reason: max_tokens
Chatchoices[].delta.contentfinish_reason + [DONE]finish_reason: length
Responsesresponse.output_text.deltaresponse.completedresponse.incomplete + max_output_tokens

response.incomplete is a terminal event, not a transport error. Preserve delivered output and inspect incomplete_details.reason.

If the client cancels before exact terminal usage is available, Guard releases the reserve without a guessed debit; do not infer that provider usage was zero.

Gemini streaming

SSE streaming works in all three APIs: send stream: true. Frames follow the selected API: Anthropic events in Messages, chat.completion.chunk and data: [DONE] in Chat Completions, response.* events in Responses. Reasoning, when its display is requested, comes in separate frames: thinking_delta in Messages and response.reasoning_summary_text.delta in Responses. Chat Completions has no way to request the reasoning display.

Muse streaming

SSE streaming works in all three APIs: send stream: true. Frames follow the selected API: Anthropic events in Messages, chat.completion.chunk and data: [DONE] in Chat Completions, response.* events in Responses.

Sections

On this page