docs(wiki): add full HTTP API reference
+453
@@ -0,0 +1,453 @@
|
|||||||
|
# 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_host` and `daemon.http_port`
|
||||||
|
- API version prefix is always `/v1`
|
||||||
|
|
||||||
|
## Response Envelope
|
||||||
|
|
||||||
|
Successful responses:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Error responses:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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/state`
|
||||||
|
- `GET /v1/devices/living-room/state`
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### `GET /v1/devices`
|
||||||
|
|
||||||
|
List known devices.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://127.0.0.1:7272/v1/devices/discover
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns `data`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /v1/devices/{id}`
|
||||||
|
|
||||||
|
Get one known device by UUID or friendly name.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://127.0.0.1:7272/v1/devices/living-room/state
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns `data`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"device": {},
|
||||||
|
"state": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /v1/devices/{id}/apps`
|
||||||
|
|
||||||
|
List installed apps for device platform from cache.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://127.0.0.1:7272/v1/devices/living-room/apps
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns `data`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"platform": "roku",
|
||||||
|
"apps": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `POST /v1/devices/{id}/apps/launch`
|
||||||
|
|
||||||
|
Launch an app by normalized app id, app name, or platform id.
|
||||||
|
|
||||||
|
Request body:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"app": "jellyfin"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"clear": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`clear=true` clears platform cache before refresh.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"key": "home"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"keys": ["home", "home", "up"],
|
||||||
|
"delay_ms": 200
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`delay_ms` defaults to `200` when omitted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://127.0.0.1:7272/v1/devices/living-room/dev/logs
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns `data`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"device": {},
|
||||||
|
"lines": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /v1/daemon/status`
|
||||||
|
|
||||||
|
Get daemon health and runtime status.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://127.0.0.1:7272/v1/daemon/status
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns `data`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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_password` is redacted in API responses.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://127.0.0.1:7272/v1/config/reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns `data`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"restart_required": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Names
|
||||||
|
|
||||||
|
Common key names:
|
||||||
|
|
||||||
|
- `home`, `back`, `up`, `down`, `left`, `right`, `select`
|
||||||
|
- `play`, `pause`, `play-pause`, `stop`, `rewind`, `fast-forward`, `replay`, `skip`
|
||||||
|
- `volume-up`, `volume-down`, `mute`
|
||||||
|
- `power`, `power-on`, `power-off`
|
||||||
|
- `channel-up`, `channel-down`
|
||||||
|
- `input-hdmi1`, `input-hdmi2`, `input-hdmi3`, `input-hdmi4`, `input-av`, `input-tuner`
|
||||||
|
- `search`, `info`, `options`
|
||||||
|
- `literal:<text>` for raw adapter literal keys
|
||||||
|
|
||||||
|
## HTTP Status Mapping
|
||||||
|
|
||||||
|
Typical statuses:
|
||||||
|
|
||||||
|
- `200 OK` success
|
||||||
|
- `400 Bad Request` invalid key, invalid payload, ambiguous app, unsupported patch values
|
||||||
|
- `404 Not Found` unknown device/default device missing
|
||||||
|
- `500 Internal Server Error` transport/adapter/internal failures
|
||||||
|
|
||||||
|
## CORS Notes
|
||||||
|
|
||||||
|
Browser clients require CORS config:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[daemon]
|
||||||
|
cors_enabled = true
|
||||||
|
cors_allowed_origins = ["http://127.0.0.1:8080", "http://localhost:8080"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Then reload:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tvctl config reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Origin must match exactly (`http://127.0.0.1:8080` is not `http://0.0.0.0:8080`).
|
||||||
Reference in New Issue
Block a user