Subscribe to all camera events (SSE)
SDK generation note: marked x-fern-ignore: true because
Server-Sent Events don’t map cleanly onto synchronous SDK methods.
The TypeScript and Swift SDKs ship hand-written SSE clients that
consume this endpoint and expose typed EventStream APIs.
Server-Sent Events stream for all connected cameras. The server sends a
keepalive comment (: keepalive) every 30 seconds and immediately fires
an initial connected event with the subscription’s camera ID payload
(see the quirk note below).
Event Types
| Event | SDK Callback | Payload | Description |
|---|---|---|---|
connected | OnConnected (or initial handshake) | {cameraId, ...} | Camera connection established OR initial SSE handshake (see quirk) |
disconnected | OnDisconnected | {cameraId, reason?} | Camera disconnected (real or synthetic — server emits one before clearing callbacks during a clean disconnect) |
propertyChanged | OnPropertyChangedCodes | {cameraId, codes: [...]} | One or more property values changed on the camera |
afStatus | OnWarning (CrWarningExt_AFStatus) | {state: "focused" | "unlocked" | "tracking", source?} | Autofocus state changed |
downloadComplete | OnCompleteDownload | {cameraId, filename, savedPath} | Auto-transferred image saved to host (remote mode + matching still-image-store-destination) |
transferProgress | OnNotifyRemoteTransferResult (or filesystem polling fallback) | {cameraId, contentId, fileId, percent, savedPath?} | Explicit file-pull progress (remote-transfer mode). On macOS V2.01 the SDK callback is unreliable; the server falls back to filesystem polling and emits synthetic events |
contentsTransfer | OnContentsTransfer | {cameraId, files: [...]} | Contents-transfer mode file list update (printable-ASCII filenames only) |
operationResult | OnCompleteOperation | {cameraId, operation, result} | Generic SDK operation completed (e.g. control codes, non-shutter commands) |
error | OnError | {cameraId, code, message} | SDK error occurred |
⚠ The dual connected event quirk
Two distinct conditions emit an event named connected:
- Initial SSE handshake — fired immediately when the EventSource
connects, with payload
{"cameraId":"<subscription-id-or-*>"}. Use it to confirm the SSE channel is open. NOT a camera state change. - Real camera connect — fired when the SDK’s
OnConnectedcallback fires for a camera, with the full camera info payload.
Discriminate by payload shape if you need to distinguish them. The
cleanest pattern is to ignore the first connected event after
opening the EventSource and treat any subsequent connected as a
real camera-state change.
Example
const events = new EventSource("http://localhost:8080/api/events");
events.addEventListener("downloadComplete", (e) => {
console.log("File saved:", JSON.parse(e.data).savedPath);
});
events.addEventListener("propertyChanged", (e) => {
const { codes } = JSON.parse(e.data);
// Refresh affected properties via getProperty / getAllProperties
});
Response
SSE event stream
Server-Sent Events stream. Each event uses the standard SSE
framing: event: <name>\\ndata: <json>\\n\\n. See the
description for the full event catalog and payload shapes.

