Manar Labs

71 documented routes · iOS, Mac & Apple TV · Android & Android TV

LiveDeck control API

Every LiveDeck app runs a small local HTTP server so a Stream Deck, Bitfocus Companion, a browser remote, or your own script can switch, cue skins, run PTZ and start outputs — all on your own network, with nothing passing through our servers. This page documents every route, traced directly to the app's own source, with the platform differences called out rather than hidden.

API reference (PDF)Companion module (free) ↗ Download the standalone tester

Both apps already send Access-Control-Allow-Origin: * on every /api/* route, so the standalone tester works even opened straight from disk (file://) — no server in between, nothing to install.

Try it on your device

This opens the device's own API console in a new tab — nothing is sent to manarlabs.com. Your browser blocks a secure website like this one from calling devices on your local network directly, but the device's own page runs calls straight from your browser to the device.

Open my device's live API console

Find the token and the exact IP in the app under Output → Control API.

Pairing

The only two /api routes that don't need a token — but they only answer a peer on the same local network. Use this to get a token into a browser or a Companion install without ever showing the token on screen.

POST/api/pairNo token (local network only)
ParamWhereRequiredDescription
namebody (JSON)YesLabel shown in the app's pairing prompt, ≤40 characters.

Example request

curl -s -X POST http://192.168.1.42:8088/api/pair \
  -H 'Content-Type: application/json' \
  -d '{"name":"My browser"}'

Example response

{ "requestID": "a1b2c3", "code": "4821", "expiresIn": 60 }

Rate-limited to 5 requests/min per peer (429 past that), one pending pair at a time (409), and 503 if the app has no token configured yet (API fully closed). The app shows the 4-digit code for the operator to approve or deny on-screen.

GET/api/pair/<requestID>No token (local network only)
ParamWhereRequiredDescription
requestIDpathYesThe id returned by POST /api/pair.

Example request

curl -s http://192.168.1.42:8088/api/pair/a1b2c3

Example response

{ "state": "waiting", "expiresIn": 42 }
// then, once approved:
{ "state": "approved", "token": "<48-char hex token>" }
// or: { "state": "denied" } / { "state": "expired" }

Poll this every couple of seconds. The token is handed over exactly once — the server destroys the pairing record right after a successful "approved" read, so a second poll after that returns "expired".

State & monitoring

Read-only. Everything here works with GET and never changes anything in the app.

GET/api/stateBearer token

Example request

curl -s http://192.168.1.42:8088/api/state?token=YOUR_TOKEN

Example response

Full state JSON — the same object the browser remote polls as /state.json.
GET/api/programBearer token

Example request

curl -s http://192.168.1.42:8088/api/program?token=YOUR_TOKEN

Example response

{ "program": "...", "liveLayout": "...", "cuedLayout": "...", "takeStyle": "cut", "portrait": false, "programPtz": {...} }

Android's response additionally includes "preview" and "monMuted" keys that iOS does not return here.

GET/api/layoutsBearer token

Example request

curl -s http://192.168.1.42:8088/api/layouts?token=YOUR_TOKEN

Example response

Array of layout objects (id, name, sources, skins…).
GET/api/sourcesBearer token

Example request

curl -s http://192.168.1.42:8088/api/sources?token=YOUR_TOKEN

Example response

Array of source objects currently known to the mixer (NDI, cameras, satellites, test patterns).
POST/api/sources/<id>/removeBearer token
ParamWhereRequiredDescription
idpathYesSource id, from /api/sources.

Example request

curl -s -X POST http://192.168.1.42:8088/api/sources/cam1/remove?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/skinsBearer token

Example request

curl -s http://192.168.1.42:8088/api/skins?token=YOUR_TOKEN

Example response

iOS: { skins, skinKinds, skinEffects, skinTriggers, skinGroups, layouts }

Android's response is narrower: only { skins, skinKinds }. The skinEffects/skinTriggers/skinGroups/per-layout skin list are iOS-only on this route.

GET/api/transitionsBearer token

Example request

curl -s http://192.168.1.42:8088/api/transitions?token=YOUR_TOKEN

Example response

Array of available transition styles (cut, dissolve, …).
GET/api/audioBearer token

Example request

curl -s http://192.168.1.42:8088/api/audio?token=YOUR_TOKEN

Example response

Per-source audio state: gain, mute, solo, delay, follow mode, master level.
GET/api/healthBearer token

Example request

curl -s http://192.168.1.42:8088/api/health?token=YOUR_TOKEN

Example response

{ "ok": true }

Cheap liveness check — good for a Companion "device reachable" indicator.

GET/api/statsBearer token

Example request

curl -s http://192.168.1.42:8088/api/stats?token=YOUR_TOKEN

Example response

Engine stats: frame rate, dropped frames, CPU/thread load, output bitrates.
GET/api/eventsSSE streamBearer token

Example request

curl -N http://192.168.1.42:8088/api/events?token=YOUR_TOKEN

Example response

text/event-stream. `event: state` with a compact state payload on every change, plus a `: ping` comment every ~15s to keep the connection alive.

iOS's compact payload includes isLive/liveSince/liveSelection; Android's compact-key set omits those three fields. Not fetch-able from the standalone tester (EventSource keeps the connection open) — use curl -N or a Companion feedback instead.

GET/api/thumb/<id>Bearer token
ParamWhereRequiredDescription
idpathYesSource id.

Example request

curl -s http://192.168.1.42:8088/api/thumb/cam1?token=YOUR_TOKEN -o thumb.jpg

Example response

image/jpeg

Hitting this also counts as "someone is watching" and keeps that source's thumbnail refreshing.

GET/api/program.jpgBearer token

Example request

curl -s http://192.168.1.42:8088/api/program.jpg?token=YOUR_TOKEN -o program.jpg

Example response

image/jpeg — a snapshot of the current Program output.
GET/api/outputsBearer token

Example request

curl -s http://192.168.1.42:8088/api/outputs?token=YOUR_TOKEN

Example response

iOS: { out: { ndi, rtmp, record, hls, rtmpSrv, … }, isLive, liveSince, liveSelection, goLiveRemembered, lastGoLiveFailures }
Android: { out: { ndi, rec, rtmp, rtmpStatus, fb, fbStatus, fbConfigured, hls, hlsURL, viewers } }

The two platforms' output objects genuinely differ: Android exposes native Facebook Live fields (fb/fbStatus/fbConfigured) that iOS does not have via this API; iOS exposes GO LIVE bookkeeping (isLive/liveSince/liveSelection/goLiveRemembered) that Android's table doesn't list here.

Run a Show

Starts, steps through and ends a saved rundown (intro/outro, cued segments).

POST/api/show/startBearer token
ParamWhereRequiredDescription
recordqueryNoDefault true.
streamqueryNoDefault true.

Example request

curl -s -X POST 'http://192.168.1.42:8088/api/show/start?token=YOUR_TOKEN&record=true&stream=true'

Example response

{ "ok": true }
POST/api/show/nextBearer token

Example request

curl -s -X POST http://192.168.1.42:8088/api/show/next?token=YOUR_TOKEN

Example response

{ "ok": true }
POST/api/show/step/<index>Bearer token
ParamWhereRequiredDescription
indexpathYes0-based step index.

Example request

curl -s -X POST http://192.168.1.42:8088/api/show/step/2?token=YOUR_TOKEN

Example response

{ "ok": true }
POST/api/show/endBearer token

Example request

curl -s -X POST http://192.168.1.42:8088/api/show/end?token=YOUR_TOKEN

Example response

{ "ok": true }

Satellite

Controls a connected Satellite (a second phone sending camera/screen/test pattern) from the Studio side.

POST/api/satellite/talk/<on>Bearer token
ParamWhereRequiredDescription
onpathYes"on" or "off".

Example request

curl -s -X POST http://192.168.1.42:8088/api/satellite/talk/on?token=YOUR_TOKEN

Example response

{ "ok": true }
POST/api/satellite/talk/target/<target>Bearer token
ParamWhereRequiredDescription
targetpathYes"auto", "all", or a source id.

Example request

curl -s -X POST http://192.168.1.42:8088/api/satellite/talk/target/auto?token=YOUR_TOKEN

Example response

{ "ok": true }
POST/api/satellite/camera/<action>Bearer token
ParamWhereRequiredDescription
actionpathYes"flip", "torch", or "zoom".
valuequeryNoUsed by "zoom".
toqueryNoTarget satellite, if more than one.

Example request

curl -s -X POST 'http://192.168.1.42:8088/api/satellite/camera/flip?token=YOUR_TOKEN'

Example response

{ "ok": true }
POST/api/satellite/messageBearer token
ParamWhereRequiredDescription
textquery/bodyYesMessage text.
toqueryNoTarget satellite, if more than one.

Example request

curl -s -X POST 'http://192.168.1.42:8088/api/satellite/message?token=YOUR_TOKEN&text=Go+to+camera+2'

Example response

{ "ok": true }

Switching

Cue and take layouts — the core vision-mixing actions.

GET/api/layout/<id>/cueBearer token
ParamWhereRequiredDescription
idpathYesLayout id.

Example request

curl -s http://192.168.1.42:8088/api/layout/lower-third/cue?token=YOUR_TOKEN

Example response

{ "ok": true }

Cues green — does not go to air.

GET/api/layout/<id>/takeBearer token
ParamWhereRequiredDescription
idpathYesLayout id.

Example request

curl -s http://192.168.1.42:8088/api/layout/lower-third/take?token=YOUR_TOKEN

Example response

{ "ok": true }

Takes to air with the studio's current default transition.

GET/api/layout/<id>/take/<style>Bearer token
ParamWhereRequiredDescription
idpathYesLayout id.
stylepathYesTransition style, e.g. cut, dissolve.

Example request

curl -s http://192.168.1.42:8088/api/layout/lower-third/take/cut?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/takeBearer token
ParamWhereRequiredDescription
stylequeryNoOptional transition style override.

Example request

curl -s http://192.168.1.42:8088/api/take?token=YOUR_TOKEN

Example response

{ "ok": true }

Takes the currently cued layout.

GET/api/cutBearer token

Example request

curl -s http://192.168.1.42:8088/api/cut?token=YOUR_TOKEN

Example response

{ "ok": true }

Shortcut for take with a hard cut.

GET/api/transition/<style>Bearer token
ParamWhereRequiredDescription
stylepathYesNew studio default transition style.

Example request

curl -s http://192.168.1.42:8088/api/transition/dissolve?token=YOUR_TOKEN

Example response

{ "ok": true }

Skins

Lower thirds, tickers, clocks and other overlays played over Program.

GET/api/skin/<id>/playBearer token
ParamWhereRequiredDescription
idpathYesSkin id.

Example request

curl -s http://192.168.1.42:8088/api/skin/ticker1/play?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/skin/<id>/stopBearer token
ParamWhereRequiredDescription
idpathYesSkin id.

Example request

curl -s http://192.168.1.42:8088/api/skin/ticker1/stop?token=YOUR_TOKEN

Example response

{ "ok": true }
POST/api/skin/<id>/colorBearer token
ParamWhereRequiredDescription
idpathYesSkin id.
valuequeryYes#RRGGBB, or "original" to reset.

Example request

curl -s -X POST 'http://192.168.1.42:8088/api/skin/ticker1/color?token=YOUR_TOKEN&value=%23FF3366'

Example response

{ "ok": true }
GET/api/catalogBearer token

Example request

curl -s http://192.168.1.42:8088/api/catalog?token=YOUR_TOKEN

Example response

Merged bundled + remote skin catalogue index.

Served directly, not routed through the generic command table.

GET/api/catalog/<id>/addBearer token
ParamWhereRequiredDescription
idpathYesCatalogue item id.
layoutIdqueryNoLayout to add the skin to.

Example request

curl -s 'http://192.168.1.42:8088/api/catalog/lower-third-01/add?token=YOUR_TOKEN&layoutId=main'

Example response

{ "ok": true }

PTZ

Pan/tilt/zoom cameras — presets, direct moves and storing new presets.

GET/api/ptz/camerasBearer token

Example request

curl -s http://192.168.1.42:8088/api/ptz/cameras?token=YOUR_TOKEN

Example response

Array of PTZ-capable camera sources.
GET/api/ptz/<target>/preset/<n>Bearer token
ParamWhereRequiredDescription
targetpathYesCamera source id.
npathYesPreset number.
speedqueryNoAndroid only — default "1".

Example request

curl -s http://192.168.1.42:8088/api/ptz/cam1/preset/3?token=YOUR_TOKEN

Example response

{ "ok": true }

Android's handler also sends an optional speed parameter (default "1") that iOS's route does not declare.

GET/api/ptz/<target>/store/<n>Bearer token
ParamWhereRequiredDescription
targetpathYesCamera source id.
npathYesPreset number to store the current position as.

Example request

curl -s http://192.168.1.42:8088/api/ptz/cam1/store/3?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/ptz/<target>/pantiltBearer token
ParamWhereRequiredDescription
targetpathYesCamera source id.
panqueryYesPan speed/position.
tiltqueryYesTilt speed/position.

Example request

curl -s 'http://192.168.1.42:8088/api/ptz/cam1/pantilt?token=YOUR_TOKEN&pan=0.2&tilt=-0.1'

Example response

{ "ok": true }
GET/api/ptz/<target>/zoomBearer token
ParamWhereRequiredDescription
targetpathYesCamera source id.
speedqueryYesZoom speed.

Example request

curl -s 'http://192.168.1.42:8088/api/ptz/cam1/zoom?token=YOUR_TOKEN&speed=0.5'

Example response

{ "ok": true }

Audio

Per-source gain, mute, solo, delay and master level.

GET/api/audio/<id>/delay/<ms>Bearer token
ParamWhereRequiredDescription
idpathYesSource id.
mspathYes0–500.

Example request

curl -s http://192.168.1.42:8088/api/audio/cam1/delay/40?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/source/<id>/videodelay/<ms>Bearer token
ParamWhereRequiredDescription
idpathYesSource id.
mspathYes0–500.

Example request

curl -s http://192.168.1.42:8088/api/source/cam1/videodelay/40?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/audio/master/<value>Bearer token
ParamWhereRequiredDescription
valuepathYes0…1 on Android; iOS allows slightly over 1 for makeup gain.

Example request

curl -s http://192.168.1.42:8088/api/audio/master/0.8?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/audio/mode/<mode>Bearer token
ParamWhereRequiredDescription
modepathYes"follow" or "manual".

Example request

curl -s http://192.168.1.42:8088/api/audio/mode/follow?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/audio/<id>/gain/<value>Bearer token
ParamWhereRequiredDescription
idpathYesSource id.
valuepathYesGain level.

Example request

curl -s http://192.168.1.42:8088/api/audio/cam1/gain/0.9?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/audio/<id>/muteBearer token
ParamWhereRequiredDescription
idpathYesSource id.

Example request

curl -s http://192.168.1.42:8088/api/audio/cam1/mute?token=YOUR_TOKEN

Example response

{ "ok": true }

Toggles.

GET/api/audio/<id>/soloBearer token
ParamWhereRequiredDescription
idpathYesSource id.

Example request

curl -s http://192.168.1.42:8088/api/audio/cam1/solo?token=YOUR_TOKEN

Example response

{ "ok": true }

Toggles.

GET/api/audio/<id>/deleteBearer token
ParamWhereRequiredDescription
idpathYesSource id.

Example request

curl -s http://192.168.1.42:8088/api/audio/cam1/delete?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/audio/<id>/follow/<layoutId>Bearer token
ParamWhereRequiredDescription
idpathYesSource id.
layoutIdpathYesLayout to follow.

Example request

curl -s http://192.168.1.42:8088/api/audio/cam1/follow/main?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/monitor/mute/<state>Bearer token
ParamWhereRequiredDescription
statepathYes"on" or "off".

Example request

curl -s http://192.168.1.42:8088/api/monitor/mute/on?token=YOUR_TOKEN

Example response

{ "ok": true }

Outputs & Go Live

Starts/stops NDI, RTMP, recording and streaming outputs, and the "GO LIVE" shortcut that starts everything ticked at once.

GET/api/remote/pinBearer token

Example request

curl -s http://192.168.1.42:8088/api/remote/pin?token=YOUR_TOKEN

Example response

{ "pin": "4821" }

This is the human web-remote's PIN, unrelated to the API bearer token.

POST/api/remote/pinBearer token
ParamWhereRequiredDescription
pinquery/bodyYes4–8 digits, or "new" for a random one.

Example request

curl -s -X POST 'http://192.168.1.42:8088/api/remote/pin?token=YOUR_TOKEN&pin=new'

Example response

{ "pin": "7310" }
POST/api/output/nasBearer token
ParamWhereRequiredDescription
hostbodyYes
sharebodyYes
folderbodyNo
userbodyNo
passwordbodyNo

Example request

curl -s -X POST http://192.168.1.42:8088/api/output/nas?token=YOUR_TOKEN \
  -d host=192.168.1.50 -d share=Recordings

Example response

{ "ok": true }

Configures record-to-NAS.

POST/api/output/nas/clearBearer token

Example request

curl -s -X POST http://192.168.1.42:8088/api/output/nas/clear?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/output/ndi/name/<name>Bearer token
ParamWhereRequiredDescription
namepathYesNew NDI output name.

Example request

curl -s http://192.168.1.42:8088/api/output/ndi/name/Studio-A?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/output/quality/<quality>Bearer token
ParamWhereRequiredDescription
qualitypathYesiOS: 480p | 720p | 1080p. Android: 720p | 1080p.

Example request

curl -s http://192.168.1.42:8088/api/output/quality/1080p?token=YOUR_TOKEN

Example response

{ "ok": true }

iOS accepts 480p; Android does not offer it.

GET/api/output/portrait/<on>Bearer token
ParamWhereRequiredDescription
onpathYes"on" or "off".

Example request

curl -s http://192.168.1.42:8088/api/output/portrait/on?token=YOUR_TOKEN

Example response

{ "ok": true }
GET/api/output/<name>/<state>Bearer token
ParamWhereRequiredDescription
namepathYesiOS: ndi | rtmp | record | hls | rtmpserver. Android: ndi | record | rtmp | facebook | hls.
statepathYes"on" or "off".
urlqueryNoAndroid only, for name=rtmp — start with a specific server URL.

Example request

curl -s http://192.168.1.42:8088/api/output/ndi/on?token=YOUR_TOKEN

Example response

{ "ok": true }

The accepted name vocabulary differs by platform: rtmpserver exists only on iOS, facebook only on Android. Android's own /api/golive/select route (below) uses the iOS vocabulary instead of this one's — see the note there.

POST/api/goliveBearer token

Example request

curl -s -X POST http://192.168.1.42:8088/api/golive?token=YOUR_TOKEN

Example response

{ "ok": true }

Starts every output currently ticked in Output settings.

POST/api/golive/stopBearer token

Example request

curl -s -X POST http://192.168.1.42:8088/api/golive/stop?token=YOUR_TOKEN

Example response

{ "ok": true }

Confirm before wiring this to a hotkey — it stops every live output at once.

GET/api/golive/select/<name>/<state>Bearer token
ParamWhereRequiredDescription
namepathYesndi | rtmp | record | hls | rtmpserver — the same set on both platforms.
statepathYes"on" or "off" — ticks/unticks it for the next GO LIVE.

Example request

curl -s http://192.168.1.42:8088/api/golive/select/rtmp/on?token=YOUR_TOKEN

Example response

{ "ok": true }

On Android this route's name vocabulary (rtmpserver, no facebook) differs from /api/output/<name>/<state>'s own vocabulary (facebook, no rtmpserver) on the same device — flagged to engineering, not something this page can paper over.

NDI network

Configures how this device finds NDI sources — a discovery server address and/or a list of direct IPs. Answers on every device regardless of mode.

GET/api/ndi/networkBearer token

Example request

curl -s http://192.168.1.42:8088/api/ndi/network?token=YOUR_TOKEN

Example response

{ "discoveryServer": "", "directIPs": [] }
POST/api/ndi/networkBearer token
ParamWhereRequiredDescription
discoveryServerbodyNo
directIPsbodyNoComma-separated. Either/both fields; empty clears.

Example request

curl -s -X POST http://192.168.1.42:8088/api/ndi/network?token=YOUR_TOKEN \
  -d directIPs=192.168.1.21,192.168.1.22

Example response

{ "ok": true }

Raw command

The generic forwarder behind the browser remote's own control panel. Covers everything that doesn't have a dedicated shortcut route above.

POST/api/commandBearer token
ParamWhereRequiredDescription
actionbody or query, plus any action-specific fieldsYese.g. addLayout, renameLayout, duplicateLayout, removeLayout, addSkin, updateSkin, removeSkin, playSkin, stopSkin, camZoom, testPattern, addInput, addCamera, …

Example request

curl -s -X POST http://192.168.1.42:8088/api/command?token=YOUR_TOKEN \
  -H 'Content-Type: application/json' \
  -d '{"action":"testPattern","on":true}'

Example response

{ "ok": true }

GET is also accepted with the same params on the query string. This is the same JSON shape the browser remote's own POST /cmd uses.

TV routes

Only answered when the device is running in TV box mode (Apple TV / Android TV). On a phone, tablet or Mac these fall through to the generic 404.

GET/api/tvBearer token

Example request

curl -s http://192.168.1.42:8088/api/tv?token=YOUR_TOKEN

Example response

Current TV mode + status.
POST/api/tv/modeBearer token
ParamWhereRequiredDescription
modequery/bodyYeswatch | studio | choose (iOS also documents "choose" explicitly to return to the chooser screen).

Example request

curl -s -X POST http://192.168.1.42:8088/api/tv/mode?token=YOUR_TOKEN&mode=watch

Example response

{ "ok": true }
POST/api/tv/fullscreenBearer token
ParamWhereRequiredDescription
onquery/bodyYes

Example request

curl -s -X POST http://192.168.1.42:8088/api/tv/fullscreen?token=YOUR_TOKEN&on=true

Example response

{ "ok": true }
POST/api/tv/autostartBearer token
ParamWhereRequiredDescription
onquery/bodyYes

Example request

curl -s -X POST http://192.168.1.42:8088/api/tv/autostart?token=YOUR_TOKEN&on=true

Example response

{ "ok": true }
POST/api/tv/qualityBearer token
ParamWhereRequiredDescription
autoquery/bodyYes

Example request

curl -s -X POST http://192.168.1.42:8088/api/tv/quality?token=YOUR_TOKEN&auto=true

Example response

{ "ok": true }
GET/api/tv/sourcesBearer token

Example request

curl -s http://192.168.1.42:8088/api/tv/sources?token=YOUR_TOKEN

Example response

Sources the TV box can watch.
POST/api/tv/watchBearer token
ParamWhereRequiredDescription
sourcequery/bodyYesSource id to watch.

Example request

curl -s -X POST http://192.168.1.42:8088/api/tv/watch?token=YOUR_TOKEN&source=cam1

Example response

{ "ok": true }

Bonjour/mDNS: both platforms advertise the API as _livedeck-api._tcp, with the port in a TXT record — that's how Companion and the "Try it" console above find a device automatically on the same network.

Pairing without typing a token: use POST /api/pair and GET /api/pair/<id> above — the only two unauthenticated routes, and only answered to a peer already on your network.