HTTP API
Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.
Conventions
Section titled “Conventions”Request and response bodies are JSON. Endpoints that take a body expect Content-Type: application/json. The base URL throughout this page is http://headend.local:8080; substitute the address and the port you configured with --port.
Channel identifiers in paths are the numeric id from the configuration file. They are reused after a delete, so a script that caches an identifier across a reconfiguration can act on the wrong channel.
Authentication
Section titled “Authentication”| Method | Path | Purpose |
|---|---|---|
| GET | /login | The login page itself. Of no use to a script; listed so that an unexpected HTML response to an API call is recognisable as a redirect to it. |
| POST | /api/login | Exchange username and password for a session cookie. Credentials are the values of CASTMUX_WEB_USERNAME and CASTMUX_WEB_PASSWORD. |
| POST | /api/logout | Invalidate the current session. |
With curl, store the cookie in a jar on login and present the jar afterwards:
# log in, keeping the session cookiecurl -s -c cookies.txt \ -H 'Content-Type: application/json' \ -d '{"username":"admin","password":"correct-horse-battery"}' \ http://headend.local:8080/api/login
# now call an authenticated endpoint with the same jarcurl -s -b cookies.txt \ http://headend.local:8080/api/viewersPublic endpoints
Section titled “Public endpoints”| Method | Path | Purpose |
|---|---|---|
| GET | /api/version | Version, commit and build time of the running binary. Deliberately unauthenticated, so a monitoring system can confirm what is deployed on every appliance in an estate without being given credentials to change anything on them. |
curl -s http://headend.local:8080/api/version# {"version":"3.1.0","commit":"9f2c41a","buildTime":"2026-04-08T09:12:44Z"}Channels
Section titled “Channels”| Method | Path | Purpose |
|---|---|---|
| Lifecycle | ||
| POST | /api/channels | Create a channel. The body is the same shape as one entry under streams in the configuration file. The assigned identifier is returned. |
| PUT | /api/channels/{id} | Replace the settings of an existing channel. A running channel is restarted if the change affects how it runs. |
| DELETE | /api/channels/{id} | Remove a channel. Stops it first. The identifier becomes available for reuse. |
| POST | /api/channels/{id}/restart | Restart one channel without touching the others. The first thing to try when a single channel is misbehaving and the rest are healthy. |
| State | ||
| POST | /api/streams/{id}/active | Enable or disable a channel. A disabled channel keeps its configuration but is never started. |
| POST | /api/streams/{id}/force-always-on | Toggle the always-on override. On, the channel runs continuously; off, it runs when viewer detection sees somebody watching. |
| Inspection | ||
| GET | /api/channels/{id}/logs | Recent engine output for one channel. This is where a source error appears in the words the origin actually used, rather than as a generic failure. |
| GET | /api/channels/resolutions | The resolution currently selected for each channel, and whether it is an exact match for the requested profile or the closest rung the origin offered. Served from cache; it does not block on origin fetches. |
| Preview | ||
| POST | /api/channels/{id}/preview | Start a browser-viewable preview of a channel. |
| POST | /api/channels/{id}/preview/stop | Stop it. Previews consume real CPU, so stop them explicitly rather than relying on closing the page. |
# create a channelcurl -s -b cookies.txt -X POST \ -H 'Content-Type: application/json' \ -d '{ "name": "Example One", "description": "Main lounge line-up", "active": true, "force_always_on": false, "engine": "tsduck", "resolution_profile": "hd", "source": {"type": "hls", "url": "https://origin.example.net/one/master.m3u8"}, "destination": {"address": "239.10.0.1", "port": 5000} }' \ http://headend.local:8080/api/channelsViewers
Section titled “Viewers”| Method | Path | Purpose |
|---|---|---|
| GET | /api/viewers | Viewer state for every channel in one call. Use this for polling rather than looping over channels, which multiplies the request count by the size of the line-up. |
| GET | /api/streams/{id}/viewers | Detail for one channel: the list of client addresses currently joined, the count, a flag for whether an IGMP querier is present on the segment, and a flag for whether detection is degraded. |
Metrics and system
Section titled “Metrics and system”| Method | Path | Purpose |
|---|---|---|
| Measurement | ||
| GET | /api/metrics | System metrics and per-channel metrics in one document: CPU, memory, uptime, per channel state and throughput. Cached for about two seconds server-side, so polling faster than that returns the same numbers and only costs you request handling. |
| GET | /api/network-stats | Interface-level counters and reachability results for the hosts in ping_hosts. |
| GET | /api/udp-bitrate | Measured bitrate actually leaving the network port, per channel. This is the engine-agnostic liveness signal: it reflects what is on the wire rather than what a decoder claims it is producing. |
| Administration | ||
| PUT | /api/settings | Replace the global settings. PUT only — there is no GET variant, so read current settings from the configuration file. |
| POST | /api/restart-all | Restart every channel. Starts are staggered by startup_stagger_seconds, so the whole line-up does not come back at once and fail together. |
| POST | /api/reboot | Reboot the appliance. Every channel is off air for the duration; this is not a remedy for a channel fault. |
DVB-C multiplexes
Section titled “DVB-C multiplexes”| Method | Path | Purpose |
|---|---|---|
| Multiplexes | ||
| GET | /api/dvb/muxes | List the configured multiplexes with their RF parameters and current state. Unlike channels, multiplexes do have a read endpoint. |
| POST | /api/dvb/muxes | Create a multiplex. |
| PUT | /api/dvb/muxes/{id} | Update RF parameters or signalling identifiers. Changing frequency, modulation or symbol rate interrupts the carrier. |
| DELETE | /api/dvb/muxes/{id} | Remove a multiplex. The channels it carried are not deleted. |
| POST | /api/dvb/muxes/{id}/active | Start or stop transmission of the carrier. |
| Contents and operations | ||
| POST | /api/dvb/muxes/{id}/channels | Assign the channels carried, and their order. The order determines service identifiers, so reordering re-identifies services and can require televisions to re-tune. Append rather than insert where you have the choice. |
| GET | /api/dvb/muxes/{id}/logs | Multiplexer and modulator output for this carrier. |
| POST | /api/dvb/muxes/{id}/hot-swap | Exchange the contents of a running multiplex without dropping the carrier, so sets stay tuned rather than reporting no signal during the change. |
| POST | /api/dvb/muxes/{id}/suspend | Suspend the multiplex temporarily, for maintenance on the modulator or the cable network, without deleting the configuration. |
HDMI output
Section titled “HDMI output”| Method | Path | Purpose |
|---|---|---|
| POST | /api/hdmi/active | Enable or disable the HDMI output. |
| POST | /api/hdmi/config | Set which channel is presented on the HDMI port and how it is rendered. |
| GET | /api/hdmi/metrics | State and throughput of the HDMI output. |
| GET | /api/hdmi/logs | Output from the HDMI rendering process. |
Automating a site build
Section titled “Automating a site build”A worked example: log in, create three channels, create a multiplex, and assign the channels to it in the order they should appear. This is the whole commissioning sequence for a small site, and it is worth scripting because typing three channels into a form is where transposed multicast addresses come from.
#!/usr/bin/env bashset -euo pipefail
BASE="http://headend.local:8080"JAR="$(mktemp)"
# 1. log in ------------------------------------------------------------curl -sf -c "$JAR" -H 'Content-Type: application/json' \ -d "{\"username\":\"$CASTMUX_USER\",\"password\":\"$CASTMUX_PASS\"}" \ "$BASE/api/login" > /dev/null
# 2. create the channels ------------------------------------------------# name | multicast group | source playlistCHANNELS=( "Example One|239.10.0.1|https://origin.example.net/one/master.m3u8" "Example Two|239.10.0.2|https://origin.example.net/two/master.m3u8" "Example News|239.10.0.3|https://origin.example.net/news/master.m3u8")
IDS=()for row in "${CHANNELS[@]}"; do IFS='|' read -r NAME GROUP URL <<< "$row"
ID=$(curl -sf -b "$JAR" -X POST -H 'Content-Type: application/json' \ -d "{ \"name\": \"$NAME\", \"active\": true, \"force_always_on\": true, \"engine\": \"tsduck\", \"resolution_profile\": \"hd\", \"source\": {\"type\": \"hls\", \"url\": \"$URL\"}, \"destination\": {\"address\": \"$GROUP\", \"port\": 5000} }" \ "$BASE/api/channels" | sed -n 's/.*"id":\([0-9]*\).*/\1/p')
echo "created $NAME as id $ID" IDS+=("$ID")
# respect the stagger: three HLS origins opened at once is the # failure this setting exists to prevent sleep 3done
# 3. create the multiplex ------------------------------------------------MUX=$(curl -sf -b "$JAR" -X POST -H 'Content-Type: application/json' \ -d '{ "name": "Mux A", "device": 0, "frequency": 474000000, "qam": 256, "symbol_rate": 6900, "network_id": 1, "ts_id": 1, "network_name": "Seaview Court", "active": true }' \ "$BASE/api/dvb/muxes" | sed -n 's/.*"id":\([0-9]*\).*/\1/p')
# 4. assign the channels, in line-up order -------------------------------# this order fixes the service IDs; changing it later means a re-tuneLIST=$(IFS=,; echo "${IDS[*]}")
curl -sf -b "$JAR" -X POST -H 'Content-Type: application/json' \ -d "{\"channel_ids\": [$LIST]}" \ "$BASE/api/dvb/muxes/$MUX/channels"
rm -f "$JAR"Two details in that script are not incidental. The sleep 3 between creations matches startup_stagger_seconds: three HLS origins opened simultaneously is the exact condition the stagger exists to avoid, and a build script is the easiest way to recreate it. And the channels are assigned in one call rather than three, because assignment order sets the service identifiers — building the list first and posting it once means the line-up is numbered as intended on the first attempt.
Notes and limitations
Section titled “Notes and limitations”- Errors are JSON. A failed request returns an appropriate status code and a JSON body describing the problem. An HTML response means the request was not authenticated and was redirected to the login page — check the cookie jar before debugging the body.
PUT /api/settingsreplaces, it does not merge. Send the complete set of global settings; anything omitted reverts to its default. The new settings are applied to running channels without restarting them.- Reads are incomplete. Channels can be created, updated and deleted through the API but not enumerated through it. Multiplexes can be listed. Until that is even, any script that needs the current configuration should read the configuration file.
- Rate limiting is not a substitute for cached data.
/api/metricsis cached for about two seconds; a dashboard polling it every 250 ms produces eight identical answers and no extra information.
A full read API, whole-configuration export and import, and API tokens in place of session cookies are all roadmap. They are listed with the rest on the roadmap page.