Skip to main content
GET
Tail the current workspace's live event stream over SSE or WebSocket

Authorizations

hookie_session
string
cookie
required

The console's sealed session cookie, set by WorkOS AuthKit. Mutating requests also require the X-Requested-With CSRF header.

Headers

Last-Event-ID
integer

Standard SSE resume header, sent automatically by EventSource on reconnect. Takes precedence over after_seq when present. Same semantics and same 1000-event / 5-minute buffer window.

Required range: x >= 0
Upgrade
enum<string>

Send exactly 'websocket' (compared case-sensitively) to get a 101 WebSocket upgrade instead of an SSE stream. Any other value, or its absence, yields the SSE response.

Available options:
websocket

Query Parameters

after_seq
integer

Resume cursor: replay buffered events with seq greater than this value. Ignored when a Last-Event-ID header is present. Non-numeric or negative values are treated as absent. The resume buffer holds at most 1000 events and drops anything older than 5 minutes; a request for evicted events still succeeds but is preceded by a stream-gap control event.

Required range: x >= 0
project_id
string

Only deliver events belonging to this project. Applied by the stream Durable Object, not by the client, because the plan caps CONCURRENT CONNECTIONS (one, on Free) — a subscriber that attached to everything and filtered locally would spend its whole allowance to watch one project. STRICT: an event with no project (a workflow instance outside one, or anything buffered before events carried a project at all) does NOT match a project filter. The per-tenant seq cursor is unaffected, so a filtered stream skips numbers by design; a gap in seq is not a lost event. This is not a security boundary — the tenant gate is; an id from another tenant simply matches nothing.

dataset
string

Only deliver events in this dataset. Combines with project_id — both have to match. Applied server-side for the same reason.

Response

WebSocket upgrade accepted (the request carried 'Upgrade: websocket'). Each live event arrives as one JSON text frame: {seq, id, dataset, received_at, data, project_id, webhook_id}. When a resume cursor was supplied and part of the requested window had been evicted, a {"type":"stream-gap","missed_from":,"resume_from":} frame is sent first, followed by the replayable buffered events. The socket is hibernatable and answers a 'ping' text frame with 'pong'. The live path is lossy by contract — durable delivery is the outbound-delivery queue, not this stream.