← LivePlay

Developer API Reference

HTTP and WebSocket control for automation, external applications and custom control surfaces.

Describes the repository’s 2.5.0 implementation. Examples use illustrative IDs, paths and measurements. This page does not send commands to a server.

Connect

InterfaceAddressPurpose
HTTPhttp://<server>:4480/api/…Read and edit projects, configuration and transport
WebSocketws://<server>:4480/wsCommands, state changes and meters
DiscoveryUDP 4481; multicast 239.255.69.80LAN discovery; optional when address is known

Use the audio server address, not this GitHub Pages website. The desktop app and server may run on different machines. Filesystem paths always name files on the server. LivePlay does not stream audio over these interfaces. HTTP and WebSocket share the configured TCP port; no application TLS listener is configured.

Resources: a project item's uuid is its stable document identity; cueId/cue_id is a live engine identity. Read pages from GET /api/project/items to map them, including nested children. Fetch again after loading a project. Bus id and engine mixerId are separate. Playlist indices and cart slots are zero-based regardless of display numbering.

Optional LAN discovery

Listen for UTF-8 JSON UDP beacons on port 4481, sent about every three seconds through broadcast and multicast. Sending {"type":"liveplay-solicit"} to that port requests a unicast reply. Use the sender address and advertised port to connect; discovery does not authenticate a server.

{"type":"liveplay-beacon","name":"Stage-PC","version":"2.5.0","port":4480,"projectName":"Show","hasOpenProject":true,"itemCount":12,"instanceId":"per-run-id"}

name is the host name; instanceId identifies the running server instance; itemCount counts top-level items. If project-header serialization fails, the fallback beacon contains only type, name, port and instanceId. These UDP messages are separate from the WebSocket catalog.

Authentication

  1. Read GET /api/auth/status.
  2. If authRequired is true, use a user login token or an administrator-issued API token.
  3. Send HTTP Authorization: Bearer <token>.
  4. Connect WebSocket with /ws?access_token=<URL-encoded-token>. The handshake does not read the Bearer header.
Credential / roleBehavior
Authentication offMiddleware permits anonymous access, including administrator routes. Individual password/profile checks still apply. No accounts is the default; creating the first account makes it an administrator and enables authentication.
OperatorShow control and project editing. Administrator routes are refused.
AdministratorAlso manages users, API tokens, output mappings, server settings and connected-client listing.
User session token (lp1.)Expires after 30 days. Password change, account deletion or logout-all invalidates subsequent requests. Each HTTP request looks up the current role.
API token (lpk1_)Non-expiring operator credential for automation. Secret shown once. Explicitly denied filesystem browsing, uploads, copying, archive import/export/download, user preferences, logout-all, auth posture and token management; administrator routes are also denied.

API-token permission is listed per endpoint. These restrictions are the implemented path checks, not a complete filesystem isolation guarantee: some permitted project/cue operations also access disk. While authentication is required, WebSocket credentials are rechecked before commands and broadcasts. Expired or revoked sessions and anonymous sockets left open when login is enabled are closed with code 1008; reconnect with a valid credential.

Default CORS origin is *. A configured origin is returned for HTTP and checked exactly on WebSocket upgrades; a native WebSocket request without Origin is accepted by the origin check. Authentication still applies. Keep credentials out of saved URLs and shared logs.

Quick example

Use an already loaded show. This JavaScript example connects for state, finds its first loaded audio item and triggers it. Set token when login is required. Run in a native client or a browser origin allowed by the server; HTTPS pages cannot directly use insecure HTTP/WS in browsers.

const base = 'http://127.0.0.1:4480';
const token = ''; // Operator session or automation token, when required.
const headers = token ? { Authorization: `Bearer ${token}` } : {};
async function api(path, method = 'GET', body) {
  const r = await fetch(base + path, {
    method, headers: { ...headers, 'Content-Type': 'application/json' },
    ...(body === undefined ? {} : { body: JSON.stringify(body) })
  });
  const value = await r.json();
  if (!r.ok) throw new Error(value.error || `HTTP ${r.status}`);
  return value;
}
const url = new URL('/ws', base.replace(/^http/, 'ws'));
if (token) url.searchParams.set('access_token', token);
const ws = new WebSocket(url);
ws.onmessage = ({ data }) => {
  const event = JSON.parse(data);
  if (event.type !== 'meters') console.log(event);
};
await new Promise((resolve, reject) => {
  ws.onopen = resolve;
  ws.onerror = reject;
});
ws.send(JSON.stringify({ type: 'set_meter_hz', hz: 10 }));
const doc = await api('/api/project');
const flatten = items => items.flatMap(i => [i, ...flatten(i.children || [])]);
const cue = flatten(doc.items || []).find(i => i.type === 'audio' && i.cueId);
if (!cue) throw new Error('Load a project and wait for its audio first.');
await api(`/api/project/items/${encodeURIComponent(cue.uuid)}/play`, 'POST');

// Separate operator actions; invoke when needed:
const seek = seconds => api(`/api/project/items/${encodeURIComponent(cue.uuid)}/seek`, 'POST', { seconds });
const stop = () => api(`/api/project/items/${encodeURIComponent(cue.uuid)}/stop`, 'POST', { fade_ms: 250 });
const stopAll = () => api('/api/transport/stop_all', 'POST', { fade_ms: 0 });

For durable edits, PATCH the item/bus/settings and then POST /api/project/save with {} after a project path is set. Live pan/DSP endpoints do not store edits. Poll /api/state/summary for a compact control view; use WebSocket for meter delivery.

HTTP conventions

  • JSON requests use Content-Type: application/json; multipart uploads are explicitly marked. GET/DELETE and no-body actions need no JSON header.
  • Successful application handlers return 200, including creates and queue acknowledgments. JSON errors are {"error":"message"}. File downloads/static files return bytes.
  • Authentication adds 401 (with WWW-Authenticate: Bearer) and authorization adds 403. Uncaught handler exceptions become JSON 500; malformed inputs do not uniformly produce 400. Framework 404/405 bodies are not guaranteed JSON.
  • Path placeholders <string> identify the resource named in each entry; encode the segment. <int> is an integer. <path> can contain slash-separated segments. Parameters beginning with ? are query parameters; other table fields are request-body fields.
  • Some actions support GET as well as POST. Prefer POST. Crow maps HEAD to GET and executes the handler, so HEAD can also trigger these actions.
  • OPTIONS is handled by Crow: matched paths return 204 and Allow; unknown paths return 404. OPTIONS /* lists globally allowed methods. CORS preflight headers allow Content-Type and Authorization and have a 600-second max age.
  • No revision/ETag or transaction protocol is implemented for project edits. Coordinate multiple writers and re-fetch authoritative state after broad changes.

Examples below use curl syntax for a POSIX shell. In PowerShell use curl.exe and adapt quoting or use Invoke-RestMethod. Substitute real resource IDs and paths. Example responses may be abbreviated where explicitly stated; use the linked shared schema for the complete shape.

WebSocket lifecycle

  • Open /ws on the HTTP port; authenticated handshakes use access_token. Origin rejection is 403; missing/invalid token is 401.
  • The next broadcast tick sends playback_snapshot. Meters arrive automatically; default server cadence is 30 Hz, configurable 1–120 Hz. No project-document subscription is required.
  • Send JSON text objects with a string type. Binary application frames are ignored. No request IDs or universal success acknowledgments are defined.
  • ping → pong is an optional JSON liveness exchange, separate from WebSocket protocol control frames. No application heartbeat timeout is enforced.
  • On reconnect, obtain the new snapshot, re-fetch project/header/items/buses, and restore per-connection meter/analyser/locale preferences. There is no event replay, sequence number or resume token. Choose a reconnect delay/backoff in your client.
  • Most state events broadcast to every socket. Preferences are user-scoped; locale and meter-rate replies can be connection-scoped. The event catalog states the exceptions.
  • Commands control the show; events are notifications. Do not echo notifications back as commands. State changes from every low-level engine operation are not guaranteed to emit a document notification.

Loading reference…

REST endpoints

WebSocket commands · Client → Server

Bus control commands cover gain, mute and PFL. DSP parameters use the HTTP bus update methods; no WebSocket DSP read/write command is implemented. Stored changes arrive as buses_patched notifications.

WebSocket events · Server → Client

Document notifications · Server → Client

Every entry uses {"type":"doc_patch","op":"…",…}. All payload fields are top-level.

Shared schemas

Required/default columns on response-only schemas describe emitted fields, not request defaults. For simple endpoint responses, the field table is derived from the example and the notes describe conditional fields.

Coverage and maintenance

The endpoint count treats each registered HTTP method/path combination separately; compatible GET/POST aliases are shown together. Automatic HEAD/OPTIONS handling and the WebSocket upgrade are documented separately. The static-file route comes from the installed Crow dependency.

Reference data is the single contract catalog used by this page. Repository developer guides link here. Source evidence: control handlers, project state and serialization. Runtime findings are tracked in the repository API audit.