System Settings & Terminalv7.0.20
Read and write the appliance’s own configuration — network interfaces, hostname and DNS, local networks, clock, SMTP relay, license, HTTPS certificate, protocol labels, downloadables, and daemon services — plus a few diagnostic actions and the in-browser terminal proxy.
These endpoints configure the appliance itself: its network interfaces, hostname and the local DNS map, the monitored local networks (the ranges the discovery scanner sweeps), the system clock and time zone, the SMTP relay used to send alert email, the product license, the HTTPS certificate, the custom-protocol port labels, the downloadable satellite installers, and the running daemon services. It also exposes a few diagnostic actions — read an appliance health snapshot, restart the monitoring stack, pull a log archive, and create or download a full backup.
These endpoints belong to the system functional area; an MCP or OAuth token needs the mcp:system scope. Most endpoints additionally require the calling user to hold the system permission. Four certificate endpoints are super-admin-only and require the sa permission instead — this is called out on each. These are appliance-wide settings with no tag anchor, so tag-scoping does not apply here; every system-permission user sees the same configuration.
Most endpoints in this chapter predate the modern REST conventions and return a custom envelope. Success is typically {"status": 201, "hasError": false, ...} — note that the numeric status is sent as a field in an HTTP 200 response, not as the HTTP status code. Failure is usually {"status": false, "hasError": true, "message": "..."}, also returned with HTTP 200. Do not key automation off the HTTP status alone for these endpoints; read the hasError field. The certificate and license endpoints are the exception — they return real HTTP 4xx/5xx codes, noted per endpoint.
Services
Read the running service table and control individual daemons or the whole monitoring stack.
List services
GET/api/manageNetmonServicessystem
Returns the current state of every monitored service as reported by the service controller. Use it to render a services dashboard or to confirm a daemon is running before acting on it.
Response 200
{
"status": 201,
"hasError": false,
"data": {
"services": [
{ "name": "snmpmond", "status": "running", "pid": "4123" }
]
}
}
The per-service object keys are whatever attributes the service controller reports for each entry. If the controller cannot be reached the response is {"status": false, "hasError": true, "message": "Cannot communicate with service controller."}.
Start, stop, or restart a service
POST/api/procmonsystem
Sends a control signal to a single daemon through the process supervisor.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
service | string | yes | Daemon name, e.g. snmpmond. |
action | string | yes | Supervisor verb, e.g. start, stop, restart, reload. |
Response 200
{ "status": 201, "hasError": false, "message": "OK" }
Errors
| Status | Body | When |
|---|---|---|
400 | {"hasError":true,"message":"Service and action are required."} | Missing service or action. |
500 | {"status":500,"hasError":true,"message":"..."} | Supervisor communication failed. |
Stopping or restarting a daemon interrupts whatever monitoring it performs for the duration of the action.
Example
curl -sS -X POST https://APPLIANCE/api/procmon \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"service":"snmpmond","action":"restart"}'
Restart the monitoring stack
POST/api/restartNetmonsystem
Restarts the entire Netmon service (every daemon at once). There is no request body.
Response 200
{ "status": 200, "hasError": false, "message": "Netmon restarted successfully" }
Errors
| Status | Body | When |
|---|---|---|
500 | {"hasError":true,"message":"Failed to restart netmon"} | The restart command exited non-zero. |
This bounces the whole monitoring stack. All polling, capture, and alerting pauses briefly while the daemons come back up.
Network interfaces
Read and write the appliance’s local network-interface configuration. Writes rewrite the per-interface config files and restart networking.
Get network interfaces
POST/api/getNetworkInfosystem
Lists every non-loopback interface with its live addresses and its persisted configuration (addressing mode, gateway, DNS servers, and whether the interface is assigned to packet capture or to the intrusion-detection engine). Despite the POST verb it takes no request body.
Response 200
{
"status": 201,
"hasError": false,
"interfaces": [
{
"name": "eth0",
"ipv4": [ { "address": "10.0.0.5", "netmask": "255.255.255.0" } ],
"ipv6": [],
"online": true,
"config": {
"allow-hotplug": false,
"auto": true,
"type": "static",
"address": "10.0.0.5",
"netmask": "255.255.255.0",
"gateway": "10.0.0.1",
"dns-nameservers": ["10.0.0.1", "1.1.1.1"],
"use_sniffer": true,
"use_suricata": false
}
}
]
}
An interface with no saved config file reports config.type as "unconfigured" with empty addressing fields. On failure the response is {"status": false, "hasError": true, "message": "..."}.
Set network interfaces
POST/api/setNetworkInfosystem
Rewrites the configuration for one or more interfaces and restarts networking. Submit the same shape returned by getNetworkInfo — an interfaces array, each element carrying a name and a config object.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
interfaces | array | yes | Each element is an interface object. |
interfaces[].name | string | yes | Interface name (max 15 chars; letters, digits, _ . -). |
interfaces[].config.type | string | yes | One of static, dhcp, manual, unconfigured. |
interfaces[].config.address | string | for static | IPv4 or IPv4/CIDR. |
interfaces[].config.netmask | string | for static | Netmask. |
interfaces[].config.gateway | string | no | IPv4 gateway. |
interfaces[].config.dns-nameservers | array | no | List of IP literals. |
interfaces[].config.allow-hotplug | boolean | no | Add an allow-hotplug directive. |
interfaces[].config.use_sniffer | boolean | no | Assign the interface to packet capture. |
interfaces[].config.use_suricata | boolean | no | Assign the interface to the IDS engine. |
All operator-supplied fields are validated against strict patterns; an invalid value rejects the whole request (no partial writes). Addressing values must be real IP literals.
Response 200
{ "status": 201, "hasError": false }
On error (validation failure or a failed systemctl restart networking) the response is {"status": false, "hasError": true, "message": "..."}.
Saving interface configuration restarts host networking. If you apply a bad address you can lose connectivity to the appliance over that interface.
Hostname & DNS
Set the appliance hostname and maintain the local hostname-to-IP map used to resolve names that aren’t in DNS.
Get hostname
GET/api/getHostnamesystem
Returns the appliance’s current hostname.
Response 200
{ "status": 200, "hasError": false, "hostname": "netmon-prod" }
Set hostname
POST/api/setHostnamesystem
Changes the appliance hostname via hostnamectl.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
hostname | string | yes | Max 255. Must be a valid DNS hostname/label. |
Response 200
{ "status": 201, "message": "Hostname successfully updated", "hostname": "netmon-prod" }
Errors
| Status | Body | When |
|---|---|---|
422 | {"message":...,"errors":{...}} | Validation failed (Laravel validator). |
200 | {"status":false,"hasError":true,"message":"..."} | hostnamectl failed. |
List host map entries
POST/api/getHostnamessystem
Returns the local hostname database (static name-to-IP records), paginated.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
page | integer | no | Page number. |
limit | integer | no | Rows per page. |
The body is a JSON-encoded paginated result of host rows (id, ip, hostname, host_name_type, node_type, timestamp). On error the {"status": false, "hasError": true, "message": "..."} envelope is returned.
Create a host map entry
POST/api/createHostnamesystem
Adds a static hostname record. The combination of ip + hostname + host_name_type + node_type is checked for duplicates first.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
ip | string | yes | IP address. |
hostname | string | yes | Name to map. |
host_name_type | string | yes | Record type/source. |
node_type | string | yes | Node classification. |
Response 200
{ "status": 201, "hasError": false, "message": "..." }
If a matching record already exists the response is {"status": false, "hasError": true, "message": "..."} (already exists).
Update a host map entry
POST/api/updateHostnamesystem
Updates an existing host record by id.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | yes | Host record id. |
ip | string | yes | IP address. |
hostname | string | yes | Name to map. |
host_name_type | string | yes | Record type/source. |
node_type | string | yes | Node classification. |
Response 200
{ "status": 201, "hasError": false, "message": "..." }
Delete a host map entry
POST/api/deleteHostsystem
Removes a host record by id.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | yes | Host record id (must be > 0). |
Response 200
{ "status": 201, "hasError": false, "message": "..." }
A non-positive id returns {"message": "..."} (invalid identifier); a missing record returns {"hasError": true, "message": "..."}.
Permanently deletes the host record.
Local networks
Local networks (“localnets”) are the IP ranges the discovery scanner sweeps for new hosts. Each carries a label, a network/broadcast pair, a scan interval, and toggles for discovery and port scanning.
List local networks
GET/api/getLocalnetssystem
Returns every non-ephemeral local network with its settings, associated credential ids, and any attached legacy alerts.
Response 200
{
"data": [
{
"id": 7,
"label": "Office LAN",
"network": "10.0.0.0",
"broadcast": "10.0.0.255",
"interval": 3600,
"enable_discovery": true,
"enable_portscan": false,
"cred_ids": [3, 5],
"alerts": null,
"timestamp": 1718000000
}
]
}
If there are no rows the endpoint returns false. On error it returns the {"status": false, "hasError": true, "message": "..."} envelope.
Create or update local networks
POST/api/updateLocalnetsystem
Upserts one or more local networks in a single call. Each element with no id is created; each with an id is updated. Credential associations are replaced wholesale from cred_ids.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
data | array | yes | Non-empty array of localnet objects. |
data[].id | integer | no | Omit to create a new row. |
data[].label | string | yes | Display label. |
data[].network | string | yes | Valid IPv4 network address. |
data[].broadcast | string | yes | Valid IPv4 broadcast; must be >= network. |
data[].interval | integer | yes | Scan interval (seconds). |
data[].enable_discovery | boolean | yes | Enable host discovery. |
data[].enable_portscan | boolean | yes | Enable port scanning. |
data[].cred_ids | array | yes | Credential ids to associate (replaces existing). |
The subnet size (broadcast − network + 1) is capped at /16 (65,536 addresses); larger ranges must be split into multiple rows. One out-of-spec row rejects the whole batch.
Response 200
{ "status": 201, "hasError": false, "message": "OK" }
Errors
| Status | Body | When |
|---|---|---|
422 | {"status":false,"hasError":true,"message":"network must be a valid IPv4 address"} | Invalid network. |
422 | {"status":false,"hasError":true,"message":"broadcast must be >= network"} | Broadcast below network. |
422 | {"status":false,"hasError":true,"message":"subnet size exceeds /16 (65536 addresses) — split into multiple localnets rows"} | Range too large. |
Reset discovery timestamp
POST/api/resetDiscoveryTssystem
Forces a full re-scan of one local network on the next discovery cycle by zeroing its last-scanned timestamp.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | yes | Local network id. |
Response 200
{ "status": 201, "hasError": false }
A missing id returns {"status": false, "hasError": true, "message": "Invalid request parameters"}.
Delete a local network
POST/api/deleteLocalnetsystem
Removes a local network by id.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | yes | Local network id (must be > 0). |
Response 200
{ "status": 201, "hasError": false, "message": "..." }
A non-positive id returns {"message": "..."} (invalid identifier); a missing record returns {"hasError": true, "message": "..."}.
Permanently deletes the local network and stops discovery against that range.
System time
Read the time configuration (time zone, NTP vs. manual mode, available zones) and set it.
Get time settings
GET/api/getTimeSettingssystem
Returns the current time zone, sync mode, configured NTP server (if any), the list of selectable time zones, and the appliance’s current Unix time.
Response 200
{
"status": 201,
"hasError": false,
"data": {
"tzs": ["Africa/Abidjan", "America/New_York", "..."],
"tz": "America/New_York",
"type": "ntp",
"ntpserver": "pool.ntp.org",
"time": 1718000000
}
}
type is ntp or manual. ntpserver is present only in NTP mode. On error the {"status": false, "hasError": true, "message": "..."} envelope is returned.
Set time settings
POST/api/setTimeSettingssystem
Sets the time zone and either enables NTP with a server list or sets the clock manually.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
type | string | yes | ntp or manual. |
tz | string | yes | Time zone (e.g. America/New_York). |
ntpserver | string | for ntp | Space-separated list of hostnames/IPs. |
manual | string | for manual | ISO-8601 timestamp to set the clock to. |
In NTP mode each server entry is validated as a hostname or IP literal. In manual mode NTP is disabled and the clock is set directly.
Response 200
{ "status": 201, "hasError": false, "message": "..." }
On any failure the {"status": false, "hasError": true, "message": "..."} envelope is returned.
SMTP / email
A single endpoint handles reading, writing, and testing the SMTP relay used to send alert email. The behavior is selected by the action field.
Read, set, or test SMTP settings
POST/api/smtpSettingssystem
One endpoint, three actions:
action: "get"— return the current SMTP configuration (with the password masked).action: "set"— persist new SMTP configuration.action: "test"— queue a test email to the calling user’s address.
Request body (get)
| Field | Type | Required | Notes |
|---|---|---|---|
action | string | yes | "get". |
Request body (set)
| Field | Type | Required | Notes |
|---|---|---|---|
action | string | yes | "set". |
sender | string | yes | “From” display name / address. |
email | string | yes | Sender email address. |
smtpserver | string | yes | SMTP server hostname. |
port | integer | yes | SMTP port. |
auth | boolean | yes | Whether the server requires authentication. |
usessl | boolean | yes | Use SSL/TLS. |
authname | string | no | Auth username. |
authpass | string | object | no | New password, or the encrypted-field sentinel to keep the existing one. |
Request body (test)
| Field | Type | Required | Notes |
|---|---|---|---|
action | string | yes | "test". |
Response 200 (get)
{
"status": 201,
"hasError": false,
"smtp": {
"sender": "Netmon Alerts",
"email": "alerts@example.com",
"server": "smtp.example.com",
"port": "587",
"auth": "1",
"usessl": "1",
"authname": "alerts@example.com",
"authpass": { "__encrypted__": true }
}
}
Response 200 (set / test)
{ "status": 201, "hasError": false, "smtp": "Success" }
For a test, smtp is a message such as "Test email queued (id: 42)". An unknown action, a missing mail daemon, or an encryption failure returns {"status": false, "hasError": true, "message": "..."}.
The SMTP authpass is stored encrypted and never returned in clear text. On get it is masked as {"__encrypted__": true}. On set, replay that exact sentinel (or send authpass empty/null) to keep the stored password unchanged; send a plaintext string only when you intend to set a new password.
Example (read SMTP settings)
curl -sS -X POST https://APPLIANCE/api/smtpSettings \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"action":"get"}'
Example (write SMTP settings)
curl -sS -X POST https://APPLIANCE/api/smtpSettings \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"action":"set","sender":"Netmon Alerts","email":"alerts@example.com",
"smtpserver":"smtp.example.com","port":587,"auth":true,"usessl":true,
"authname":"alerts@example.com","authpass":"s3cret"}'
Licensing
Read the product license and activate the appliance with a registration key.
Get license info
GET/api/getLicenseInfosystem
Returns the license record(s): company, license type, and the end-of-license / end-of-maintenance dates.
Response 200
{
"status": 201,
"hasError": false,
"data": [
{
"company_name": "Acme Corp",
"user_name": "admin",
"user_email": "admin@example.com",
"activation_key": "ABCDEF-012345-6789AB-CDEF01-234567-89ABCD",
"license_type": "perpetual",
"active": true,
"activation_time": 1700000000,
"end_of_license": 1800000000,
"end_of_maintenance": 1800000000
}
]
}
data is an empty array when the appliance is unlicensed. On error the response is {"status": false, "message": "..."}.
Example
curl -sS https://APPLIANCE/api/getLicenseInfo \
-H "Authorization: Bearer $TOKEN"
Validate / apply a registration key
POST/api/validateLicensesystem
Stores a new activation key and restarts the monitoring stack so the new license takes effect.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
registrationKey | string | yes | Six dash-separated groups of six hex characters, e.g. ABCDEF-012345-6789AB-CDEF01-234567-89ABCD. |
Response 200
{ "status": 201, "hasError": false, "message": { "activation_key": "ABCDEF-..." } }
Errors
| Status | Body | When |
|---|---|---|
422 | {"status":false,"hasError":true,"message":"..."} | Key fails the format regex. |
200 | {"status":false,"message":"..."} | Save failed. |
A successful call restarts the entire monitoring stack so the new license is picked up. Monitoring pauses briefly.
HTTPS certificate
The certificate endpoints manage the TLS certificate Apache serves the web UI and API over. All four require the sa (super-admin) permission, not the system permission used by the rest of these endpoints, and they return real HTTP status codes.
Get certificate info
GET/api/getCertificatesa
Permission sa (super-admin)
Returns parsed details of the installed certificate.
Response 200
{
"subject": { "CN": "netmon.example.com" },
"issuer": { "CN": "Let's Encrypt R3", "O": "Let's Encrypt" },
"validFrom": "2026-01-01 00:00:00",
"validTo": "2026-04-01 00:00:00"
}
Errors
| Status | Body | When |
|---|---|---|
404 | {"error":"Public key file not found"} | No certificate installed. |
400 | {"error":"Invalid public key"} | Stored file is not a valid key. |
500 | {"error":"Unable to ..."} | Certificate could not be read/parsed. |
Extract a certificate file
POST/api/extractCertificatesa
Permission sa (super-admin)
Parses an uploaded certificate file — a PEM (optionally with an encrypted key), a DER certificate, or a PKCS#12 (.pfx/.p12) bundle — and returns the extracted PEM certificate chain and private key for review before saving. Nothing is persisted. Send the file as multipart/form-data.
Request body (multipart/form-data)
| Field | Type | Required | Notes |
|---|---|---|---|
file | file | yes | The certificate file (max 512 KB). |
password | string | no | Passphrase for an encrypted key or PKCS#12 bundle (max 1024). |
Response 200
{
"status": 200,
"certificate": "-----BEGIN CERTIFICATE-----\n...",
"private_key": "-----BEGIN PRIVATE KEY-----\n..."
}
Errors
| Status | Body | When |
|---|---|---|
422 | {"status":422,"code":"invalid_request","message":"..."} | Missing/oversized file. |
400 | {"status":400,"code":"password_required","message":"..."} | File is protected; no password given. |
400 | {"status":400,"code":"bad_password","message":"..."} | Wrong password. |
400 | {"status":400,"code":"legacy_cipher","message":"..."} | PKCS#12 uses a legacy (RC2/3DES) cipher OpenSSL 3 cannot read. |
400 | {"status":400,"code":"unrecognized","message":"..."} | Not a recognized certificate file. |
Verify a certificate and key
POST/api/verifyCertificatesa
Permission sa (super-admin)
Validates that a certificate (or full chain) and a private key are well-formed and that they match — without saving anything.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
public | string | yes | PEM certificate (server cert first if a chain). |
private | string | yes | PEM private key (unencrypted). |
Response 200
{ "status": 200, "message": "ok" }
Errors
| Status | Body | When |
|---|---|---|
400 | {"status":400,"message":"Both public and private keys are required"} | Missing field. |
400 | {"status":400,"message":"The certificate is not a valid PEM X.509 certificate."} | Bad certificate. |
400 | {"status":400,"message":"Certificate block N in the chain could not be parsed."} | Truncated chain. |
400 | {"status":400,"message":"The private key is encrypted. ..."} | Encrypted key pasted. |
400 | {"status":400,"message":"Invalid private key."} | Bad key. |
400 | {"status":400,"message":"Certificate and private key do not match. ..."} | Mismatch. |
Save a certificate
POST/api/saveCertificatesa
Permission sa (super-admin)
Verifies the certificate and key (same checks as verifyCertificate) and, if they pass, writes them to disk so Apache serves them after its next restart.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
public | string | yes | PEM certificate / chain. |
private | string | yes | PEM private key (unencrypted). |
Response 201
{ "status": 201, "message": "ok" }
Errors
Returns the same 400 verification errors as verifyCertificate when the certificate/key fail validation.
This overwrites the appliance’s installed TLS certificate and private key. An invalid pair that somehow passes can break HTTPS access until corrected, so verify first.
Custom protocols
Custom protocols are operator-defined labels that name a port/protocol pair so traffic to that port is shown with a friendly name throughout the UI.
List custom protocols
POST/api/getProtocolssystem
Returns the protocol labels, paginated. Despite the POST verb this is a read.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
page | integer | no | Page number. |
limit | integer | no | Rows per page. |
The body is a JSON-encoded paginated result of protocol rows (id, port, protocol, name). On error the {"status": false, "hasError": true, "message": "..."} envelope is returned.
Get one custom protocol
POST/api/getProtocolsForSinglesystem
Fetches a single protocol label by id.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | yes | Protocol id. |
Response 200
{
"status": 201,
"hasError": false,
"data": { "id": 12, "port": 8443, "protocol": "tcp", "name": "Admin Console" }
}
A missing record returns {"status": false, "hasError": true, "message": "..."}.
Create a custom protocol
POST/api/createProtocolssystem
Adds a protocol label. The protocol + port + name combination is checked for duplicates first.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
port | integer | yes | Port number. |
protocol | string | yes | e.g. tcp, udp. |
name | string | yes | Display label. |
Response 200
{ "status": 201, "hasError": false, "message": "..." }
A duplicate returns {"status": false, "hasError": true, "message": "..."} (already exists).
Update a custom protocol
POST/api/updateProtocolsystem
Updates a protocol label by id.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | yes | Protocol id. |
port | integer | yes | Port number. |
protocol | string | yes | Protocol. |
name | string | yes | Display label. |
Response 200
{ "status": 201, "hasError": false, "message": "..." }
Delete a custom protocol
POST/api/deleteProtocolsystem
Removes a protocol label by id.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | yes | Protocol id (must be > 0). |
Response 200
{ "status": 201, "hasError": false, "message": "..." }
A non-positive id returns {"message": "..."} (invalid identifier); a missing record returns {"hasError": true, "message": "..."}.
Permanently deletes the protocol label.
Downloadables
The appliance bundles operator-facing satellite installers and reference documents (the Windows agent, the Wireshark plugin, the product guide, the API reference). These two endpoints list and stream them.
List downloadables
GET/api/downloadablessystem
Returns the catalog grouped by category, each with the files staged on the appliance.
Response 200
{
"categories": [
{
"key": "windows-agent",
"label": "Windows Agent",
"description": "Installer for the Netmon Windows agent.",
"files": [
{ "filename": "netmon-agent-installer-7.0.20-amd64.exe", "size": 5242880, "mtime": 1718000000 }
]
}
]
}
A category with nothing staged returns an empty files array.
Download a file
GET/api/downloadables/{category}/{filename}system
Streams one staged file as a binary download.
Path parameters
| Name | Type | Notes |
|---|---|---|
category | string | Catalog category key (e.g. windows-agent). |
filename | string | File name from the catalog. May include one subdirectory segment (<subdir>/<file>); path traversal is rejected. |
Response 200 — the file body, Content-Type: application/octet-stream, served as an attachment named after the file.
Errors
| Status | Body | When |
|---|---|---|
404 | {"status":false,"message":"File not found."} | Unknown category or file. |
Example
curl -sS https://APPLIANCE/api/downloadables/windows-agent/netmon-agent-installer-7.0.20-amd64.exe \
-H "Authorization: Bearer $TOKEN" -o netmon-agent.exe
System health
A read-only self-diagnostic snapshot of the appliance, plus the one repair it offers. These are the endpoints behind the Settings → System → System Health card.
Get the health snapshot
GET/api/system/healthsystem
Runs every appliance self-check and returns one snapshot. Unlike most endpoints in this chapter it uses a plain JSON envelope, not {"status":201,...}. The call never fails on a bad probe: a check that cannot be evaluated is reported with severity unknown rather than raising an error, and the whole snapshot is bounded by a short wall-clock budget so it stays fast on loaded hardware.
Checks are grouped into four groups — scheduler (Scheduled Maintenance), storage (Storage), alerts (Alert Delivery), and platform (Platform). Every check and group carries a severity from ok, warn, crit, unknown — a group takes the worst severity among its checks, and overall the worst among the groups.
Response 200
{
"overall": "warn",
"generated_at": "2026-08-10T14:02:11+00:00",
"groups": [
{
"id": "scheduler",
"label": "Scheduled Maintenance",
"severity": "warn",
"checks": [
{
"id": "cron.parked",
"label": "Scheduled jobs enabled",
"severity": "warn",
"summary": "3 of 11 scheduled jobs are disabled.",
"detail": "Disabled: rotate_syslog_partition, cleanup_db, cleanup_hosts_geoip",
"hint": "This is the signature of an interrupted package upgrade. …",
"action": "cron-reenable"
}
]
},
{
"id": "storage",
"label": "Storage",
"severity": "ok",
"checks": [
{
"id": "storage.backups",
"label": "Database backups",
"severity": "ok",
"summary": "Most recent backup is 2 days old.",
"link": { "kind": "anchor", "target": "nm-sys-card-backups" }
}
]
}
]
}
Check fields
| Field | Type | Notes |
|---|---|---|
id | string | Stable check identifier, e.g. cron.parked, storage.var_netmon. |
label | string | Human-readable check name. |
severity | string | ok, warn, crit, or unknown. |
summary | string | One-line result. |
detail | string | Optional. Supporting evidence (names, counts, sizes). |
hint | string | Optional. What the condition usually means and what to do. |
link | object | Optional. {"kind":"anchor"|"route","target":"..."} — the UI target that fixes it. |
action | string | Optional. A remediation this API offers; today the only value is cron-reenable. |
Example
curl -sS https://APPLIANCE/api/system/health \
-H "Authorization: Bearer $TOKEN"
Re-enable parked scheduled jobs
POST/api/system/health/cron-reenablesystem
Re-enables every disabled database scheduled job. An interrupted package upgrade can leave them all switched off, which stops partition rotation and every retention janitor. This is the remediation behind the cron-reenable action. Takes no request body, and is idempotent — a second call re-enables nothing and reports 0.
Response 200
{ "ok": true, "reenabled": 3 }
Example
curl -sS -X POST https://APPLIANCE/api/system/health/cron-reenable \
-H "Authorization: Bearer $TOKEN"
Diagnostics & logs
Pull a diagnostic log archive and manage full appliance backups.
Download log archive
GET/api/downloadLogssystem
Builds and streams a ZIP of every file under the appliance log directory. Useful when attaching diagnostics to a support ticket.
Response 200 — a ZIP file, Content-Type: application/zip, attachment named logs.zip.
Errors
| Status | Body | When |
|---|---|---|
500 | {"error":"Failed to create zip archive"} | The archive could not be created. |
Example
curl -sS https://APPLIANCE/api/downloadLogs \
-H "Authorization: Bearer $TOKEN" -o logs.zip
Create a full backup
POST/api/createFullBackupsystem
Dumps the database and the appliance configuration into a compressed archive in the backup directory. Guarded by an advisory lock so concurrent calls don’t collide.
Response 200
{ "status": 201, "hasError": false, "message": "Backup created successfully" }
If a backup is already running, or the database dump / archiving step fails, the response is {"hasError": true, "message": "..."}.
List backups
GET/api/backupssystem
Lists the backup archives on disk with their sizes and timestamps.
Response 200
{
"backups": [
{ "name": "bk-1718000000.tgz", "size": 10485760, "date": "2026-06-10 04:00:00" }
]
}
Download a backup
GET/api/backups/{filename}system
Streams one backup archive as a binary download.
Path parameters
| Name | Type | Notes |
|---|---|---|
filename | string | Backup file name from the list. |
Response 200 — the file body, Content-Type: application/octet-stream, served as an attachment named after the file.
Errors
| Status | Body | When |
|---|---|---|
403 | {"message":"PRIVATE_KEY download is restricted to the super-admin account.","hasError":true} | The reserved PRIVATE_KEY file is requested by a non-super-admin. |
200 | {"message":"Backup not found.","hasError":true} | File does not exist. |
The reserved PRIVATE_KEY backup (the appliance RSA private key) can only be downloaded by the super-admin account; all other backups are available to any system-permission user.
Delete a backup
DELETE/api/backups/{filename}system
Deletes a backup archive from disk.
Path parameters
| Name | Type | Notes |
|---|---|---|
filename | string | Backup file name. |
Response 200
{ "message": "Backup deleted successfully.", "hasError": false }
Errors
| Status | Body | When |
|---|---|---|
403 | {"message":"PRIVATE_KEY deletion is restricted to the super-admin account.","hasError":true} | The reserved PRIVATE_KEY file is targeted by a non-super-admin. |
200 | {"message":"Backup not found.","hasError":true} | File does not exist. |
Permanently deletes the backup archive. Deleting the reserved PRIVATE_KEY file is restricted to the super-admin account.
Alert templates
Read and edit the saved alert email templates (the per-alert-type message bodies). These are exposed here because they are configured from the system settings surface.
List alert templates
GET/api/getAlertTemplatessystem
Returns every alert type with its template fields.
Response 200
{
"status": 200,
"hasError": false,
"data": [
{ "id": 1, "name": "Device Down", "template_up": "...", "template_down": "..." }
]
}
Update an alert template field
POST/api/setAlertTemplatesystem
Updates a single template field on one alert type.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | yes | Alert type id. |
field | string | yes | Template field name (e.g. template_up). Must be an existing field on the row. |
value | string | yes | New field value. |
Response 200
{ "status": 201, "hasError": false, "data": { "id": 1, "template_up": "..." } }
An unknown alert type or an invalid field returns {"status": 400, "hasError": true, "message": "..."}.
System Terminal
The appliance ships an in-browser terminal — a web shell rendered inside the Netmon UI. The single endpoint below is the reverse proxy that bridges the browser to that on-box terminal service. It is not a REST endpoint and is not meant for scripting; it exists so the SPA’s Terminal pane can talk to the local terminal over the same authenticated origin as the rest of the UI.
This endpoint belongs to the system functional area (mcp:system scope), but unlike the rest of the API it authenticates against a browser web session, not a bearer token, and is gated by the system permission.
Proxy to the on-box terminal
ANY/api/term/proxy/{path?}system
Permission system
A transparent reverse proxy to the appliance’s local terminal service. Every HTTP method is accepted, and the optional trailing {path?} (including slashes) is forwarded verbatim along with the request method, headers, body, and query string. The upstream response — status, headers, and body — is returned unchanged. This carries the terminal’s HTML, JavaScript, and its interactive request/response traffic; the payloads are terminal protocol data, not JSON.
This route is opened by the web UI’s Terminal pane using your logged-in browser session (cookies), not a Passport bearer token. There is no stable JSON contract here — it is a passthrough to a separate terminal service. Drive it through the UI; do not target it from automation.
Path parameters
| Name | Type | Notes |
|---|---|---|
path | string | Optional. Forwarded verbatim to the upstream terminal service, slashes included. Defaults to the terminal root. |
Response
The upstream terminal service’s response, proxied through unchanged (status code, headers, and body). Content type is whatever the terminal emits (HTML, JavaScript, or terminal stream data) — not a JSON envelope.
Errors
| Status | Body | When |
|---|---|---|
502 | {"message":"Terminal unavailable"} | The upstream terminal service could not be reached. |