System API
The endpoints on this page describe the router as a whole: its status, its health checks, its backups and saved configuration versions, and the traffic graphs it draws. For the base URL, authentication and error format, see the API overview.
Status and checks
Section titled “Status and checks”GET /status
Section titled “GET /status”A one-call summary of the router: version, whether the DHCP service is running, how many legacy per-MAC clients are registered and online, clients per network, and the anti-spoofing mode.
curl -s http://ROUTER-IP:8880/status -H "X-API-Key: YOUR_API_KEY"{ "api": "DTVSOL DHCP API v1.0", "router_version": "2026.09.27", "dhcp_service": "running", "total_clients": 42, "online_clients": 37, "per_network": { "10.110.0.0/21": 42 }, "interfaces": 6, "antispoof": "strict", "server_time": "2026-09-28 10:15:00"}antispoof is the configured mode (strict or dynamic) when anti-spoofing is enabled, otherwise off. online_clients counts clients whose address is currently a live neighbour of the router.
GET /doctor
Section titled “GET /doctor”The configuration doctor: a full audit of the router’s configuration and of what survives a reboot (addresses, VLANs, DHCP and router-advertisement configuration, data files, the configuration store, NTP for the OLTs). With ?olt=1 it also checks each registered OLT against the router’s records. It only reads.
| Name | In | Type | Notes |
|---|---|---|---|
olt |
query | boolean | 1 also checks the registered OLTs (slower). Omitted: the router only. |
curl -s "http://ROUTER-IP:8880/doctor?olt=1" -H "X-API-Key: YOUR_API_KEY"{ "ok": true, "code": 200, "generated": "2026-09-28 10:15:00", "count": 1, "counts": { "critical": 0, "warning": 1, "info": 0 }, "findings": [ { "severity": "warning", "area": "dhcp", "problem": "…", "detail": "…", "fix": "…" } ]}ok is true when there are no critical findings. Each finding carries a severity (critical, warning or info), the area it concerns, the problem, a detail and a suggested fix. The HTTP status is always 200; read ok and counts.
The CLI equivalent is dtvsol doctor (with the OLT checks) or dtvsol doctor --no-olt.
GET /alerts
Section titled “GET /alerts”The conditions worth attention right now: the DHCP service down, VLAN links down, address pools nearly full, the CGNAT pool, anti-spoofing drops, unknown devices, OLT and fibre problems reported by the OLT collector, and the licence. It only reads.
curl -s http://ROUTER-IP:8880/alerts -H "X-API-Key: YOUR_API_KEY"{ "count": 2, "generated": "2026-09-28 10:15:00", "alerts": [ { "severity": "critical", "type": "dhcp", "message": "DHCP service is not running" }, { "severity": "warning", "type": "olt", "olt": "olt-1", "message": "OLT olt-1: …" } ]}severity is critical, warning or info. type is one of dhcp, interface, dhcp-pool, stranger, cgnat, spoof, olt, fiber or licence; OLT and fibre alerts also name the olt (and, for fibre, the port and ONT).
For alarms with a history (raised, cleared, acknowledged), see the Alarms and health API.
Backup and restore
Section titled “Backup and restore”GET /backup
Section titled “GET /backup”Downloads a full backup of the router as a .tar.gz archive: the etc/ and data/ directories, with the configuration database included as a consistent copy taken at that moment. The response is the archive itself (Content-Type: application/gzip, with a Content-Disposition file name such as dtvsol-router-backup-20260928-101500.tar.gz).
curl -s http://ROUTER-IP:8880/backup -H "X-API-Key: YOUR_API_KEY" -OJOn failure the answer is JSON with status 500:
{ "error": "Backup failed", "detail": "…"}The CLI equivalent is dtvsol backup [outfile.tar.gz].
POST /restore
Section titled “POST /restore”Restores a backup archive that is already on the router (upload it first, for example with scp). Before unpacking, the current configuration is saved as a new configuration version, so the restore can itself be undone with dtvsol config restore <undo_version> --yes. After unpacking, the router rewrites the DHCP host files and reapplies shaping, accounting, CGNAT, port forwards, anti-spoofing and the firewall rules.
| Name | In | Type | Notes |
|---|---|---|---|
file |
body | string | Path of the .tar.gz archive on the router. Required. |
curl -s -X POST http://ROUTER-IP:8880/restore \ -H "X-API-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"file": "/root/dtvsol-router-backup-20260928-101500.tar.gz"}'{ "ok": true, "code": 200, "message": "Restored and services reapplied", "documents": ["clients", "services"], "undo_version": 57}Errors: 400 when the file is missing ("Provide an existing backup file path (upload it to the router first)") or is not a valid tar.gz; 500 when extraction fails, or when the archive was unpacked but its configuration documents could not all be brought in — that answer includes undo_version and a next hint with the command that returns to the configuration before the restore.
The CLI equivalent is dtvsol restore <file.tar.gz>.
Configuration versions (action API)
Section titled “Configuration versions (action API)”The router keeps saved versions of its configuration in its database, like a switch’s saved configuration in flash. Over HTTP these are reached only through the action API (/api?action=…); parameters go in the query string, or for POST in a JSON body (the body wins, the query string fills in what the body lacks). The CLI equivalent is dtvsol config ….
| Action | Method | Parameters | What it does |
|---|---|---|---|
action=config-status |
GET | — | Which saved version the running configuration matches, the latest version id, and whether there are unsaved changes (files added, removed, changed). |
action=config-versions |
GET | n (default 30, 1–1000) |
The newest saved versions: id, saved_at, saved_by, comment, auto, files, bytes, digest. |
action=config-save |
POST | comment (optional, up to 200 characters) |
Changes the router: saves the running configuration as a new version. A GET is refused with 405. Answers 201. |
action=config-diff |
GET | from (version id, required), to (version id or running, default running) |
What changed between two versions, or between a version and the running configuration. |
action=config-show |
GET | id (version id, required), path (optional) |
Without path: the list of files in that version. With path: that file’s content, with passwords, keys and tokens masked. |
Restoring a saved version is done from the CLI: dtvsol config restore <id> --yes.
curl -s "http://ROUTER-IP:8880/api?action=config-status" -H "X-API-Key: YOUR_API_KEY"{ "ok": true, "saved": { "id": 57, "saved_at": "2026-09-28 09:00:00", "comment": "before maintenance" }, "latest": 57, "unsaved": true, "changes": { "added": [], "removed": [], "changed": ["data/services.json"] }, "code": 200}curl -s -X POST "http://ROUTER-IP:8880/api?action=config-save" \ -H "X-API-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"comment": "new plans for October"}'{ "ok": true, "saved": true, "version": 58, "files": 24, "message": "…", "code": 201}curl -s "http://ROUTER-IP:8880/api?action=config-diff&from=57&to=running" -H "X-API-Key: YOUR_API_KEY"{ "ok": true, "from": 57, "to": "running", "changes": { "added": [], "removed": [], "changed": ["data/services.json"] }, "diff": "…", "code": 200}curl -s "http://ROUTER-IP:8880/api?action=config-show&id=57" -H "X-API-Key: YOUR_API_KEY"{ "ok": true, "version": 57, "files": ["etc/config.php", "data/services.json"], "code": 200}Errors: 400 for a missing or non-numeric from/id, or a to that is neither a version id nor running; 404 for a version (or a file in a version) that does not exist; 500 when the store cannot be read.
Traffic graphs
Section titled “Traffic graphs”Graphs are returned as PNG images (Content-Type: image/png). When no graph can be drawn the answer is JSON: {"error": "…"} with status 400 (bad parameters), 404 (no data yet — samples are collected every minute) or 500 (drawing failed).
GET /graph/{name}
Section titled “GET /graph/{name}”Traffic of one subscriber or one interface. {name} is a service id (svc_ followed by 8 hex digits), a client MAC address, or an interface name (for example vlan100).
| Name | In | Type | Notes |
|---|---|---|---|
name |
path | string | Service id, MAC address or interface name. |
period |
query | string | hour (last 3 hours), day (default), week, month or year. |
curl -s "http://ROUTER-IP:8880/graph/vlan100?period=week" \ -H "X-API-Key: YOUR_API_KEY" -o graph.pngGET /graph/oltport
Section titled “GET /graph/oltport”Traffic of an OLT PON port, an uplink port, or a whole card (all its ports), from the OLT collector’s samples.
| Name | In | Type | Notes |
|---|---|---|---|
olt |
query | string | Registered OLT name. Required. |
port |
query | string | F/S/P for a port, or F/S for a whole card. Required. |
pon |
query | boolean | 1 (default): a PON port; 0: an uplink port. |
period |
query | string | hour, day (default), week, month, quarter, year or 2years. |
curl -s "http://ROUTER-IP:8880/graph/oltport?olt=olt-1&port=0/1/3&period=month" \ -H "X-API-Key: YOUR_API_KEY" -o graph.pngGET /graph/ont
Section titled “GET /graph/ont”Traffic or error counters of one ONT, as seen by the OLT.
| Name | In | Type | Notes |
|---|---|---|---|
olt |
query | string | Registered OLT name. Required. |
port |
query | string | PON port F/S/P. Required. |
ont |
query | integer | ONT id on that port. Required. |
what |
query | string | traffic (default) or errors. |
period |
query | string | hour, day (default), week, month, quarter, year or 2years. |
curl -s "http://ROUTER-IP:8880/graph/ont?olt=olt-1&port=0/1/3&ont=12&what=errors" \ -H "X-API-Key: YOUR_API_KEY" -o graph.pngGET /services/{id}/graph
Section titled “GET /services/{id}/graph”Traffic of one service. {id} is anything that identifies the service (see the Services API).
| Name | In | Type | Notes |
|---|---|---|---|
id |
path | string | Service id or another key of the service. |
source |
query | string | router (default): traffic through the router; olt: traffic of its ONT as the OLT counts it; errors: the ONT’s error counters. |
period |
query | string | For router: hour, day (default), week, month, year. For olt/errors: also quarter and 2years. |
curl -s "http://ROUTER-IP:8880/services/svc_1a2b3c4d/graph?source=olt&period=week" \ -H "X-API-Key: YOUR_API_KEY" -o graph.pngErrors: 404 "No such service", or "This service has no ONT" for source=olt|errors on a service without an ONT.
Licence
Section titled “Licence”The router’s licence is not exposed over the HTTP API. It is managed on the router with the CLI:
| Command | What it does |
|---|---|
dtvsol licence status |
Shows whether the router is enrolled, the licence provider, whether the licence is valid (and why not), its expiry date with the days left, the last refresh (time and result), and a note about the clock. |
dtvsol licence refresh |
Fetches a fresh licence now (a timer also does this daily). |
dtvsol licence enrol <id> <token|-> |
Enrols the router with the id and token issued for it; - reads the token from standard input. |
An expiring or invalid licence also shows up as a licence alert in GET /alerts.
Action API equivalents
Section titled “Action API equivalents”| Action | Same as |
|---|---|
action=status |
GET /status |
action=doctor (&olt=1) |
GET /doctor |
action=alerts |
GET /alerts |
action=config-status |
dtvsol config status |
action=config-versions |
dtvsol config versions [n] |
action=config-save (POST) |
dtvsol config save ["comment"] |
action=config-diff |
dtvsol config diff <a> [b|running] |
action=config-show |
dtvsol config show <id> [path] |