Stream chat response deltas (Server-Sent Events)
/ai/streams/{streamId}/eventsServer-sent-events counterpart to GET /ai/streams/{streamId}. Instead
of returning a snapshot the caller re-polls, this holds the connection
open and pushes the assistant's response as it is generated. The server
polls the DB-backed stream (~300ms) and flushes each new chunk until the
message completes.
Requires the ai key scope and a linked service user. The streamId
must belong to the linked user — one key can never read another key's
stream (404 otherwise).
Usage
Open this on its own connection after issuing the message POST on a separate connection (PHP-FPM blocks per request):
POST /ai/streams/init {chatRef}→streamIdPOST /ai/chats/{ref}/messages {message, streamId}(on connection A)GET /ai/streams/{streamId}/events(on connection B) — consume the event stream below
Standard text/event-stream semantics — use any SSE client
(EventSource, curl -N, an SSE library). The connection is hard-capped
server-side (see Bounds) and closes itself on completion.
Event types
event: | data: payload | Meaning |
|---|---|---|
delta | { "content": "<text>" } | Text appended since the previous event — concatenate onto what you have. |
delta | { "content": "<full text>", "replace": true } | Rare: earlier content was rewritten (e.g. a follow-ups block streamed in then got stripped). Replace your buffer with content rather than appending. |
done | StreamDoneEvent | Terminal. Stream completed (or was aborted); connection closes. Carries the fully-cleaned final content plus results / followUpQuestions. |
error | StreamErrorEvent | Terminal. The stream ended in an error state, the row vanished, or the connection hit its time cap. |
Lines beginning : (e.g. : keepalive) are SSE comments emitted when the
stream is idle to defeat proxy buffering — ignore them.
Bounds
A connection lives for exactly one chat response (seconds, not a
subscription). It is hard-capped at 120s; if the underlying stream
has not completed by then the server emits a terminal error
(status: "timeout") and closes. A vanished client is detected each poll
and frees the worker within one poll interval. Per-key rate limits cap
concurrent streams per integration.
Example
event: deltadata: {"content":"Once upon a time, a publisher asked"}event: deltadata: {"content":" for server-sent events."}: keepaliveevent: donedata: {"status":"complete","content":"Once upon a time, a publisher asked for server-sent events.","reasoning":null,"results":[],"followUpQuestions":[]}Authorization
apiKey Issued to you when your integration is provisioned. Determines which catalogue resources are visible and which AI tools are available.
In: header
Path Parameters
The stream id from POST /ai/streams/init.
Response Body
text/event-stream
application/json
application/json
application/json
curl -X GET "https://example.com/ai/streams/string/events""event: delta\ndata: {\"content\":\"Hello\"}\n\nevent: delta\ndata: {\"content\":\" world\"}\n\nevent: done\ndata: {\"status\":\"complete\",\"content\":\"Hello world\",\"reasoning\":null,\"results\":[],\"followUpQuestions\":[]}\n"{ "success": false, "status": "fail", "message": "string", "error": { "message": "API key is required", "code": "NO_API_KEY" }}{ "success": false, "status": "fail", "message": "string", "error": { "message": "API key is required", "code": "NO_API_KEY" }}{ "success": false, "status": "fail", "message": "string", "error": { "message": "API key is required", "code": "NO_API_KEY" }}Stream a chat image GET
Returns image bytes for an image saved by the chat pipeline (either attached by the caller or generated by `image_generation`). ### Two auth modes - **Signed URL** (preferred for browsers): pass `path`, `exp`, `sig` query params as returned in the `images[i].url` field of a chat response. The signature is validated and bytes are served without an api-key. URLs expire after 1 hour. - **API key** (server-to-server): send `X-Api-Key` and `path` only. The path is checked against the api-key's scope; you can only fetch images that belong to chats the api-key would otherwise be able to read. Inline image refs in `chatResponse` HTML are auto-rewritten to signed-URL form, so customers rendering the response HTML directly get working `<img src>` tags out of the box.
Poll a stream GET
Returns the current accumulated content. Safe to poll. Once `isComplete` is true, stop polling and either inspect `content` here or `GET /ai/chats/{ref}` for the saved assistant message.