Networks API
These endpoints decide which interfaces the router serves with DHCP (IPv4) and DHCPv6 + router advertisements (IPv6), which addresses the pools hand out, how IPv6 prefix delegation is split between VLANs, and which DNS resolvers subscribers are given. Base URL, authentication and the error format are described in the API overview.
Every change is checked before it takes effect: the DHCP configuration is tested and the service restarted, and if either step fails the previous file is put back and the answer says … — rolled back. A 5xx answer can carry broken_data_files, naming router data files that do not parse.
Interfaces are addressed by name (vlan110, svlan300.10, bond0…). For VLANs, see VLANs, IPs and routes — adding a VLAN with an address serves it automatically.
Networks and interfaces
Section titled “Networks and interfaces”GET /networks
Section titled “GET /networks”Every IPv4 network configured on the router’s interfaces, with the IPv6 network of the same interface when it has one.
curl -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/networks{ "count": 1, "networks": [ { "iface": "vlan110", "gateway": "100.64.8.1", "subnet": "100.64.8.0", "mask": "255.255.255.0", "cidr": 24, "network": "100.64.8.0/24", "bcast": "100.64.8.255", "ipv6": "XXXX:XXXX:110::/64", "gateway6": "XXXX:XXXX:110::1" } ]}GET /interfaces
Section titled “GET /interfaces”Each IPv4 network and whether DHCP actually serves it: dhcp_active is true only when the subnet is in the DHCP configuration and the interface is in the DHCP listen list. The same for DHCPv6 when the interface has an IPv6 network.
curl -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/interfaces{ "count": 1, "interfaces": [ { "iface": "vlan110", "gateway": "100.64.8.1", "network": "100.64.8.0/24", "cidr": 24, "in_dhcp_conf": true, "in_dhcp_listen": true, "dhcp_active": true, "network6": "XXXX:XXXX:110::/64", "gateway6": "XXXX:XXXX:110::1", "in_dhcp6_conf": true, "in_dhcp6_listen": true, "dhcp6_active": true } ]}GET /net and GET /net6 give the same answer.
GET /iface
Section titled “GET /iface”Every link on the router (physical ports, bonds, VLANs, S-VLANs, C-VLANs, USB, loopback) with its state, VLAN tag, addresses and counters.
curl -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/iface{ "interfaces": [ { "name": "vlan110", "type": "vlan", "status": "UP", "parent": "bond0", "ips": ["100.64.8.1/24"], "ips6": ["XXXX:XXXX:110::1/64"], "vlan_id": 108, "vlan_proto": "802.1Q", "mtu": 1500, "speed_mbps": null, "rx_bytes": 123456789, "tx_bytes": 987654321 } ]}type is one of physical, vlan, svlan, cvlan, usb, loopback. status is UP only when the link is both up and has carrier.
DHCP (IPv4)
Section titled “DHCP (IPv4)”POST /dhcp/reload
Section titled “POST /dhcp/reload”Tests the DHCP configuration and restarts the DHCP service. Any other /dhcp/… path answers 404 Use /dhcp/reload.
curl -X POST -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/dhcp/reload{ "ok": true, "message": "DHCP reloaded" }On failure: 500 with error (DHCP config test failed or DHCP restart failed) and detail.
POST /net
Section titled “POST /net”Serves the IPv4 network already configured on an interface: its subnet block is added to the DHCP configuration and the interface to the listen list. If the subnet is already there, only the listen list is updated.
| Name | In | Type | Notes |
|---|---|---|---|
iface |
body | string | Interface that carries the IPv4 address, e.g. vlan110. |
label |
body | string | Optional text written as a comment on the subnet block. |
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"iface":"vlan110","label":"OLT 1 PON 0/1/3"}' \ http://ROUTER-IP:8880/net{ "ok": true, "code": 201, "message": "Network 100.64.8.0/24 added on vlan110", "network": { "iface": "vlan110", "gateway": "100.64.8.1", "network": "100.64.8.0/24", "cidr": 24 }, "label": "OLT 1 PON 0/1/3"}Errors: 404 when the interface has no IPv4 address; 500 when the configuration test or restart fails (rolled back).
DELETE /net
Section titled “DELETE /net”| Name | In | Type | Notes |
|---|---|---|---|
iface |
body | string | Interface to stop serving. |
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"iface":"vlan110"}' http://ROUTER-IP:8880/net{ "ok": true, "code": 200, "message": "Network 100.64.8.0/24 removed from vlan110", "network": { "iface": "vlan110", "network": "100.64.8.0/24" }}Errors: 409 while clients are still registered on the interface (Cannot remove: N client(s) registered on vlan110. Delete them first.); 404 when the interface has no IPv4 address; 500 when the subnet block is not found or the DHCP test/restart fails.
DHCPv6 and router advertisements
Section titled “DHCPv6 and router advertisements”POST /net6
Section titled “POST /net6”Adds the interface’s IPv6 network to DHCPv6, with an address pool derived from the network (for a /64: ::1000 to ::ffff), and updates router advertisements. If the other DHCPv6 subnets already carry name servers and no global IPv6 resolver is set, the new subnet inherits them.
| Name | In | Type | Notes |
|---|---|---|---|
iface |
body | string | Interface that carries a global IPv6 address. |
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"iface":"vlan110"}' http://ROUTER-IP:8880/net6{ "ok": true, "code": 201, "message": "IPv6 network XXXX:XXXX:110::/64 added on vlan110 (DHCPv6 + radvd)", "network6": { "iface": "vlan110", "gateway": "XXXX:XXXX:110::1", "prefix": 64, "network": "XXXX:XXXX:110::/64" }, "radvd": { "ok": true, "message": "radvd reloaded" }, "pool": "XXXX:XXXX:110::1000 - XXXX:XXXX:110::ffff", "dns": "XXXX:XXXX::53"}When no pool can be derived the answer carries warning instead of pool; when there is no resolver to inherit, dns is null and a note says so. Errors: 404 No IPv6 address on interface '…'; 500 when the DHCPv6 test or restart fails (rolled back).
DELETE /net6
Section titled “DELETE /net6”Removes the interface from DHCPv6. The subnet6 block is removed unless another served interface uses the same network; the interface’s prefix-delegation range is released.
| Name | In | Type | Notes |
|---|---|---|---|
iface |
body | string | Interface to stop serving over IPv6. |
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"iface":"vlan110"}' http://ROUTER-IP:8880/net6{ "ok": true, "code": 200, "message": "IPv6 network XXXX:XXXX:110::/64 removed from vlan110", "radvd": { "ok": true, "message": "radvd reloaded" }, "removed_pd_pool": { "network6": "XXXX:XXXX:110::/64", "start": "XXXX:XXXX:b:1000::", "end": "XXXX:XXXX:b:10ff::", "size": 256 }}POST /net6/pool
Section titled “POST /net6/pool”Sets the address range handed out on an interface’s IPv6 subnet. Without start/end the range is derived from the network. Parameters are read from the body, then the query string.
| Name | In | Type | Notes |
|---|---|---|---|
iface |
body or query | string | Interface whose subnet6 block exists (see POST /net6). |
start |
body or query | IPv6 | Optional first address; must be inside the network. |
end |
body or query | IPv6 | Optional last address; must be inside the network. |
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"iface":"vlan110"}' http://ROUTER-IP:8880/net6/pool{ "ok": true, "code": 200, "message": "pool added on XXXX:XXXX:110::/64", "iface": "vlan110", "network": "XXXX:XXXX:110::/64", "pool": "XXXX:XXXX:110::1000 - XXXX:XXXX:110::ffff", "dns_added": false}Errors: 400 for an invalid or out-of-network address, or when no pool can be derived; 404 when the interface has no IPv6 address or no subnet6 block.
POST /net6/lease
Section titled “POST /net6/lease”Sets the valid and preferred lifetimes DHCPv6 gives out (addresses and delegated prefixes) and updates router advertisements. GET /net6/lease takes the same parameters from the query string.
| Name | In | Type | Notes |
|---|---|---|---|
valid |
body | integer | Valid lifetime in seconds, at least 120. |
preferred |
body | integer | Optional; defaults to half of valid, cannot exceed it. |
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"valid":86400,"preferred":43200}' http://ROUTER-IP:8880/net6/lease{ "ok": true, "code": 200, "message": "DHCPv6 lifetimes updated", "changed": ["default-lease-time = 86400", "preferred-lifetime = 43200", "dhcp-renewal-time = 21600", "dhcp-rebinding-time = 34560"], "radvd": { "ok": true, "message": "radvd reloaded" }, "note": "existing leases keep their old lifetime until the client next renews"}IPv6 prefix delegation
Section titled “IPv6 prefix delegation”Delegated prefixes (by default /64s) come from one router-wide pool set in the router configuration (pd_pool, pd_len). Each VLAN gets a slice of that pool (default pd_slice prefixes); the first pd_reserve prefixes are kept back for prefixes pinned to single clients.
GET /pd
Section titled “GET /pd”The pool, its capacity, each VLAN’s slice, the pinned prefixes and the delegated routes the kernel holds now.
curl -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/pd{ "pool": "XXXX:XXXX:a::/48", "prefix_len": 64, "usable": true, "reserved_for_pinned": 4096, "default_slice": 256, "capacity": { "prefixes_total": 65536, "prefixes_reserved": 4096, "prefixes_used": 256, "prefixes_free": 61184, "largest_free_run": 61184, "vlans_at_default_slice": 240, "vlans_free_at_default_slice": 239 }, "per_vlan": { "vlan110": { "network6": "XXXX:XXXX:110::/64", "index": 4096, "slice": 0, "start": "XXXX:XXXX:a:1000::", "end": "XXXX:XXXX:a:10ff::", "len": 64, "size": 256 } }, "pinned": [{ "mac": "AA:BB:CC:DD:EE:FF", "hostname": "cpe-1", "prefix6": "XXXX:XXXX:a:5::/64" }], "live_routes": ["XXXX:XXXX:a:1000::/64 via fe80::1 dev vlan110 proto dhcp metric 1024"], "live_count": 1}POST /pd
Section titled “POST /pd”Enables prefix delegation on an interface that already has DHCPv6 (POST /net6). Calling it again with a new size re-allocates the slice.
| Name | In | Type | Notes |
|---|---|---|---|
iface |
body | string | Interface with a subnet6 block. |
size |
body | integer | Optional number of prefixes, a power of two (256, 512, 1024…); default is the configured slice. |
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"iface":"vlan110","size":256}' http://ROUTER-IP:8880/pd{ "ok": true, "code": 201, "message": "prefix delegation enabled on vlan110", "iface": "vlan110", "network": "XXXX:XXXX:110::/64", "pool": "XXXX:XXXX:a:1000:: - XXXX:XXXX:a:10ff::", "prefix_len": 64, "capacity": 256, "next": "set the CPE Site Prefix Type to \"Delegated\""}When the slice moved, replaced and warning are added (CPEs keep their old prefix until the lease expires; run a sync). Errors: 400 when size is not a power of two; 404 with no subnet6 block; 507 when the pool is exhausted (with requested and largest_free_run).
POST /pd/resize
Section titled “POST /pd/resize”| Name | In | Type | Notes |
|---|---|---|---|
iface |
body | string | Interface that already delegates. |
size |
body | integer | New number of prefixes (power of two). |
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"iface":"vlan110","size":1024}' http://ROUTER-IP:8880/pd/resizeThe answer is the same as POST /pd. Errors: 400 without size; 404 when the interface has no delegation; 409 when it already holds that many prefixes.
DELETE /pd
Section titled “DELETE /pd”| Name | In | Type | Notes |
|---|---|---|---|
iface |
body | string | Interface to stop delegating on. |
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"iface":"vlan110"}' http://ROUTER-IP:8880/pd{ "ok": true, "code": 200, "message": "prefix delegation removed from vlan110", "note": "delegated routes are withdrawn as their leases expire"}POST /pd/assign
Section titled “POST /pd/assign”Gives a client (by MAC) the same delegated prefix every time. Without prefix, the first free prefix in the reserved band is taken. GET /pd/assign takes the same parameters from the query string.
| Name | In | Type | Notes |
|---|---|---|---|
mac |
body | string | A registered client’s MAC. |
prefix |
body | IPv6 prefix | Optional; must have the delegated length and lie inside the pool. The length may be omitted. |
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"mac":"AA:BB:CC:DD:EE:FF","prefix":"XXXX:XXXX:a:5::/64"}' \ http://ROUTER-IP:8880/pd/assign{ "ok": true, "code": 200, "message": "pinned XXXX:XXXX:a:5::/64 to AA:BB:CC:DD:EE:FF", "mac": "AA:BB:CC:DD:EE:FF", "prefix6": "XXXX:XXXX:a:5::/64"}Errors: 404 unknown client; 400 invalid or out-of-pool prefix; 409 prefix pinned to another client; 507 no free prefix in the reserved band.
DELETE /pd/assign
Section titled “DELETE /pd/assign”| Name | In | Type | Notes |
|---|---|---|---|
mac |
body | string | Client whose pinned prefix is removed. |
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"mac":"AA:BB:CC:DD:EE:FF"}' http://ROUTER-IP:8880/pd/assign{ "ok": true, "code": 200, "message": "unpinned XXXX:XXXX:a:5::/64 from AA:BB:CC:DD:EE:FF" }Errors: 404 when the client has no pinned prefix.
POST /pd/sync
Section titled “POST /pd/sync”Runs the delegated-route reconciler now and returns its output. Any method on /pd/sync runs it.
| Name | In | Type | Notes |
|---|---|---|---|
dry |
query | 1 |
Only report what would change. |
curl -X POST -H "X-API-Key: YOUR_API_KEY" "http://ROUTER-IP:8880/pd/sync?dry=1"{ "ok": true, "code": 200, "dry_run": true, "output": ["…the reconciler's report, one line per entry…"]}DNS resolvers
Section titled “DNS resolvers”The resolvers subscribers receive over DHCP and DHCPv6: a global default, and optional per-VLAN overrides.
GET /dns
Section titled “GET /dns”What each served VLAN is actually given, where it comes from (per-vlan, global or none), and which served VLANs get no resolver at all.
curl -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/dns{ "global": { "ipv4": "XXX.XXX.XXX.53, XXX.XXX.XXX.53", "ipv6": "XXXX:XXXX::53", "domain": "example.net" }, "per_vlan": { "ipv4": { "100.64.9.0": "XXX.XXX.XXX.53" }, "ipv6": {} }, "effective": [ { "iface": "vlan110", "enabled": true, "ipv4": "XXX.XXX.XXX.53, XXX.XXX.XXX.53", "ipv4_source": "global", "ipv6": "XXXX:XXXX::53", "ipv6_source": "global" } ], "serving_no_resolver": []}POST /dns
Section titled “POST /dns”| Name | In | Type | Notes |
|---|---|---|---|
v4 |
body | string or list | IPv4 resolvers, comma-separated or a JSON list. |
v6 |
body | string or list | IPv6 resolvers. |
domain |
body | string | Search domain. |
apply |
body | string | Optional: all drops per-VLAN overrides so every VLAN follows the default; missing changes nothing further. |
iface |
body | string | If given, sets a per-VLAN override instead (same as POST /dns/{iface}). |
At least one of v4, v6, domain is required.
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"v4":"XXX.XXX.XXX.53,XXX.XXX.XXX.53","v6":"XXXX:XXXX::53","domain":"example.net"}' \ http://ROUTER-IP:8880/dns{ "ok": true, "code": 200, "message": "resolvers updated", "changed": ["ipv4 -> XXX.XXX.XXX.53, XXX.XXX.XXX.53", "domain -> example.net", "ipv6 -> XXXX:XXXX::53"], "note": "clients pick this up at their next DHCP renewal", "status": { "ipv4": "XXX.XXX.XXX.53, XXX.XXX.XXX.53", "ipv6": "XXXX:XXXX::53", "domain": "example.net" }}With apply, applied_to lists the VLANs whose overrides were dropped. Without it, a warning and shadowing list name VLANs whose own IPv6 resolvers hide the new default.
POST /dns/{iface}
Section titled “POST /dns/{iface}”| Name | In | Type | Notes |
|---|---|---|---|
iface |
path | string | Served VLAN interface, e.g. vlan130. |
v4 |
body | string or list | IPv4 resolvers for this VLAN. |
v6 |
body | string or list | IPv6 resolvers for this VLAN. |
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"v4":"XXX.XXX.XXX.53"}' http://ROUTER-IP:8880/dns/vlan130{ "ok": true, "code": 200, "message": "resolvers set on vlan130", "iface": "vlan130", "override": { "ipv4": "XXX.XXX.XXX.53" }, "note": "overrides the global resolvers for this VLAN only"}Errors: 400 without v4/v6 or with an invalid address; 404 when the interface, its network or its subnet block does not exist.
DELETE /dns/{iface}
Section titled “DELETE /dns/{iface}”| Name | In | Type | Notes |
|---|---|---|---|
iface |
path | string | VLAN interface. |
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/dns/vlan130{ "ok": true, "code": 200, "message": "override removed from vlan130", "removed": ["ipv4"], "now_inherits": { "ipv4": "XXX.XXX.XXX.53, XXX.XXX.XXX.53", "ipv6": "XXXX:XXXX::53", "domain": "example.net" }}Errors: 404 when the VLAN has no override.
DELETE /dns
Section titled “DELETE /dns”| Name | In | Type | Notes |
|---|---|---|---|
global |
body | string | v4, v6, domain or all (all also removes existing IPv6 resolvers). |
iface |
body | string | Alternatively, the VLAN whose override to remove. |
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"global":"domain"}' http://ROUTER-IP:8880/dns{ "ok": true, "code": 200, "message": "global resolvers cleared: domain", "cleared": ["domain"], "global_now": { "ipv4": "XXX.XXX.XXX.53, XXX.XXX.XXX.53", "ipv6": "XXXX:XXXX::53", "domain": null }, "serving_no_resolver": []}Errors: 400 when neither global nor an interface is given, or global has another value; 404 when nothing of that kind was set.
Action API equivalents
Section titled “Action API equivalents”| Action | Query parameters | Same as |
|---|---|---|
action=networks |
— | GET /networks |
action=interfaces |
— | GET /interfaces |
action=iface-list |
— | GET /iface (without the counters) |
action=reload |
— | POST /dhcp/reload |
action=add-net |
iface, label |
POST /net |
action=remove-net |
iface |
DELETE /net |
action=net6-add |
iface |
POST /net6 |
action=net6-del |
iface |
DELETE /net6 |
action=net6-pool |
iface, start, end |
POST /net6/pool |
action=net6-lease |
valid, preferred |
POST /net6/lease |
action=net6-dns |
servers, domain or clear_domain=1 |
Sets only the DHCPv6 resolvers/domain |
action=pd-list |
— | GET /pd |
action=pd-add |
iface, size |
POST /pd |
action=pd-resize |
iface, size |
POST /pd/resize |
action=pd-del |
iface |
DELETE /pd |
action=pd-assign |
mac, prefix |
POST /pd/assign |
action=pd-unassign |
mac |
DELETE /pd/assign |
action=pd-sync |
dry=1 |
POST /pd/sync |
action=dns-list |
— | GET /dns |
action=dns-set |
v4, v6, domain, apply, or iface + v4/v6 |
POST /dns, POST /dns/{iface} |
action=dns-del |
iface, or global=v4|v6|domain|all |
DELETE /dns/{iface}, DELETE /dns |
This site was written with the help of AI and checked by our team.