Local API
APIExpose exposes a REST API and WebSockets locally only (127.0.0.1) — nothing leaves your machine.
The basics
| What | Address |
|---|---|
| Service status (API, WebSocket, ES, managers) | http://127.0.0.1:12345/api/v1/status |
| Service health | http://127.0.0.1:12345/api/v1/health |
| Startup progress | http://127.0.0.1:12345/api/v1/startup/ready |
| Swagger (all endpoints, testable) | http://127.0.0.1:12345/swagger/index.html |
| WebSocket stream discovery | http://127.0.0.1:12345/api/v1/ws/streams |
| General WebSocket | ws://127.0.0.1:12345/ws |
Swagger is your friend
The Swagger UI documents and lets you test every endpoint from the browser, with pre-filled examples that actually return data (megadrive/sonic for consoles, mame/1943 for arcade). It is the up-to-date API reference — always in sync with the installed version, and published as a swagger.json artifact with every release.
How the API is organized
Endpoints are grouped with the same logic as the EmulationStation menu: each manager is the gateway to its domain, and a manager switched OFF disables its whole branch (see the diagram on the Menus and options page). GET /api/v1/status shows the effective state of every gate.
| Swagger group | Domain |
|---|---|
| System & Health | health, startup, service status, effective options |
| Context & Navigation | current game/system, ES control (tap, combo, launch) |
| Local Media Manager | served media, gamelist operations |
| Auto Scraping Manager | scraping state and actions |
| Roms Manager | romset filters, pack installers, gamelists |
| Control Panel Manager | resolved panels, control deployments |
| Themes & Collections | theme exports (.gameinfos) |
| Game Events | scores, arcade outputs, RetroAchievements, hiscores |
| Notifications & UI | toasts, native ES notifications |
| Real-time (WebSocket) | stream discovery |
| Internal & Prototype | maintenance, ingestion, future surfaces |
Experimental endpoints
es/controller/goto-system and goto-game are not yet reliable on every theme/view — prefer tap/combo sequences. reloadgames must never be used as an automatic refresh (the user's cursor is lost).
The WebSocket streams
Each stream only delivers the event types of its prefixes; some replay their last snapshot on connect (retained). The complete list, always in sync with the installed version: GET /api/v1/ws/streams. The formal specification (channels, envelope, real examples): asyncapi.yaml, also published with every release.
| Stream | Content |
|---|---|
/ws/frontend |
ES navigation, game start/end (ui.*) |
/ws/marquee, /ws/topper, /ws/instruction-card, /ws/screen |
Physical surface media snapshots |
/ws/panel |
Resolved panel of the current context (retained panel.state) |
/ws/ingame |
In-game memory events (RetroArch, MAME Lua) |
/ws/arcade |
Native MAME outputs (lamps), sessions |
/ws/score, /ws/timer |
Normalized live score and timer (retained) |
/ws/retroachievements |
RA session: rich presence, unlocks, challenges, leaderboards |
/ws/hiscore |
High score captures and updates |
/ws/media, /ws/roms, /ws/system, /ws/control, /ws/esevent |
Media store, Roms Manager, service, commands, raw ES hooks |
Surface snapshots carry Media (legacy fields, unchanged) and, in addition, Assets — a table keyed by canonical media kind (box-3d, mixrbv2, wheel…) holding only what the entry really owns. In game scope, SystemAssets carries the same table for its system: that is what tells the game's fanart apart from the system's, where the legacy fields silently fall back from one to the other. A key exists only when the file does.
Streams that print something about a game — topper, instruction card — also carry Text: description, genre, player count and rating in the language EmulationStation is set to, with the languages available for that entry.
/ws/instruction-card also carries Controls: what each button does and its colour, projected from resources/dynpanels. Enough to compose a card (logo, box art, description, coloured panel over a fanart) rather than only display a ready-made one; the full panel geometry stays on /ws/panel.
Every event shares one envelope: { "Type": "ui.game.selected", "Ts": "...", "NodeId": "...", "CorrelationId": "...", "Payload": { ... } } — the contract is additive (fields are added, never removed).
Hiscores: arcade and consoles
High scores now cover console (non-MAME) games as well as arcade. The current game's board is served by GET /api/v1/hiscores (its Me field names the player at the cabinet). The game's world ranking (Top 100, when the cabinet is linked to NelfePlay) is relayed by GET /api/v1/nelfeplay/records/leaderboard. Details and schemas in Swagger.
Build your own tool
A browser overlay, a rich presence, a homemade scoreboard: any WebSocket/REST consumer can plug in. Start with:
GET /api/v1/statusto check everything is green;- open Swagger and try the endpoints (the examples respond);
- connect to
ws://127.0.0.1:12345/wsand watch events while browsing EmulationStation; - move to the filtered streams (
/api/v1/ws/streams) once you know what you need.
Stability
The streams listed here are the ones MarqueeManager and LedManager consume — they are maintained with priority and evolve in a backward-compatible way.