Skip to main content

Durable Conversation Streaming

Use these two endpoints to submit a message and read its events independently. The Assistant service continues processing when your stream connection closes. The existing POST /v1/conversations and /v1/conversations/with-uploads retain their current behavior.

Accept a message​

Send POST /v1/conversations/messages/accept with your x-api-key header and a JSON body:

{
"agent_id": "0e546d24-09a3-41f7-9a2f-11a8bbc2160e",
"query": "Summarize the report",
"client_message_id": "5981bb90-5d26-4071-a11e-cc29be8aae3c"
}

Use agent_name instead of agent_id to select an agent by name. Generate a new client_message_id for each turn; reuse it unchanged when retrying that same request. It is required and must contain 1–128 characters. The upstream service deduplicates repeated accepts using this key.

The endpoint returns 202 Accepted after the turn is persisted:

{
"conversation_id": "c4b12a3e-a456-4890-a12e-1fdd20d9dcbb",
"stream_id": "f05d7c78-7951-45e3-859a-48b930cd130a",
"assistant_message_id": "f05d7c78-7951-45e3-859a-48b930cd130a",
"user_message_id": "997f125f-dd6c-46ba-8577-007c774bfbe0",
"stream_start_id": "1790071000000-0"
}

For the next turn, supply conversation_id and set parent_message_id to the previous assistant message ID. stream_start_id and user_message_id may be null when replaying records from older deployments.

You can include collection_id, uploads, knowledge_base, and user_context as in the existing message API. Upload files through the document upload API first; the stream reports ingestion progress. New conversations default to is_incognito: false. Eligible tool approvals default to automatic approval; set bypass_tool_approval: false to handle approval events and submit decisions through the existing tool interventions endpoint.

stream, message_only, and run_in_background are not accepted by this endpoint. The POST always returns JSON, and the GET always streams all events.

Read and reconnect​

Send a GET with your x-api-key header to:

/v1/conversations/{conversation_id}/streams/{stream_id}?stream_start_id={stream_start_id}

Use the cursor returned by accept for the first GET; omit it if null. The response is text/event-stream. Preserve the last SSE id you receive. On a reconnection, send that value in the Last-Event-ID request header, or use since_id as a query parameter. Replay is exclusive of the supplied cursor. Last-Event-ID takes precedence over since_id when both are supplied. Use stream_start_id for the initial connection.

Events, IDs, retry hints, multiline data, and heartbeat comments pass through unchanged. Use an SSE parser that handles arbitrary network chunk boundaries. After a transport failure, reconnect with the last received event ID. A broken connection is not a completion signal. To cancel generation explicitly, use the existing interruption endpoint with stream_id as its message_id.

Browser clients that authenticate with x-api-key should use a streaming fetch client capable of sending custom headers.

Recover after a page reload​

On deployments that expose is_streaming and last_event_id in message history, read /v1/conversations/{conversation_id}/messages. For a still-streaming assistant message, use its message_id as stream_id and its last_event_id as the Last-Event-ID header (omit the header if null). This resumes the existing turn without submitting it again.

Permissions and errors​

Accept requires conversations:create and respects the API key's agent scope. Reading requires conversations:read; the Assistant service also checks access to the requested conversation and stream.

  • 409 on accept: Durable streaming is unavailable for this deployment or caller. A client may explicitly fall back to the legacy send-message API.
  • 410 on GET: Replay has expired. Read the persisted transcript from the public messages_url returned in the JSON response, alongside assistant_message_id.
  • Cursor-expired SSE error after GET has started: Read /v1/conversations/{conversation_id}/messages using your API key. The relayed error event may contain an internal /chat/... metadata.messages_url; do not use that URL against the public API. A following close event ends replay.
  • 401, 403, or 404: Resolve authentication, access, or missing-resource errors before retrying.

Availability depends on the upstream streaming rollout. Verify the full flow against your target environment before adopting it in production.