webstation-broker
REST API

Status and health

GET /api/session/status for a session summary and GET /api/health for a bare liveness check.

Status

curl -H "X-Broker-Secret: $BROKER_SECRET" http://localhost:3000/streaming/api/session/status

Send the broker secret as X-Broker-Secret when one is set, since the answer names players and ROMs. If no session is running, it answers {"active": false, "last_exit": ...}. If one is running, you get:

FieldMeaning
activeWhether a session is currently running.
session_id, emulator, rom, rom_fileWhich session, emulator, and ROM were activated, and the exact file the broker chose to boot.
multiplayerWhether multiplayer is on. This is set once, when the session is activated, and doesn't change after that.
emulator_aliveWhether the emulator process is still running.
boot_failedTrue when an emulator can tell its own process is alive but never actually reached a running game, for example because it's stuck on a boot-error dialog. This is a passive signal: the broker only reports it and doesn't act on it.
extraction_phasenull, "extracting_archive", or "extracting_pkg". Set while shadPS4, RPCS3, PPSSPP or ScummVM is unpacking an archived ROM (extracting_archive), or shadPS4 a .pkg (extracting_pkg), and cleared back to null once unpacking ends. At that point the emulator still hasn't started yet, so null here doesn't mean the game is running; check emulator_alive for that. Like boot_failed, this is a passive signal: poll it to show a plain loading spinner while it isn't null. There's no percentage to show.
supports_statesWhether save and load states work at all for this emulator, so the parent (usually RomM) doesn't need to keep its own list of which emulators support them.
state_slotThe one slot this emulator uses. Every save and load echoes this same number back.
started_atUnix time (seconds since January 1, 1970) marking when the session was created.
userThe controller's info (the person playing), exactly as it was given when the session was activated.
viewersEveryone who joined: username, user_id, and permission.
last_exitHow the most recent exit ended, in both shapes, or null before the first exit since the broker started: session_id, ended_at (Unix time), duration_s, state_saved, dump_error (null unless the save dump failed), upload (uploaded, skipped, failed or report-only in dev mode) and archive_path (where a copy was kept on the container, if one was). It survives the next activate, so a save archive that never reached RomM stays visible until another exit replaces it.

RomM polls this to know whether a session it launched is still running, to decide whether to offer save and load, and to show the player a boot failure instead of leaving them staring at a frozen frame.

Health

curl http://localhost:3000/streaming/api/health

Answers {"status": "ok"} as soon as the broker is up and serving requests. Inside the container, svc-broker waits for selkies (the video streaming piece) to answer before it starts the broker at all, so a healthy broker also means selkies is up and reachable.

Room context

curl "http://localhost:3000/streaming/api/session/context?token=<personal token>"

This is what the room UI reads when it loads: who the token belongs to, what that person is allowed to do, and the session's rom and emulator. It doesn't say who else is in the room; that roster arrives separately, over the room's websocket state_update broadcast. It answers 409 when there's no session, and 401 for a token that isn't part of it. Opened with ?invite=... instead, it seats the arrival first, so it can also answer 429 when the room is full, or 409 when another session operation is already running. It's documented here because it's useful when you're troubleshooting a room that shows "Session Ended", but it isn't part of the parent-facing API (the endpoints meant for the parent, usually RomM, to call).

On this page