Billing integration
A billing can drive the router in two ways:
- The REST API on port 8880. New integrations use it, with services.
- MK-api on port 8728: a MikroTik RouterOS API listener, for a billing that already provisions MikroTik routers and cannot be changed. It works with MAC-based clients.
REST API basics
Section titled “REST API basics”-
Address:
http://<router>:8880. -
Every request carries the API key: header
X-API-Key: <key>(or?api_key=on GET). The key was printed by the installer and is in/opt/dtvsol/etc/config.php. -
The billing server’s network must be on the allow-list:
Terminal window dtvsol protect add XXX.XXX.XXX.25 "billing" -
JSON in, JSON out.
-
Timeouts: at least 60 seconds per call (120 s is comfortable). Creating a service holds one OLT session (10–40 s), and the router talks to an OLT one session at a time. A call that arrives while the router is syncing or saving that OLT waits up to about 25 s more. That is not an error: do not retry early.
The provisioning flow
Section titled “The provisioning flow” billing (support) billing (technician app) router OLT 1. create customer and contract 2. installs the ONU, taps "register ONU" GET /services/unregistered --> asks every OLT -------> autofind <-- list of ONTs {olt, pon, sn, vendor} 3. picks the serial POST /services -------------> registers the ONT ---> ONT, service-port, {ref, sn, olt, pon, plan} address, DHCP, CGNAT, rate limit anti-spoofing <-- 201 {service: {id, ipv4}, technician: {user_vlan}} 4. shows "ONU WAN = VLAN <user_vlan>, DHCP" 5. stores service.id 6. later, by id: plan change, suspend/resume, end date, delete, status, graphEndpoints
Section titled “Endpoints”| Call | Purpose |
|---|---|
GET /services/unregistered[?olt=<name>] |
ONTs connected and not registered (about 3 s per OLT) |
POST /services |
create a service (the one call) |
GET /services/{id} |
status: record, plan and live state |
POST /services/{id} |
change plan, names, end date, or retry |
POST /services/{id}/suspend, /resume |
cut at the fiber and on the router, and restore |
DELETE /services/{id}[?keep_ont=1] |
remove it; the id is never reused |
GET /services/{id}/graph?period=hour|day|week|month|year |
a PNG of the traffic |
GET /services?state=…&olt=…&q=…&fast=1 |
list; fast=1 skips the live probe |
{id} accepts the service id, your ref, the serial, the contract or the IPv4 address.
POST /services fields
Section titled “POST /services fields”| Field | Required | Meaning |
|---|---|---|
ref |
recommended | your id for this service. Makes the call idempotent: repeating it returns the existing service (200, existing: true). |
sn |
yes | the ONT serial, 16 hex digits |
olt |
when more than one OLT | the OLT name |
pon |
recommended | frame/slot/port; looked up in autofind if left out |
plan, or down_mbps + up_mbps |
yes | a plan name, or speeds (plan_<down>_<up> is created if missing) |
name |
yes | the customer, as you want to see it on the router |
contract, comment |
no | free text, stored and searchable |
user_vlan |
no | the VLAN the ONU sends, when it is not the port’s |
ipv6 |
no | default true when the router has an IPv6 pool |
iptv |
no | the ONT’s second Ethernet port on the IPTV VLAN |
expires |
no | end date: suspended on that date, resumed when you push a later one |
Example request:
{ "ref": "C-0001", "sn": "485754430A1B2C3D", "olt": "olt-1", "pon": "0/1/0", "down_mbps": 200, "up_mbps": 200, "name": "Example Customer", "contract": "C-0001", "ipv6": true, "expires": "2026-12-31" }Store service.id from the answer, and show technician.user_vlan to the technician. The
subscriber’s address (service.ipv4.address) is fixed for the life of the service. See
Services for a full answer.
Changes
Section titled “Changes”{ "plan": "plan_300_300" }{ "down_mbps": 300, "up_mbps": 300 }{ "name": "…", "contract": "…", "comment": "…", "ref": "…" }{ "expires": "2026-11-30" }{ "expires": "never" }{ "retry": true }A plan change moves the ONT to the new rate limit (a few seconds of interruption). The answer’s
olt field says whether the OLT side succeeded. A 502 on suspend or resume means the router
side was done and the OLT did not follow: retry.
Errors
Section titled “Errors”| Code | Meaning | What to do |
|---|---|---|
400 |
a field is missing or invalid (error says which) |
fix the request |
404 |
the serial is not in the OLT’s autofind table | the ONU is not connected, not seen yet, or already registered |
409 |
the serial already belongs to a service (returned), or the port cannot be used now | use the returned id; otherwise ask the operator |
502 |
the OLT refused or could not be reached | retry later; nothing was created |
500 |
the OLT side worked, the router side failed | the service is in state error: {"retry": true} after the cause is fixed |
507 |
no address left on that port | ask the operator |
- Always send
ref. A retry after a network timeout then never creates a second service. - Numbering is derived, never chosen. See Concepts.
- The MAC address is not an input. If the customer replaces his router, the service keeps working with the same address and id.
MK-api (MikroTik compatible)
Section titled “MK-api (MikroTik compatible)”MK-api listens on TCP 8728 and speaks enough of the MikroTik RouterOS API that a billing thinks it talks to a MikroTik. It turns the billing’s commands into calls to the router’s own API.
Scope: DHCP/IPoE only.
| Billing command | What the router does |
|---|---|
/ip/dhcp-server/lease/add |
creates a client (MAC + address) |
/ip/dhcp-server/lease/set (disabled) |
suspends or resumes the client |
/ip/dhcp-server/lease/remove |
deletes the client |
/ip/dhcp-server/lease/print |
lists the clients |
/queue/simple/… or a lease rate-limit |
sets the speed: a plan mk_<down>m_<up>m is made for it |
/ppp/… (PPPoE) |
refused |
Set it up:
dtvsol mkapi # statusdtvsol mkapi set user billing password '<password>'dtvsol mkapi set identity router-1identity, model <m> and version <v> set what the router answers when the billing asks
which MikroTik it is talking to. port <n> changes the port.
The billing’s address must be on the allow-list (dtvsol protect add). The listener runs as
dtvsol-mkapi.service.
This site was written with the help of AI and checked by our team.