Appearance
HTTP REST API
Exaplay 3 exposes an HTTP REST API for programmatic control of compositions, Playlists, Timelines, and media playback. This is the same API used by the Exaplay web UI and is suitable for integration with external show control systems, custom applications, and automation scripts.
Naming note: The Exaplay UI calls this composition type a Playlist. The wire protocol still uses the original
cuelistidentifier (composition type string, request names such ascuelist.seek, status fields such asCUEINDEX). This is intentional so existing integrations continue to work — treatcuelistandCueListin the protocol as synonyms for Playlist in the UI.
Connection
| Parameter | Value |
|---|---|
| Protocol | HTTP |
| Default Port | 8123 |
| Content-Type | application/json |
All commands are sent as POST requests to http://<host>:8123/project with a JSON body. The req field in the body specifies the command.
Composition Transport
These commands control playback of any composition (CueList or Timeline).
All transport commands are sent as POST /project requests with the req field. For composition.play there is also a convenience shortcut — see below.
req value | Required fields | Description |
|---|---|---|
composition.play | src-uid | Start playback |
composition.pause | src-uid | Pause playback |
composition.stop | src-uid | Stop playback |
composition.set-time | src-uid, time | Seek to position (seconds) |
composition.next | src-uid | Advance to the next cue/item (CueList only) |
composition.prev | src-uid | Go back to the previous cue/item (CueList only) |
Example: Seek a composition to 30 seconds
http
POST /project HTTP/1.1
Content-Type: application/json
{
"req": "composition.set-time",
"src-uid": 12345678,
"time": 30.0
}Response: 200 OK
Play by name — POST /composition/play
A convenience endpoint that locates a composition by name (or UID) and starts playback without requiring an upfront GET /project lookup.
Fields:
| Field | Type | Description |
|---|---|---|
name | string | Name of the composition to play |
src-uid | integer | UID of the composition (alternative to name) |
Provide either name or src-uid. If both are present, the first composition matching either value is played.
http
POST /composition/play HTTP/1.1
Content-Type: application/json
{
"name": "Main Show"
}Response: 200 OK — composition found and started Response: 400 Bad Request — neither name nor src-uid provided Response: 404 Not Found — no composition matches the given name or UID
Cue Commands
Trigger a cue in a specific composition — cue.go
Triggers a cue inside one specific composition, addressed by the composition's UID. This is the endpoint to use when several compositions contain cues with the same name and /cue/trigger (below) would be ambiguous.
req value | Required fields | Description |
|---|---|---|
cue.go | comp-uid, cue or name | Trigger a cue by index or name in the given composition |
cue.execute | comp-uid, cue-uid | Trigger a cue by its UID in the given composition |
cue.next | comp-uid | Advance to the next item (Playlist compositions only) |
cue.prev | comp-uid | Go back to the previous item (Playlist compositions only) |
Fields:
| Field | Type | Description |
|---|---|---|
comp-uid | integer | The UID of the target composition (from GET /project) |
cue | integer | Timeline: the cue's variable index · Playlist: the 1-based item position |
name | string | Cue/item name (case-insensitive, within this composition) — alternative to cue |
cue-uid | integer | The cue object's UID (cue.execute only) |
Behaviour of cue.go:
- Timeline — the playhead jumps to the cue's time offset, then the cue's action (play/pause/stop/custom) is executed.
- Playlist — the item at the given 1-based position starts playing.
Example: Trigger cue 5 in composition UID 12345678
http
POST /project HTTP/1.1
Content-Type: application/json
{
"req": "cue.go",
"comp-uid": 12345678,
"cue": 5
}Example: Trigger the cue named "Blackout" in composition UID 12345678
http
POST /project HTTP/1.1
Content-Type: application/json
{
"req": "cue.go",
"comp-uid": 12345678,
"name": "Blackout"
}Response: 200 OK (or 404 if the composition/cue does not exist, 500 if triggering failed)
Trigger a cue by name across all compositions — POST /cue/trigger
This is a separate endpoint (not a req on /project): POST http://<host>:8123/cue/trigger. It searches all compositions in project order — Timeline cues by name or variable index, Playlist items by name or variable index — and fires the first match.
| Body field | Type | Description |
|---|---|---|
name | string | Cue/item name to match (case-insensitive) |
number | integer | Cue variable index to match (alternative to name) |
comp | string | (optional) Restrict the search to the composition with this variable name |
comp-uid | integer | (optional) Restrict the search to the composition with this UID |
bash
curl -X POST http://192.168.1.5:8123/cue/trigger \
-H "Content-Type: application/json" \
-d '{"name": "Scene 1 - Opening"}'Scoped to one composition — with comp (or comp-uid) only that composition is searched, so identically named cues elsewhere can never fire:
bash
curl -X POST http://192.168.1.5:8123/cue/trigger \
-H "Content-Type: application/json" \
-d '{"name": "Blackout", "comp": "comp_act2"}'Response: 200 OK on the first match, 404 if no cue matched (or the scoped composition does not exist), 400 if neither name nor number was supplied.
Duplicate cue names: without a scope the first match wins, so either keep cue names project-unique or pass
comp/comp-uid. Alternatively usecue.gowithcomp-uid+name.
CueList Commands
Seek within a CueList
Seek the currently playing item in a CueList to a specific time position. Unlike the generic composition.set-time endpoint, this endpoint validates that the target composition is a CueList and returns 400 Bad Request if it is not. Use this endpoint when integrating external control systems that specifically target CueList compositions.
For seeking any composition type (CueList or Timeline), use composition.set-time instead.
req value | Required fields | Description |
|---|---|---|
cuelist.seek | src-uid, time | Seek CueList playback to position (seconds) |
Fields:
| Field | Type | Description |
|---|---|---|
src-uid | integer | The UID of the CueList composition |
time | float | Target position in seconds |
Example: Seek a CueList to 15.5 seconds
http
POST /project HTTP/1.1
Content-Type: application/json
{
"req": "cuelist.seek",
"src-uid": 12345678,
"time": 15.5
}Response: 200 OK
Media Commands
Seek a specific media item
Seek within a specific media item by its UID. This is useful when you know the exact media item (e.g., from a CueList item click).
req value | Required fields | Description |
|---|---|---|
media.set-time | src-uid, time | Seek a media item to position (seconds) |
Fields:
| Field | Type | Description |
|---|---|---|
src-uid | integer | The UID of the media item |
time | float | Target position in seconds |
Example: Seek a media item to 10 seconds
http
POST /project HTTP/1.1
Content-Type: application/json
{
"req": "media.set-time",
"src-uid": 87654321,
"time": 10.0
}Response: 200 OK
Error Responses
| HTTP Status | Meaning |
|---|---|
200 | Success |
400 | Bad request (missing or invalid parameters) |
404 | Composition or media item not found |
500 | Internal server error |
Cross-Reference: Other Protocols
The same seeking functionality is available via other protocols:
| Protocol | Command | Documentation |
|---|---|---|
| TCP | set:cuetime,COMPID,SECONDS | TCP API |
| UDP | set:cuetime,COMPID,SECONDS | UDP API |
| OSC | /exaplay/<comp>/cuetime <seconds> | Config → Network → OSC |
Examples
Python
python
import requests
HOST = "http://192.168.1.5:8123"
# Seek a cuelist to 30 seconds
requests.post(f"{HOST}/project", json={
"req": "cuelist.seek",
"src-uid": 12345678,
"time": 30.0,
})
# Play a composition
requests.post(f"{HOST}/project", json={
"req": "composition.play",
"src-uid": 12345678,
})
# Stop a composition
requests.post(f"{HOST}/project", json={
"req": "composition.stop",
"src-uid": 12345678,
})JavaScript / Node.js
javascript
const HOST = "http://192.168.1.5:8123";
// Seek a cuelist to 15 seconds
await fetch(`${HOST}/project`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
req: "cuelist.seek",
"src-uid": 12345678,
time: 15.0,
}),
});curl
bash
# Seek a cuelist to 45.5 seconds
curl -X POST http://192.168.1.5:8123/project \
-H "Content-Type: application/json" \
-d '{"req":"cuelist.seek","src-uid":12345678,"time":45.5}'
# Play a composition
curl -X POST http://192.168.1.5:8123/project \
-H "Content-Type: application/json" \
-d '{"req":"composition.play","src-uid":12345678}'