Streaming & Polling
Last verified: 2026-06-20 (Task #390 — User APIs documentation).
A run emits a sequenced stream of events. Each event has a monotonic
per-run sequence number that you use as a cursor to catch up without
missing or duplicating events. Two ways to consume them — both are
owner-only.
Polling (works with any credential)
GET /v1/agent-runs/{runId}/events?since={sequence}
Returns events newer than since, plus the current runStatus and
currentPhase. Start at since=0, then pass the highest sequence you
have seen on the next call.
curl -s "https://api.travelmode.ai/v1/agent-runs/9f2a1c7e-…/events?since=14" \
-H "Authorization: Bearer <token>"
{
"events": [
{ "sequence": 15, "eventType": "PHASE_STARTED", "payload": { "phase": "compose" }, "createdAt": "2026-06-20T12:01:00.000Z" },
{ "sequence": 16, "eventType": "ARTIFACT_CREATED", "payload": { "artifactType": "proposals" } }
],
"runStatus": "running",
"currentPhase": "compose"
}
Stop polling once runStatus is completed, failed, or cancelled.
Live stream (SSE, cookie-only)
GET /v1/agent-runs/{runId}/stream?since={sequence}
Opens a Server-Sent Events stream. Authentication is session-cookie
only — the EventSource API cannot send an Authorization header, so a
bearer token is not accepted on this endpoint (see
authentication.md).
// Browser — the session cookie is sent automatically.
const es = new EventSource("/v1/agent-runs/9f2a1c7e-…/stream?since=0");
es.onmessage = (e) => {
const frame = JSON.parse(e.data);
// frame.type: "connected" | "run_event" | "status" | "run_finished" | "error"
if (frame.type === "run_finished") es.close();
};
Frame types
type | When |
|---|---|
connected | Once, immediately after the stream opens. |
run_event | For each new run event (carries the event, including its sequence). |
status | Periodic status/phase heartbeats. |
run_finished | Terminal frame when the run reaches a final status. |
error | The stream encountered an error. |
Resuming after a disconnect
Pass since set to the last sequence you processed when you reconnect,
so the server replays only the events you missed. This makes reconnect
loops safe and idempotent.