To access the API, you must first log in to the device and obtain an access token.
The account used also needs the API role assigned in the portal.
The token will be valid for the duration of the client login.
Alternatively, if the reqest is received on localhost (127.0.0.1) the token requirement will be ignored.
POST http://edgedevice:88/api/login
{
"Username": "username",
"Password": "password"
}
Status: 200 OK
{
"success": "Login successful",
"error": "",
"data": {
"AuthToken": "e0db2c0d81...d52cd273db",
"Username": "username"
}
}
Status: 401 Unauthorized
{
"success": "",
"error": "Invalid username or password",
"data": null
}
Use AuthToken
as a Bearer token in the header of API requests:
Authorization: Bearer e0db2c0d81...d52cd273db
Check if the token is valid, send a ping request to the API.
GET http://edgedevice:88/api/ping
Status: 200 OK
{
"success": "Success",
"error": "",
"data": null
}
Status: 401 Unauthorized
Unauthorized - Invalid token
POST http://edgedevice:88/api/edge/network/192.168.2.0-24
POST http://edgedevice:88/api/edge/network/192.168.2.0
Status: 200 OK
{
"success": "Network created",
"error": "",
"data": {
"Network": {
"Name": "192.168.2.0/24",
"IFname": "",
"HostIPMask": "",
"HostIP": "",
"HostMask": 0,
"NetIPMask": "192.168.2.0/24",
"NetIP": "192.168.2.0",
"NetMask": 24,
"IPint": 3232236032,
"LastScan": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
}
}
}
Manipulate networks registered on the device. Specify CIDR notation in URLs with a -
in place of a /
.
GET http://edgedevice:88/api/edge/network/192.168.2.0-24
GET http://edgedevice:88/api/edge/network/192.168.2.0
Status: 200 OK
{
"success": "Network found",
"error": "",
"data": {
"Network": {
"Name": "192.168.2.0/24",
"IFname": "",
"HostIPMask": "",
"HostIP": "",
"HostMask": 0,
"NetIPMask": "192.168.2.0/24",
"NetIP": "192.168.2.0",
"NetMask": 24,
"IPint": 3232236032,
"LastScan": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
}
}
}
GET http://edgedevice:88/api/edge/network
Status: 200 OK
{
"success": "Networks found",
"error": "",
"data": {
"Count": 2,
"Networks": [
{
"Name": "192.168.2.0/24",
"IFname": "",
"HostIPMask": "",
"HostIP": "",
"HostMask": 0,
"NetIPMask": "192.168.2.0/24",
"NetIP": "192.168.2.0",
"NetMask": 24,
"IPint": 3232236032,
"LastScan": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
...
]
}
}
Status: 404 Not Found
{
"success": "",
"error": "Network not found",
"data": null
}
DELETE http://edgedevice:88/api/edge/network/192.168.2.0-24
DELETE http://edgedevice:88/api/edge/network/192.168.2.0
Status: 200 OK
{
"success": "Network deleted",
"error": "",
"data": null
}
Status: 404 Not Found
{
"success": "",
"error": "Network not found",
"data": null
}
Create or update a device in the network.
POST http://edgedevice:88/api/edge/device/192.168.8.10
{
"Name": "Brother MFC",
"Hostname": "brother",
"IP": "192.168.8.10",
"Network": "192.168.8.0/24",
"Vendor": "Brother Industries Ltd."
}
Status: 200 OK
{
"success": "Network updated",
"error": "",
"data": {
"Device": {
"Name": "Brother MFC",
"Hostname": "brother",
"IP": "192.168.8.10",
"IPint": 3232237578,
"Network": "192.168.8.0/24",
"MAC": "",
"Vendor": "Brother Industries Ltd.",
"Notes": "",
"Ports": null,
"Forwards": null,
"ProxyMap": null,
"ForwardsMap": null,
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
}
}
}
Retrieve information about a specific device (node) in a network.
GET http://edgedevice:88/api/edge/device/192.168.8.10
Status: 200 OK
{
"success": "Device found",
"error": "",
"data": {
"Node": {
"Name": "brother",
"Hostname": "brother",
"IP": "192.168.8.10",
"IPint": 3232237578,
"Network": "192.168.8.0/24",
"MAC": "e8:65:38:28:7d:53",
"Vendor": "CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD.",
"Notes": "",
"Ports": null,
"Forwards": [
{
"Name": "Admin UI",
"Nodename": "",
"IP": "192.168.8.10",
"IPint": 3232237578,
"PortNum": 443,
"Protocol": "tcp",
"Method": "Forward",
"Service": "",
"SourceIP": "0.0.0.0",
"SourcePort": 10000,
"OpenAs": "https",
"Command": "https://device.account.2ho.ca:10000",
"Enabled": true,
"Updated": "0001-01-01T00:00:00Z"
}
],
"ProxyMap": null,
"ForwardsMap": null,
"Created": "0001-01-01T00:00:00Z",
"Updated": "2024-12-11T10:55:33.768678777-05:00"
}
}
}
Retrieve a list of all devices in the network. Specify the network CIDR in the URL. If the network is not specified, all devices are returned. Use a -
in place of a /
in the CIDR notation.
GET http://edgedevice:88/api/edge/devices
GET http://edgedevice:88/api/edge/devices/192.168.8.0-24
Status: 200 OK
{
"success": "Devices found",
"error": "",
"data": {
"Count": 19,
"Network": [
{
"Name": "unifi",
"Hostname": "unifi",
"IP": "192.168.8.1",
"IPint": 3232237569,
"Network": "192.168.8.0/24",
"MAC": "0e:ea:14:4d:1a:cc",
"Vendor": "Unknown Vendor",
"Notes": "",
"Ports": null,
"Forwards": [...],
"ProxyMap": null,
"ForwardsMap": null,
"Created": "0001-01-01T00:00:00Z",
"Updated": "2024-12-13T14:18:11.800682015-05:00"
},
...
]
}
}
Delete a device from the network.
DELETE http://edgedevice:88/api/edge/device/192.168.8.10
Status: 200 OK
{
"success": "Device deleted",
"error": "",
"data": null
}
Creates a new forwarding rule or updates an existing one if the port already exists. If the device does not exist, it is automatically created.
POST http://edgedevice:88/api/edge/forward
{
"Name": "Admin UI",
"IP": "192.168.8.10",
"PortNum": 80,
"Protocol": "tcp",
"OpenAs": "http",
"Enabled": true
}
{
"success": "Forward created successfully",
"error": "",
"data": {
"Forward": {
"Name": "Admin UI",
"Nodename": "",
"IP": "192.168.8.10",
"IPint": 3232237578,
"PortNum": 80,
"Protocol": "tcp",
"Method": "Forward",
"Service": "",
"SourceIP": "0.0.0.0",
"SourcePort": 10000,
"OpenAs": "http",
"Command": "",
"Enabled": true,
"Updated": "0001-01-01T00:00:00Z"
}
}
}
Read a specified forwarding rule by port.
GET http://edgedevice:88/api/edge/forward/192.168.8.10/443
Status: 200 OK
{
"success": "Forward found",
"error": "",
"data": {
"Forward": {
"Name": "Admin UI",
"Nodename": "",
"IP": "192.168.8.10",
"IPint": 3232237578,
"PortNum": 80,
"Protocol": "tcp",
"Method": "Forward",
"Service": "",
"SourceIP": "0.0.0.0",
"SourcePort": 10000,
"OpenAs": "http",
"Command": "",
"Enabled": true,
"Updated": "0001-01-01T00:00:00Z"
}
}
}
Read all the forwarded ports from a device.
GET http://edgedevice:88/api/edge/forward/192.168.8.10
Status: 200 OK
{
"success": "Forwards found",
"error": "",
"data": {
"Forwards": [
{
"Name": "Admin UI",
"Nodename": "",
"IP": "192.168.8.10",
"IPint": 3232237578,
"PortNum": 80,
"Protocol": "tcp",
"Method": "Forward",
"Service": "",
"SourceIP": "0.0.0.0",
"SourcePort": 10000,
"OpenAs": "http",
"Command": "",
"Enabled": true,
"Updated": "0001-01-01T00:00:00Z"
},
...
]
}
}
Delete a forwarding rule from the device.
DELETE http://edgedevice:88/api/edge/forward/192.168.8.10/80
Status: 200 OK
{
"success": true,
"error": "",
"message": "Forward deleted successfully"
}
Start a network scan.
Request
GET http://edgedevice:88/api/edge/scan/start
Response
Status: 200 OK
{
"success": "Continuous scanning started",
"error": "",
"data": null
}
Stop a network scan.
Request
GET http://edgedevice:88/api/edge/scan/stop
Response
Status: 200 OK
{
"success": "Scanning stopped",
"error": "",
"data": null
}
Scan a network once. i.e. Not continuously.
Request
GET http://edgedevice:88/api/edge/scan/once
Response
Status: 200 OK
{
"success": "Single scan initiated",
"error": "",
"data": null
}
Scan a network for ONVIF devices using the ONVIF protocol only.
GET http://edgedevice:88/api/edge/scan/onvif
Status: 200 OK
{
"success": "ONVIF scan initiated",
"error": "",
"data": null
}
Scan a single host for open ports.
GET http://edgedevice:88/api/edge/scan/192.168.8.1
Status: 200 OK
{
"success": "Host scan initiated",
"error": "",
"data": null
}
Get the configuration of the Netrinos Edge Services
GET http://edgedevice:88/api/edge/config
Status: 200 OK
{
"success": "Edge config found",
"error": "",
"data": {
"Config": {
"LocalNet": {
"Hostname": "",
"IsStatic": false,
"LocalIPn": "",
"Gateway": "",
"DNS": ""
},
"Server": {
"IP": "0.0.0.0",
"Port": "88"
},
"Proxy": {
"IP": "0.0.0.0",
"ServeIP": "192.168.8.20",
"PortStart": 10000,
"PortRange": 1000
},
"Socks": {
"IP": "0.0.0.0",
"Port": 1080
},
"Scan": {
"Auto": false,
"Interval": 0,
"Workers": 0,
"Continuous": false,
"NoScanSubnets": "",
"OnvifScan": false
},
"Monitor": {
"Auto": false,
"Target": ""
}
}
}
}
Get the scan configuration of the Netrinos Edge Services
GET http://edgedevice:88/api/edge/config/config
Status: 200 OK
{
"success": "Scanner config found",
"error": "",
"data": {
"Scan": {
"Auto": false,
"Interval": 0,
"Workers": 0,
"Continuous": false,
"NoScanSubnets": "",
"OnvifScan": false
}
}
}
Set parameters of the scan configuration
POST http://edgedevice:88/api/edge/scan/config
{
"Auto": false
}
Status: 200 OK
{
"success": "Scan configuration updated",
"error": "",
"data": {
"Scanner": {
"Auto": false,
"Interval": 0,
"Workers": 0,
"Continuous": false,
"NoScanSubnets": "",
"OnvifScan": false
}
}
}
POST http://edgedevice:88/api/edge/config
{
"Continuous": true
}
Status: 200 OK
{
"success": "Scan configuration updated",
"error": "",
"data": {
"Scanner": {
"Auto": false,
"Interval": 0,
"Workers": 0,
"Continuous": true,
"NoScanSubnets": "",
"OnvifScan": false
}
}
}
These examples are far from optimal. They are meant as simplified examples of how to use the API.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
const apiURL = "http://localhost:88" // API URL
var client *http.Client // Global HTTP client
func main() {
client = &http.Client{}
// Previously authenticated token. May not be current.
token := "1234abcdthismayormaynotbeavalidtokenab6abcd1234"
// Login credentials - be sure the account has the API role in the admin portal
credentials := map[string]string{
"Username": "username",
"Password": "password",
}
// Check if the token is valid
req, _ := http.NewRequest("GET", apiURL+"/api/ping", nil)
req.Header.Set("Authorization", "Bearer "+token)
tokenResp, _ := client.Do(req)
if tokenResp.StatusCode == http.StatusOK {
fmt.Printf("Token is valid.")
} else {
fmt.Println("Token is invalid. Logging in to get a new token.")
// Login to get a new token
jsonData, _ := json.Marshal(credentials)
resp, _ := http.Post(apiURL+"/api/login", "application/json", bytes.NewBuffer(jsonData))
body, _ := io.ReadAll(resp.Body)
defer resp.Body.Close()
// Check that the login was successful
if resp.StatusCode != http.StatusOK {
fmt.Printf("Login failed. Status code: %d\n", resp.StatusCode)
return
}
var loginResp map[string]interface{}
json.Unmarshal(body, &loginResp)
// Get the auth token from the nested response structure
loginData := loginResp["data"].(map[string]interface{})
token = loginData["AuthToken"].(string)
fmt.Printf("Received token: %s\n", token)
}
// Create forward rule
IP := "192.168.8.254"
forwardRule := map[string]interface{}{
"Name": "RTSP Stream",
"IP": IP,
"PortNum": 554,
"Protocol": "tcp",
"OpenAs": "rtsp",
"Enabled": true,
}
ruleJSON, _ := json.Marshal(forwardRule)
req, _ = http.NewRequest("POST", apiURL+"/api/edge/forward/"+IP, bytes.NewBuffer(ruleJSON))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, _ := client.Do(req)
body, _ := io.ReadAll(resp.Body)
defer resp.Body.Close()
fmt.Printf("Forward rule response: %s\n", string(body))
}
Token is invalid. Logging in to get a new token.
Received token: 1fbcc8daf8d212ca91285a7ee4772b6208b3cb6d56a14e682847616aaab6490a
Forward rule response: {
"success": "Forward created successfully",
"error": "",
"data": {
"Forward": {
"Name": "RTSP Stream",
"Nodename": "unknown",
"IP": "192.168.8.254",
"IPint": 3232237822,
"PortNum": 554,
"Protocol": "tcp",
"Method": "Forward",
"Service": "rtsp",
"SourceIP": "0.0.0.0",
"SourcePort": 10000,
"OpenAs": "rtsp",
"Command": "",
"Enabled": true,
"Updated": "2024-12-16T19:36:06.642964426-05:00"
}
}
}
Scan the network for ONVIF devices and list the results
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
const apiURL = "http://edgedevice:88"
func main() {
// Known token from previous authentication
token := "1234abcdthismayormaynotbeavalidtokenab6abcd1234"
client := &http.Client{}
// Start ONVIF scan
req, _ := http.NewRequest("GET", apiURL+"/api/edge/scan/onvif", nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, _ := client.Do(req)
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
fmt.Printf("Scan initiated: %s\n", string(body))
// Poll scan status until complete
for {
req, _ = http.NewRequest("GET", apiURL+"/api/edge/scan", nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, _ = client.Do(req)
body, _ = io.ReadAll(resp.Body)
resp.Body.Close()
var respData map[string]interface{}
json.Unmarshal(body, &respData)
data := respData["data"].(map[string]interface{})
if !data["running"].(bool) {
break
}
time.Sleep(3 * time.Second)
}
fmt.Println()
// Get discovered devices
req, _ = http.NewRequest("GET", apiURL+"/api/edge/devices", nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, _ = client.Do(req)
body, _ = io.ReadAll(resp.Body)
resp.Body.Close()
var result map[string]interface{}
json.Unmarshal(body, &result)
fmt.Println("\nDiscovered devices:")
devices := result["data"].(map[string]interface{})["Network"].([]interface{})
for _, device := range devices {
dev := device.(map[string]interface{})
fmt.Printf("Name: %s\nIP: %s\nVendor: %s\n\n",
dev["Name"],
dev["IP"],
dev["Vendor"])
}
}
Scan initiated: {
"success": "Onvif scan initiated",
"error": "",
"data": null
}
Discovered devices:
Name: unknown
IP: 192.168.8.254
Vendor: Speco Technologies