SSE streaming API
Server-Sent Events (text/event-stream) for real-time event and operation
progress streaming.
Scope note. There is no
SSEBrokersubsystem and nosse.*config section in the Go daemon — those were Python-era. Streaming is implemented directly in the module routers below. This page documents the routes that actually emittext/event-stream, verified against the chi routers.
Streaming endpoints
Section titled “Streaming endpoints”| Method | Path | Emits | Module / source |
|---|---|---|---|
GET | /api/method/shc.events.stream | event stream (docker/audit/error) | events |
GET | /api/method/shc.events.errors.stream | error events only | events |
GET | /api/method/shc.operation.stream/{operation_id} | operation progress | backup (+ operation) |
GET | /api/method/shc.operation.state/{operation_id} | one-shot operation state (JSON, not SSE) | backup |
GET | /api/method/shc.mount.subscribe/{session_id} | mount-session events (pins the session) | backup/mount |
GET | /api/method/shc.stack.logs.stream | chunked log stream | logs |
GET | /api/method/shc.storage.logs.stream | chunked storage-op log stream | storage |
POST | /internal/events | cross-node event ingest (peer → local bus) | events |
SSE wire format
Section titled “SSE wire format”All SSE responses set:
Content-Type: text/event-streamCache-Control: no-cacheConnection: keep-aliveX-Accel-Buffering: no
Each frame is:
id: <sequence>event: <event_type>data: <json>id: is emitted only when the sequence is known (locally published events).
A heartbeat frame is sent every 30 seconds during idle periods:
event: heartbeatdata: {"ts": "2026-01-24T12:00:00.123456Z"}Event stream — GET /api/method/shc.events.stream
Section titled “Event stream — GET /api/method/shc.events.stream”Streams system-wide events. Auth: events:read (tenant-scoped); a
non-member is rejected with 403 before any SSE headers are written. The
local UDS caller is implicitly all-tenants.
Query parameters
| Parameter | Description |
|---|---|
type | Comma-separated event types to include: docker, audit, error, event. Omit for all. |
stack_name | Filter to one stack. |
node_id | Filter to events originating on one node. |
all_tenants | 1 = all tenants (platform admin only). |
Event type classification (from the event code prefix): D… → docker,
A… → audit, E… → error; audit/error flags override; anything else →
event. Each data payload is the event’s ToDict() envelope plus an
event_type key.
GET /api/method/shc.events.errors.stream is the same stream restricted to
error events.
Operation progress — GET /api/method/shc.operation.stream/{operation_id}
Section titled “Operation progress — GET /api/method/shc.operation.stream/{operation_id}”Async operations (shc.backup.create_async, restore_async,
recover_async, stack start/stop/restart, install/update, …) return an
operation_id in their response body. Subscribe to this route to receive
progress frames. Event types seen on this channel include step
(progress update), complete, and error; the stream closes after a
complete or error frame.
The backup-module handler serves the canonical URL; it tries the async
operations store first, then falls back to the operation module’s
registry, so operations registered by either land on the same URL.
GET /api/method/shc.operation.state/{operation_id} returns a one-shot JSON
snapshot of operation state (used by the CLI to check whether an operation
still exists before following it).
Reconnection
Section titled “Reconnection”- The client tracks the last
id:received. - On reconnect it sends
Last-Event-Id: <seq>(or?last_event_id=<seq>for clients that can’t set headers, e.g. browserEventSource). - The server replays events after that sequence from
events_log(up to a 1000-event window) before resuming the live stream. Beyond the window the client resyncs by re-querying current state.
Cross-node ingest — POST /internal/events
Section titled “Cross-node ingest — POST /internal/events”Peer nodes forward events to each other over the internal listener. The body
is one event in ToDict() shape; code is required and X-SHC-Source-Node
must be present. Events whose source equals the receiving node are dropped
(204, loop prevention). Received events are persisted locally and delivered
to local subscribers but are not re-broadcast (prevents storms).
| Status | Meaning |
|---|---|
200 | Delivered + persisted locally. |
204 | Self-broadcast dropped. |
400 | Missing X-SHC-Source-Node / decode error / missing code. |
500 (X500007EVTBUS) | Event bus not running. |