products:software:edgeos:api

This is an old revision of the document!


EdgeOS API Guide

The EdgeOS API is largely undocumented. However as the requests and responses can be monitored in a web-browser a lot of information on how it works can be derived.

A HTTP POST to https://host-or-ip/ with the username and password encoded as a simple application/x-www-form-urlencoded form with the following request content will grant you a PHPSESSID cookie that is used to confirm you are authenticated:

username=<<USERNAME>>&password=<<PASSWORD>>

This will return a HTTP status code "303 See Other" on success and the same login form again with a "200 OK" containing the text "The username or password you entered is incorrect" on failure, be careful as some web clients will automatically follow the 303 redirection and the cookies may not be where you expect them to be.

The session ID is returned multiple times but the only header of importance for authentication is:

Set-Cookie: PHPSESSID=9a00126c5bf04e29835f7c13fe5ab155; secure

A session is valid for 15 minutes and is refreshed on every web request.

A session can be extended with a HTTP GET to /api/edge/heartbeat.json?t=«EPOCH» where «EPOCH» is the current time in EPOCH notation (such as "1591537772865").

A HTTP GET to /api/edge/get.json can be used to get a JSON formatted dictionary containing the configuration (and the current SESSION_ID).

A HTTP GET to /api/edge/getcfg.json can be used to get a JSON formatted list stating which sections have been modified.

The /api/edge/data.json endpoint can query a variety of stats and data.


DHCP Leases

A HTTP GET to /api/edge/data.json?data=dhcp_leases can be used to get a JSON formatted list of DHCP leases:

{"success": "1", "output": {"dhcp-server-leases": {"LAN2": "", "LAN1": {"192.168.0.180": {"expiration": "2020/06/08 13:07:17", "pool": "LAN1", "mac": "xx:xx:xx:xx:xx:xx", "client-hostname": "Versa"}, "192.168.0.165": {"expiration": "2020/06/08 08:42:42", "pool": "LAN1", "mac": "xx:xx:xx:xx:xx:xx", "client-hostname": ""}, "192.168.0.104": {"expiration": "2020/06/07 16:19:20", "pool": "LAN1", "mac": "xx:xx:xx:xx:xx:xx", "client-hostname": "andys-6s"}}}}}


DHCP Stats

A HTTP GET to /api/edge/data.json?data=dhcp_stats can be used to get a JSON formatted list of DHCP stats:

{"success": "1", "output": {"dhcp-server-stats": {"LAN2": {"pool_size": "253", "leased": "0", "available": "253"}, "LAN1": {"pool_size": "253", "leased": "3", "available": "250"}}}}


System Information

A HTTP GET to /api/edge/data.json?data=sys_info obtains basic system information:

{"success": "1", "output": {"sw_ver": "EdgeRouter.ER-e300.v2.0.9-beta.3.5296219.200507.1538", "unms": {"daemon": "Not running", "status": "", "last": ""}, "fw-latest": {"version": "v2.0.8-hotfix.1", "url": "https://fw-download.ubnt.com/data/e300/669e-edgerouter-2.0.8-hotfix.1-752ed9f0476a4cb3adcce84ec537b228.tar", "md5": "d4b30e3821621f16f6e960d753eaf073", "state": "up-to-date"}}}


Routes

A HTTP GET to /api/edge/data.json?data=routes obtains route information:

{"success": "1", "output": [{"pfx": "0.0.0.0/0", "nh": [{"t": "S>*", "metric": "210/0", "via": "xxx.xxx.xxx.xxx", "intf": "eth0"}]}, {"pfx": "xxx.xxx.xxx.xxx/21", "nh": [{"t": "C>*", "intf": "eth0"}]}, {"pfx": "127.0.0.0/8", "nh": [{"t": "C>*", "intf": "lo"}]}, {"pfx": "192.168.0.0/24", "nh": [{"t": "C>*", "intf": "eth1"}]}]}


Default Configuration Status

A HTTP GET to /api/edge/data.json?data=default_config obtains information on whether the device is operating with no user supplied configuration:

{"success": "1", "output": {"is_default": "0"}}


Download Configuration

To download the configuration send a HTTP GET to /api/edge/config/save.json:

{"CONFIG": {"success": "1", "path": "/tmp/sysd-save.ycYPpL"}, "success": true}

and then make a request to /files/config/. The file will be deleted once the request has been made.


Reboot

The device can be rebooted by sending a HTTP POST to /api/edge/operation/reboot.json

Reset Default Configuration

The device configuration can be reset by sending a HTTP POST to /api/edge/operation/reset-default-config.json

Shutdown

The device can be shutdown by sending a HTTP POST to /api/edge/operation/shutdown.json

Support File

A support file can be generated by sending a HTTP POST to /api/edge/operation/get-support-file.json

Renew DHCP

The DHCP lease can be renewed by sending a HTTP POST to /api/edge/operation/renew-dhcp.json

Release DHCP

The DHCP lease can be released by sending a HTTP POST to /api/edge/operation/release-dhcp.json

Clear Traffic Analysis

The Traffic Analysis data can be cleared by sending a HTTP POST to /api/edge/operation/clear-traffic-analysis.json

Check For Firmware Updates

A check for firmware updates can be performed by sending a HTTP POST to /api/edge/operation/refresh-fw-latest-status.json


The /api/edge/batch.json endpoint allows you to make batch updates to the device's configuration.

POST /api/edge/batch.json

{
    "SET":{"system":{"host-name":"<hostname>"},"service":{"unms":{"disable":null}}},
    "GET":{"system":null,"service":null}
}

Response:

{
    "SET": {"failure": "0", "success": "1"}, 
    "SESSION_ID": "session_id", 
    "GET": {
        "system": { system as json }, 
        "service": { service as json }, 
    "COMMIT": {"failure": "0", "success": "1"}, 
    "SAVE": {"success": "1"}, 
    "success": true
}

The CLI can be accessed from wss://host-or-ip/ws/cli. The data sent to the WebSocket will be as you would type on CLI and the received data is just the response raw.

You can get streaming statistical data from the endpoint wss://host-or-ip/ws/stats. The data from the WebSocket is framed oddly, it's actually a streaming protocol that has been sent and received over WebSocket. The data will not arrive like you might expect. You *MUST* reassemble the web socket data fragments since the frames may not align with data boundaries. Commands must be sent with a valid SESSION_ID.

The format of data to and from the WebSocket stream is "LENGTH\nJSON_PAYLOAD". Failure of sending properly formed messages to start the streaming will result in no messages from server aka "dead air".

When the SESSION_ID times out the WebSocket will abruptly close so it's recommended to refresh it occasionally.

249
{"SUBSCRIBE":[{"name":"export"},{"name":"discover"},{"name":"pon-stats"},{"name":"interfaces"},{"name":"system-stats"},{"name":"num-routes"},{"name":"config-change"},{"name":"users"}],"UNSUBSCRIBE":[],"SESSION_ID":"b5d5cfdb326c484abb00ca0d9effffff"}

Return values from the stream follow a similar format.

104
{
    "system-stats":
    {
        "cpu": "10",
        "uptime": "57864",
        "mem": "60"
    }
}

The webUI sends a non-standard ping every 30 seconds which consists of the following string with NO length prefix

{"CLIENT_PING"}

Each one of these subscriptions will output data with a headers indicating what datapoint they are returning.

  • system-stats: Returns cpu, memory and uptime
    {'system-stats': {'cpu': '35', 'mem': '22', 'uptime': '3321154'}}
    {'system-stats': {'cpu': '21', 'mem': '22', 'uptime': '3321157'}}
  • num-routes: Returns information about the number of active routes, use the json endpoint to fetch detailed routing information
    {'num-routes': {'connected': '5', 'static': '1', 'total': '6'}}
  • config-change: Returns only when the config has changed as an indication you need to reload
    {'config-change': {'commit': 'started'}}
    {'config-change': {'commit': 'ended'}}
  • users: Lists the users logged into the EdgeOS device including ssh, web, and vpn
  • interfaces: Shows per-interface details about the device
  • discover: Results from any devices discovered via ubnt protocols
  • export: Traffic Analysis (aka DPI) information
  • lldp-detail: Information about LLDP connected neightbors
  • udapi-statistics: System information formatted for udapi, odd dialect

Each one of these endpoints just dumps data with the dict

{'': '<line of text>\n' }
  • log-feed: Basically tail -f /var/log/messages
  • fw-stats: Returns per-rule firewall stats
  • pf-stats: Not sure
  • nat-stats: Returns per-rule nat stats

Example fw-stats.

{'': 'MGT_IN 10 11604461 1380173884 ACCEPT ""\n'}
{'': 'MGT_IN 20 0 0 DROP "drop direct stun"\n'}
{'': 'MGT_IN 30 24 1152 ACCEPT "stun"\n'}
{'': 'MGT_IN 10000 8417 670074 DROP "DEFAULT ACTION"\n\n'}
{'': 'WAN_IN 10 747540714 999952823643 ACCEPT "Allow established/related"\n'}
{'': 'WAN_IN 20 0 0 DROP "Drop invalid state"\n'}
{'': 'WAN_IN 30 1095 52610 DROP "block ET"\n'}
{'': 'WAN_IN 40 0 0 DROP "block TOR"\n'}
{'': 'WAN_IN 50 0 0 DROP "block EDROP"\n'}
{'': 'WAN_IN 60 0 0 DROP "block China" DISABLED\n'}
{'': 'WAN_IN 70 92712 5078903 ACCEPT "server - web ports - tcp"\n'}
{'': 'WAN_IN 80 65556 3923195 ACCEPT "server - ssh"\n'}
{'': 'WAN_IN 90 877 52516 ACCEPT "server - gitlab ssh"\n'}
{'': 'WAN_IN 100 142 33791 ACCEPT "server - mosh"\n'}
{'': 'WAN_IN 110 3926 143574 ACCEPT "server - unifi stun"\n'}
{'': 'WAN_IN 10000 259 136357 DROP "DEFAULT ACTION"\n\n'}
{'': 'WAN_LOCAL 10 55434 36097276 ACCEPT "Allow established/related"\n'}
{'': 'WAN_LOCAL 20 87599 17248696 DROP "Drop invalid state"\n'}
{'': 'WAN_LOCAL 61 41787 1761510 DROP "block ET"\n'}
{'': 'WAN_LOCAL 62 0 0 DROP "block TOR"\n'}
{'': 'WAN_LOCAL 63 100 4160 DROP "block EDROP"\n'}
{'': 'WAN_LOCAL 64 0 0 DROP "block China" DISABLED\n'}
{'': 'WAN_LOCAL 65 21894 1372976 ACCEPT "ICMP"\n'}
{'': 'WAN_LOCAL 10000 241941 37301536 DROP "DEFAULT ACTION"\n\n'}

Each one of these endpoints performs a toolbox action. These are subscribed to in the same way as the JSON subscriptions above but additional parameters must be specified:

Ping ("ping-feed")

163
{"SUBSCRIBE":[{"name":"ping-feed","sub_id":"ping1","target":"192.168.0.1","count":"1","size":""}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}

with the response being pretty similar to a raw feed:

76
{
    "ping1": "PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.\n\n"
}

Traceroute ("traceroute-feed")

165
{"SUBSCRIBE":[{"name":"traceroute-feed","sub_id":"trace2","target":"192.168.0.254","resolve":true}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}

with the response being pretty similar to a raw feed:

98
{
    "trace6": "traceroute to 192.168.0.254 (192.168.0.254), 30 hops max, 38 byte packets\n 1"
}

Packet Capture ("packets-feed")

224
{"SUBSCRIBE":[{"name":"packets-feed","sub_id":"packets4","interface":"1","pkt_count":"1","resolve":true,"f_proto":"","f_address":"","f_port":"","f_neg":true}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}

Bandwidth Test ("bwtest-feed")

Client:

150
{"SUBSCRIBE":[{"name":"bwtest-feed","sub_id":"bandwidth5","server":"192.168.0.253"}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}

Server:

144
{"SUBSCRIBE":[{"name":"bwtest-feed","sub_id":"bandwidth5","server-mode":true}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}

There is also the following endpoints that not much is known about:

  • onu-list: Lists Optical Network Unit devices.
  • pon-stats: Lists Passive Optical Network stats.
  • nni-stats: Lists Network to Network Interface stats.

There are a few developers who have worked on creating unofficial APIs:


Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /home/nevyxvrt/ubntwiki.com/lib/plugins/authplain/auth.php on line 428
dokuwiki\Exception\FatalException: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes)

dokuwiki\Exception\FatalException: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes)

An unforeseen error has occured. This is most likely a bug somewhere. It might be a problem in the authplain plugin.

More info has been written to the DokuWiki error log.