Skip to content

Streaming responses

One endpoint does not return JSON. POST /api/v1/ai/conversations/{id}/messages streams its answer as Server-Sent Events, so the answer appears as it is produced rather than after it is complete.

OpenAPI cannot usefully describe an event stream, so the reference entry for that operation documents the response as text/event-stream and links here for the payloads.

Send the message as JSON, and accept an event stream:

POST /api/v1/ai/conversations/{id}/messages
Authorization: Bearer <access token>
Content-Type: application/json
Accept: text/event-stream

The response has Content-Type: text/event-stream. Read it incrementally — do not wait for the body to complete, because it does not complete until the answer is finished.

Only one turn may be in flight per conversation. A second concurrent request on the same conversation is rejected with 409 and code turn_in_progress. This is not a transient failure to retry blindly: it means something else is already answering on that conversation.

The stream emits a comment line roughly every fifteen seconds while it is working:

: heartbeat

Lines beginning with : are SSE comments. Ignore them — they exist to stop intermediaries from closing an idle connection. Standard EventSource clients discard them for you.

Two rules that matter more than the event list:

  1. Treat unknown event names as ignorable. New event types may be added. A client that fails on an unrecognised event will break on an additive change.
  2. Do not treat stream end as success. An error may terminate the stream. Only a completion event means the answer finished; a stream that stops without one should be surfaced as a failure.
Terminal window
curl -N \
-H "Authorization: Bearer $CRITIAS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{"content":"Which resources are unmanaged in production?"}' \
https://api.example.com/api/v1/ai/conversations/$CONVERSATION_ID/messages

-N disables curl’s output buffering. Without it you will see nothing until the stream closes, which makes a working stream look broken.

Authentication, authorization, and validation failures happen before streaming begins, so they return an ordinary JSON error with the usual error envelope and a normal status code. Only once the response is 200 text/event-stream do you need the event handling above.