Skip to content

Client API

The Lumora Controller desktop app runs a lightweight HTTP server on your local machine that local tools (Stream Deck plugin, Companion, scripts) can call to trigger hotkey-equivalent actions and query app state. No API key required.

Server API

Looking for the cloud-side API for triggering specific graphics by ID from anywhere on the internet? See the Server API.

When to use which

Use thisIf you want to…
Server APITrigger a specific graphic by ID from anywhere on the internet, regardless of what the operator has selected. Authenticated, internet-exposed.
Client APIDrive whatever the operator currently has selected. Same outcome as pressing a hotkey. Local-only, no auth.

The Client API is the right fit for hardware controllers (Stream Deck, foot pedals, deck builders) that sit on the same machine as the controller and act as remote hotkeys. Pressing a Stream Deck button feels exactly like pressing Numpad +.

Network access

The controller binds the API server to 127.0.0.1 (loopback) by default, so only processes running on the same machine can reach it:

text
http://127.0.0.1:<port>
  • No authentication by default. Matches Companion / vMix / OBS-WebSocket norms for broadcast-tool local APIs. See Enhanced security below for the opt-in token gate.
  • HTTP, not HTTPS. Loopback-only, plain HTTP.
  • Loopback by default. Stream Deck and Companion run locally and connect via 127.0.0.1. Cross-device access (e.g. a Stream Deck on a separate box) is not supported in the current release.

Security model

By default the Client API is unauthenticated. The loopback bind ensures only local processes can reach it. Do not expose the port to the network or the internet. If you also run a regular browser on the controller machine, enable Enhanced security so a website you visit can't fire CORS-simple POSTs at the loopback API.

Port configuration

The default port is 3031. To change it, open the controller and go to SettingsClient ConfigurationClient API.

  • Port range: 1024–65535
  • Default: 3031
  • Changing the port restarts the local API server immediately. Any in-flight Stream Deck / Companion bindings need updating to the new port.

Enhanced security

A vMix-style opt-in token gate. Off by default. When enabled, every request must present a shared token, and the permissive CORS header is dropped so a website opened in the operator's browser can no longer fire requests at 127.0.0.1.

Enabling

SettingsClient ConfigurationClient API → tick Enhanced security. The controller mints a 256-bit token (43-char base64url) once per install and shows it in the same panel — Reveal, Copy, or Regenerate from there. Paste the token into your Stream Deck plugin / Companion module config.

Presenting the token

Either form is accepted, header takes precedence:

text
Authorization: Bearer <token>
text
http://127.0.0.1:<port>/v1/take/on?key=<token>

Requests without a valid token return 401 Unauthorized.

Regenerating

Click Regenerate in the Client Configuration panel. The previous token is invalidated immediately — update any Stream Deck / Companion bindings before regenerating, or you'll lock them out until they're re-pasted.

API versioning

The Client API uses path versioning. All canonical endpoints are prefixed with /v1/:

text
http://127.0.0.1:<port>/v1/<endpoint>

Un-versioned paths (e.g. /take/on) continue to work and return the same response, but include Deprecation: true and Link: </v1/...>; rel="successor-version" headers per RFC 9745. Update your integrations to the /v1/ paths at your convenience — no removal date is set.

Endpoints

All endpoints are rooted at http://127.0.0.1:<port>/v1. None of them take path or query parameters. They all act on the operator's currently-selected graphic and active channel.

GET Requests

EndpointDescription
/v1/graphic/nameName of the currently selected graphic as a JSON string, or null if nothing is selected
/v1/channel/numberActive output channel number (1-based integer)
/v1/channel/nameActive output channel name as a JSON string

POST Requests

EndpointDescriptionHotkey equivalent
/v1/take/onTake the selected graphic on — fires on every channel in its lock setNumpad Enter
/v1/take/offTake the selected graphic off — clears it from every channel it's live on (no advance)Numpad − (without advance)
/v1/take/on/nextTake on, then advance selection to the next graphicNumpad +
/v1/take/off/nextTake off, then advance selection to the next graphicNumpad −
/v1/clearClear every graphic from the active output channel(none)
/v1/panicInstantly clear all graphics from all channelsEsc Esc
/v1/refresh-previewReload the graphic preview iframeF8

See Hotkeys for the full keyboard reference.

Responses

POST requests

json
{ "ok": true }

GET requests

GET endpoints return raw JSON values, not wrapped objects:

json
"Lower Third"
json
3
json
null

The null value is returned when nothing is selected (/v1/graphic/name) or when no channel is active.

Status codes

CodeMeaning
200Success
404Endpoint not found (typo in path)
500Controller error. Check the controller log

There's no 401 because there's no authentication, and no 409 because POST actions are always accepted and behave as no-ops if there's nothing to act on (e.g. /v1/take/on with no graphic selected).

Examples

Read the active channel name

bash
curl http://127.0.0.1:3031/v1/channel/name

Take the selected graphic on-air

bash
curl -X POST http://127.0.0.1:3031/v1/take/on

Take on and advance (Numpad + equivalent)

bash
curl -X POST http://127.0.0.1:3031/v1/take/on/next

Panic, clear everything

bash
curl -X POST http://127.0.0.1:3031/v1/panic

Reload the preview

bash
curl -X POST http://127.0.0.1:3031/v1/refresh-preview

Common integrations

The Client API has no Lumora-specific plugins. All of these drive the endpoints above with each tool's generic HTTP action.

  • Stream Deck. Elgato's built-in HTTP Request action fires a request per button press. The Client API is particularly well-suited here: one button per hotkey-equivalent action, with no need to track graphic IDs as the show evolves.
  • Bitfocus Companion. Point Companion at http://127.0.0.1:<port> and use generic HTTP actions for each button.
  • Foot pedals / hardware controllers. Anything that can fire an HTTP request on press works. The "no auth" model is a feature here: hardware integrations can be set up in seconds.
  • Custom scripts. Useful for show-day automation that needs to read state (GET /v1/graphic/name) and react.

Troubleshooting

Connection refused. The controller isn't running, or it's running but the API server is bound to a different port. Open the controller and check SettingsClient ConfigurationClient API for the actual port.

401 Unauthorized on every request. Enhanced security is enabled and your request isn't presenting the token. Either include Authorization: Bearer <token> or append ?key=<token> to the URL. The token is shown in SettingsClient ConfigurationClient API.

Returns 404 on a known endpoint. Check for trailing slashes — POST /v1/take/on/ with a trailing slash may differ from POST /v1/take/on. Also verify you're using the /v1/ prefix.

Port in use. Another application on the controller machine is already bound to the same port (common conflicts: 3000, 8080, 8000). Pick a port in the range 1024–65535 that nothing else uses. The controller will refuse to start with a clear error if the port is taken.