webstation-broker
REST API

Users and invites

Adding people to a running session with POST /api/session/join, and minting invite links.

Add a user to the session

curl -k -X POST https://localhost:3001/streaming/api/session/join \
  -H 'X-Broker-Secret: <shared secret>' \
  -H 'Content-Type: application/json' \
  -d '{
    "user": { "id": 2, "username": "player2", "display_name": "Player Two" },
    "permission": "participant"
  }'

Returns {"status": "joined", "url": "/streaming/?token=<personal token>", ...}, 409 when no session is up. permission: "readonly" for spectators. Re-joining the same user (by id, else username) replaces their old token.

Every user gets a personal token. The broker pushes the full token map, {token: {role, slot, mk_control}}, to selkies, which enforces input routing per streaming connection: a participant can be handed a gamepad slot or the mouse and keyboard from the room UI by dragging the icons onto them, a spectator never gets input. Removing a user from the room revokes the token and selkies drops that connection live.

curl -k -X POST https://localhost:3001/streaming/api/session/invite \
  -H 'X-Broker-Secret: <shared secret>' \
  -H 'Content-Type: application/json' \
  -d '{ "permission": "participant" }'

Mints a token with no user attached and returns its room URL. Whoever opens it joins under the name they pick in the room. The invite route ignores the session's multiplayer flag: a link always works. That flag only governs whether RomM advertises the session for joining and whether the room shows its comms surface (chat, webcam) while the host is alone.

The room

The URL activate and join return is the collab room, a vanilla JS page that iframes the selkies stream and connects to the broker's websocket at <SUBFOLDER>/ws/room. It bootstraps from GET /api/session/context?token=..., which tells it who the token belongs to, what it may do, and the current roster. Over the websocket the room carries chat, webcam and microphone fanout, resolution changes, gamepad and mouse/keyboard reassignment, and the exit button. The wire format is documented on the room module in the Python reference.

On this page