Skip to content

Services

A service is one customer on one ONT, with one speed, one fixed address and a permanent id. One call registers the ONT on its OLT (profiles, rate limit, QinQ service-port) and sets up the router side: the port’s VLAN interface, DHCP with Option 82, IPv6 and a delegated prefix, CGNAT, accounting and anti-spoofing. Read Concepts first for the numbering.

  • The OLT is registered with this router’s S-VLAN: dtvsol olt add … --svlan <n>. See OLTs.
  • The S-VLAN interface vlan<svlan> exists on the port or bond facing the OLT.
  • The services’ address pools are set in /opt/dtvsol/etc/config.php: svc_ipv4_pool (for example 100.64.0.0/10), and for IPv6 svc_ipv6_pool and svc_pd_pool. Without an IPv6 pool, services are IPv4 only.
  1. The technician connects and powers the ONU.

  2. He lists the ONTs that are connected and not yet registered:

    Terminal window
    dtvsol service unregistered
  3. He picks the serial and creates the service:

    Terminal window
    dtvsol service add 485754430A1B2C3D --name "Example Customer" --plan plan_200_200 \
    --olt olt-1 --pon 0/1/0 --ref C-0001 --contract C-0001
  4. The command prints the VLAN to set on the ONU’s WAN, with DHCP. The ONU then receives its fixed address.

Terminal window
dtvsol service unregistered [--olt n]
dtvsol service add <sn> --name "..." (--plan p | --down d --up u) [--olt n] [--pon f/s/p]
[--user-vlan v] [--ref r] [--contract c] [--expires YYYY-MM-DD|never]
[--comment ...] [--iptv] [--no-ipv6]
dtvsol service list [--state active|suspended|error] [--olt n] [-q text] [--fast] [--json]
dtvsol service get <id>
dtvsol service set <id> [--plan p | --down d --up u] [--name] [--contract] [--expires] [--comment] [--retry]
dtvsol service suspend <id> | resume <id>
dtvsol service del <id> [--keep-ont]
dtvsol service graph <id> [hour|day|week|month|year] [out.png] [--olt|--errors]

Notes:

  • <id> can be the service id, your ref, the ONT serial, the contract, the address or the interface.
  • --down/--up instead of --plan creates plan_<down>_<up> if it does not exist.
  • --pon can be left out: the router finds the serial in the OLT’s autofind table.
  • --user-vlan is for an ONU that already sends another VLAN (for example when taking over an existing network). The OLT translates it; the ONU is not touched.
  • --ref makes the call idempotent: the same ref returns the same service.
  • --iptv puts the ONT’s second Ethernet port on the OLT’s IPTV VLAN.
  • A plan change moves the ONT to the new rate limit on the OLT. The customer sees a few seconds of interruption.
  • Suspending deactivates the ONT on the OLT and blocks the address on the router. With an end date (--expires), the router suspends by itself on that date and resumes when you push a later date.
  • service graph --olt shows the ONT’s traffic as the OLT counts it; --errors its fiber errors (BIP, FEC).

A subscriber whose ONT was provisioned by hand can still be recorded:

Terminal window
dtvsol service add none --svlan 1000 --pon 0/1/0 --ont-id 7 --name "Example Customer" --plan plan_100_50

The same operations are available over HTTP on port 8880. Every request carries the API key in the X-API-Key header. The caller’s network must be on the allow-list (dtvsol protect add).

Give every call at least 60 seconds. Creating a service holds one OLT session (10–40 s), and may wait for the router’s own OLT work.

Unregistered ONTs:

Terminal window
curl -s -H "X-API-Key: $KEY" "http://XXX.XXX.XXX.10:8880/services/unregistered?olt=olt-1"
{ "ok": true, "count": 1,
"onts": [ { "olt": "olt-1", "pon": "0/1/0", "sn": "485754430A1B2C3D",
"vendor": "HWTC", "seen_at": "2026-09-25 10:12:03+00:00",
"svlan": 1000, "cvlan": 116 } ],
"errors": {} }

Create a service:

Terminal window
curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
"http://XXX.XXX.XXX.10:8880/services" -d '{
"ref": "C-0001", "sn": "485754430A1B2C3D", "olt": "olt-1", "pon": "0/1/0",
"down_mbps": 200, "up_mbps": 200, "name": "Example Customer",
"ipv6": true, "expires": "2026-12-31" }'

The answer (201) carries the service. Store service.id. Show technician.user_vlan to the technician:

{ "ok": true, "message": "Service created",
"service": {
"id": "svc_d320fcbd", "ref": "C-0001", "olt": "olt-1", "pon": "0/1/0", "ont_id": 7,
"svlan": 1000, "cvlan": 116, "user_vlan": 116, "iface": "v1000.116",
"ipv4": { "network": "100.64.16.0/24", "gateway": "100.64.16.1", "address": "100.64.16.9" },
"ipv6": { "link": "XXXX:XXXX:0:116::/64", "pd": "XXXX:XXXX:1:1600::/56" },
"plan": "plan_200_200", "state": "active" },
"technician": { "user_vlan": 116, "note": "set the ONU's WAN to VLAN 116, DHCP; it receives 100.64.16.9" } }

Other calls:

Call What it does
GET /services/{id} the record, plus live state: link, online, MAC seen, DHCP lease
POST /services/{id} change plan (or down_mbps/up_mbps), name, contract, comment, expires, or {"retry": true}
POST /services/{id}/suspend, /resume cut and restore
DELETE /services/{id} remove it everywhere (?keep_ont=1 leaves the ONT registered)
GET /services/{id}/graph?period=day a PNG of the traffic
GET /services?state=active&olt=olt-1&q=text&fast=1 the list

Error codes to handle: 400 bad field, 404 serial not in autofind, 409 serial already belongs to a service (the answer carries it), 502 the OLT refused or could not be reached (nothing was created), 500 the OLT side worked but the router side failed (the service exists in state error: fix the cause, then {"retry": true}), 507 no address left on that port.

The full integration guide for billing teams is in Billing integration.