API overview
Where the endpoints live, how they are authenticated, and which ones RomM calls versus the room UI.
Every endpoint lives under the SUBFOLDER prefix, so with the default the
API root is /streaming/api/. The examples on these pages talk to a container
directly on its HTTP port (3000); behind a reverse proxy substitute RomM's origin.
Authentication
BROKER_SECRET is a shared secret between RomM and the container, like a
password only the two of them know. When it's set, the lifecycle endpoints
require it in the X-Broker-Secret header (an extra field sent along with
the request) and answer 403 if that check fails. Leaving it unset is not a
"no auth" mode: the broker refuses to start at all, unless
dev mode (BROKER_DEV_MODE=true) is also set. In
dev mode it does start with BROKER_SECRET unset, but then every
session-lifecycle endpoint is left unauthenticated, so a dev-mode broker
should never be exposed beyond local development.
Endpoints fall into five groups:
| Group | Caller | Auth |
|---|---|---|
| Lifecycle: activate, join, swap-disc | RomM's backend | X-Broker-Secret |
| State and archive transfer: save-state, load-state, state-file, state-screenshot, imports, import-spec, exports, memory card, RetroArch core list | RomM's backend | X-Broker-Secret |
| Host actions: invite, exit | the room UI (invite), RomM (exit) | the controller token as ?token=; exit also accepts the secret |
| Room: context, the collab websocket | the room UI | a personal token, or an invite token, in the URL |
| Status and health | RomM's backend (status), anyone (health) | X-Broker-Secret for status; none for health |
The room UI never holds the secret. Its invite tile carries the controller token instead; exit accepts either so RomM and the controller token both work.
Endpoints
| Method | Path | Page |
|---|---|---|
POST | /api/session/activate | Launch a game |
POST | /api/session/swap-disc | Launch a game |
POST | /api/session/join | Users and invites |
POST | /api/session/invite | Users and invites |
GET | /api/session/context | Users and invites |
POST | /api/session/save-state | Save states |
POST | /api/session/load-state | Save states |
GET / PUT | /api/session/state-file | Save states |
GET | /api/session/state-screenshot | Save states |
POST | /api/session/exit | Exit |
PUT | /api/session/imports/{name}.zip | Save archives |
GET | /api/session/import-spec | Declared imports |
GET / DELETE | /api/session/exports[/{name}.zip] | Save archives |
GET / PUT | /api/session/memory-card | Save archives |
GET | /api/retroarch/cores | RetroArch core manifest |
GET | /api/session/status | Status |
GET | /api/health | Status |
The request and response models are documented in the
Python reference, and a running broker serves
its own OpenAPI schema at <SUBFOLDER>/openapi.json with the interactive
explorer at <SUBFOLDER>/docs.
Conventions
- Status codes carry meaning.
409is "there is no session" (or "there already is one" on activate).400is "the running emulator cannot do that", for example a state route on an emulator without save states.413is a body over a configured ceiling.422is a payload the broker could not act on. - A
"failed"status is a real answer, not an error. Save and load reportfailedwhen the emulator did not acknowledge, or the slot held no state. - Slots resolve to the emulator's working slot. RomM is the library of states, so each emulator works in exactly one slot and echoes the slot it actually used. Whatever slot a request names, the response says which one it landed in.