Skip to main content
GET
/
v1
/
api
/
conversations
/
{id}
/
stream
Stream conversation events
curl --request GET \
  --url https://api.hq.zone/v1/api/conversations/{id}/stream \
  --header 'Authorization: Bearer <token>'

Server-Sent Events

This endpoint is a long-lived Server-Sent Events (SSE) stream, not a one-shot JSON response. Open it with an SSE client and keep it open — it emits one event per agent or platform update until you disconnect.
GET /v1/api/conversations/{id}/stream
Authorization: Bearer hq_pat_...
Accept: text/event-stream
A comment line (: ping / : idle) is sent periodically as a keepalive so proxies don’t drop the connection — ignore it.

Event shape

Each event has an event: name, a monotonic id: cursor, and a single-line JSON data: payload:
event: text_delta
id: 7Z9aQ2
data: {"text":"Looking up the financials"}

Common events

event:dataMeaning
text_delta{ text }A chunk of the assistant’s reply — append it.
status{ message }Progress caption.
agent_active{ hint }Drive a typing indicator. hint is diagnostic — don’t render it as user-facing text.
tool_call{ id, name, scope, args_summary, args_digest }The agent invoked a tool.
tool_result{ id, is_error, summary }The matching tool call finished.
token_usage{ model, input_tokens, output_tokens, cost_usd, … }Usage and cost for the turn.
final{ text, duration_ms }Terminal for the turn — the reply is complete.
error{ message, recoverable }Terminal for the turn — it failed.
final/error end a turn, not the stream — the next message produces the next batch. New event: names may be added over time; ignore ones you don’t recognize (standard SSE behavior).

Reconnecting

id: is an opaque, incrementing sequence. On reconnect, send the last one you saw as the Last-Event-ID header and the server replays the events you missed from the conversation journal. (EventSource sets Last-Event-ID automatically on auto-reconnect; on a fresh attach where you can’t set the header, pass ?since_seq=<id> instead.) An optional ?scope= query parameter narrows which events you receive.
To send a message and watch the reply, POST to Post a message (returns immediately) and read the result off this stream.

Authorizations

Authorization
string
header
required

Personal Access Token. Send as Authorization: Bearer hq_pat_....

Path Parameters

id
string<uuid>
required

Conversation id

Query Parameters

scope
string | null

Self-downgrade only. user strips diagnostic + accounting fields; admin / integrator and absent default to the trusted full vocabulary. Unknown values do NOT elevate -- see [crate::stream_scope::Scope::from_query]. Auth-derived scope replaces this in #729.

since_seq
integer<int64> | null

Explicit "I've already seen up to seq N" cursor for fresh attaches. The standard EventSource API doesn't let JS set Last-Event-ID on the initial request -- only on automatic reconnects -- so Studio passes its journal high-water mark here to avoid a race where events emitted between the journal fetch and the SSE subscribe vanish into the gap.

view
string | null

?view=admin opts a tenant admin into attaching to a conv stream they don't participate in. Non-admins are silently downgraded. Audited per-attach so admin tail reads of someone else's conv are observable.

Response

Server-Sent Events for the conversation's turn. Each frame is a named event (the agent token/tool/final event kinds, plus stale when the client lagged and done when the turn closes) carrying a JSON data payload and an id: sequence. Resume after a drop with the standard Last-Event-ID header, or pass ?since_seq= on a fresh attach. Native EventSource (cookie auth) and fetch-stream (Bearer PAT) both work.