Table of Contents
- HTTP API
- Base URL
- Response Envelope
- Device Identifiers
- Endpoints
- GET /v1/devices
- POST /v1/devices/discover
- GET /v1/devices/{id}
- DELETE /v1/devices/{id}
- GET /v1/devices/{id}/state
- GET /v1/devices/{id}/apps
- POST /v1/devices/{id}/apps/launch
- POST /v1/devices/{id}/apps/stop
- POST /v1/devices/{id}/apps/refresh
- POST /v1/devices/{id}/remote/key
- POST /v1/devices/{id}/remote/sequence
- POST /v1/devices/{id}/dev/install
- POST /v1/devices/{id}/dev/reload
- GET /v1/devices/{id}/dev/logs
- GET /v1/daemon/status
- GET /v1/config
- PATCH /v1/config
- POST /v1/config/reload
- Key Names
- HTTP Status Mapping
- CORS Notes
HTTP API
tvctl exposes a loopback HTTP API for local automation and dashboards.
Base URL
- Default:
http://127.0.0.1:7272/v1 - Configurable with
daemon.http_hostanddaemon.http_port - API version prefix is always
/v1
Response Envelope
Successful responses:
{
"ok": true,
"data": {}
}
Error responses:
{
"ok": false,
"error": {
"code": "device_not_found",
"message": "No known device matched 'living-room'.",
"hint": "Run tvctl device list to see known devices."
}
}
Use error.code for automation logic. message and hint are human-facing.
Device Identifiers
Anywhere {id} appears, you can use either:
- tvctl UUID
- Friendly device name
Example:
GET /v1/devices/3e2f7e8b-2d5e-4eb5-aef3-b2c4f2b2f17a/stateGET /v1/devices/living-room/state
Endpoints
GET /v1/devices
List known devices.
Example:
curl http://127.0.0.1:7272/v1/devices
Returns data as Device[].
POST /v1/devices/discover
Run discovery immediately and merge results into registry.
Example:
curl -X POST http://127.0.0.1:7272/v1/devices/discover
Returns data:
{
"devices": []
}
GET /v1/devices/{id}
Get one known device by UUID or friendly name.
Example:
curl http://127.0.0.1:7272/v1/devices/living-room
Returns data as Device.
DELETE /v1/devices/{id}
Remove one device from the registry.
Example:
curl -X DELETE http://127.0.0.1:7272/v1/devices/bedroom
Returns data as removed Device.
GET /v1/devices/{id}/state
Fetch live state for one device.
Example:
curl http://127.0.0.1:7272/v1/devices/living-room/state
Returns data:
{
"device": {},
"state": {}
}
GET /v1/devices/{id}/apps
List installed apps for device platform from cache.
Example:
curl http://127.0.0.1:7272/v1/devices/living-room/apps
Returns data:
{
"platform": "roku",
"apps": []
}
POST /v1/devices/{id}/apps/launch
Launch an app by normalized app id, app name, or platform id.
Request body:
{
"app": "jellyfin"
}
Example:
curl -X POST http://127.0.0.1:7272/v1/devices/living-room/apps/launch \
-H 'Content-Type: application/json' \
-d '{"app":"jellyfin"}'
Returns action payload in data.
POST /v1/devices/{id}/apps/stop
Stop the currently active app.
Example:
curl -X POST http://127.0.0.1:7272/v1/devices/living-room/apps/stop
Returns action payload in data.
POST /v1/devices/{id}/apps/refresh
Refresh cached app catalog from live device.
Request body is optional.
- Without body: merge/refresh cache
- With body:
{
"clear": true
}
clear=true clears platform cache before refresh.
Examples:
curl -X POST http://127.0.0.1:7272/v1/devices/living-room/apps/refresh
curl -X POST http://127.0.0.1:7272/v1/devices/living-room/apps/refresh \
-H 'Content-Type: application/json' \
-d '{"clear":true}'
Returns action payload in data.
POST /v1/devices/{id}/remote/key
Send a single normalized key.
Request body:
{
"key": "home"
}
Example:
curl -X POST http://127.0.0.1:7272/v1/devices/living-room/remote/key \
-H 'Content-Type: application/json' \
-d '{"key":"volume-up"}'
Returns action payload in data.
POST /v1/devices/{id}/remote/sequence
Send multiple normalized keys with per-key delay.
Request body:
{
"keys": ["home", "home", "up"],
"delay_ms": 200
}
delay_ms defaults to 200 when omitted.
Example:
curl -X POST http://127.0.0.1:7272/v1/devices/living-room/remote/sequence \
-H 'Content-Type: application/json' \
-d '{"keys":["home","home","home","up"],"delay_ms":200}'
Returns action payload in data.
POST /v1/devices/{id}/dev/install
Sideload a development package ZIP (Roku developer mode).
Content type: multipart/form-data
Form field:
archive: zip file bytes
Example:
curl -X POST http://127.0.0.1:7272/v1/devices/living-room/dev/install \
-F archive=@./channel.zip
Returns action payload in data.
POST /v1/devices/{id}/dev/reload
Reload currently sideloaded development package.
Example:
curl -X POST http://127.0.0.1:7272/v1/devices/living-room/dev/reload
Returns action payload in data.
GET /v1/devices/{id}/dev/logs
Fetch recent device developer logs.
Example:
curl http://127.0.0.1:7272/v1/devices/living-room/dev/logs
Returns data:
{
"device": {},
"lines": []
}
GET /v1/daemon/status
Get daemon health and runtime status.
Example:
curl http://127.0.0.1:7272/v1/daemon/status
Returns data:
{
"pid": 12345,
"socket": "/run/user/1000/tvctl.sock",
"http_enabled": true,
"http_host": "127.0.0.1",
"http_port": 7272,
"device_count": 1,
"default_device": "living-room"
}
GET /v1/config
Read effective config from disk.
Notes:
dev.roku_passwordis redacted in API responses.
Example:
curl http://127.0.0.1:7272/v1/config
Returns data as full config object.
PATCH /v1/config
Patch config using flat key/value pairs.
Rules:
- Keys are dotted paths (for example
daemon.http_port) - Values must be string, number, boolean, or
null
Example:
curl -X PATCH http://127.0.0.1:7272/v1/config \
-H 'Content-Type: application/json' \
-d '{"daemon.cors_enabled":true,"daemon.cors_allowed_origins":"http://127.0.0.1:8080"}'
Returns same shape as config reload result in data.
POST /v1/config/reload
Reload daemon config from disk.
Example:
curl -X POST http://127.0.0.1:7272/v1/config/reload
Returns data:
{
"config": {},
"restart_required": []
}
Key Names
Common key names:
home,back,up,down,left,right,selectplay,pause,play-pause,stop,rewind,fast-forward,replay,skipvolume-up,volume-down,mutepower,power-on,power-offchannel-up,channel-downinput-hdmi1,input-hdmi2,input-hdmi3,input-hdmi4,input-av,input-tunersearch,info,optionsliteral:<text>for raw adapter literal keys
HTTP Status Mapping
Typical statuses:
200 OKsuccess400 Bad Requestinvalid key, invalid payload, ambiguous app, unsupported patch values404 Not Foundunknown device/default device missing500 Internal Server Errortransport/adapter/internal failures
CORS Notes
Browser clients require CORS config:
[daemon]
cors_enabled = true
cors_allowed_origins = ["http://127.0.0.1:8080", "http://localhost:8080"]
Then reload:
tvctl config reload
Origin must match exactly (http://127.0.0.1:8080 is not http://0.0.0.0:8080).