Super-Adminv7.0.20
The most privileged administrative surfaces of the appliance — directory (LDAP / Active Directory) integration, the out-of-band operating-system upgrade flow, and the approval queue for dynamically-registered OAuth clients.
Nothing on this page is routine: wiring the appliance to a directory changes who can log in, the OS-upgrade endpoints hand the machine to an out-of-band assistant, and the client-approval queue decides which self-registered OAuth clients may complete an authorization flow.
These endpoints belong to the system functional area; an MCP or OAuth token needs the mcp:system scope, and the calling user needs the permission shown on each endpoint. Most endpoints here require permission:sa (super-admin); the OAuth client-approval endpoints require the broader permission:system.
Two cross-cutting points apply to the whole chapter:
- Response envelope. The LDAP endpoints wrap their payload in a
{status, hasError, ...}object, wherestatusis201on success andfalseon error (it is a body field, not the HTTP code, which stays200). The OS-upgrade and OAuth-client endpoints return bare JSON objects instead. Each endpoint shows its real shape. - Secrets are never echoed. The LDAP bind password is write-only — it is accepted on save but never returned on read, and the OS-upgrade one-shot token is rendered exactly once by the caller and never persisted.
LDAP / Active Directory
These endpoints configure directory-backed authentication: the bind connection to your LDAP or Active Directory server, a connection test that can also discover groups, the mapping of directory groups to appliance permissions and tag restrictions, and a manual user-sync.
The bind password is the one encrypted field in this section — see the note on Save LDAP configuration.
Get LDAP configuration
GET/api/ldap/configsa
Returns the saved LDAP configuration, or null when nothing has been saved yet. The bind password is never included in the response.
Response 200
{
"status": 201,
"hasError": false,
"config": {
"enabled": true,
"host": "dc01.example.com",
"port": 636,
"use_ssl": true,
"use_tls": false,
"verify_tls": false,
"base_dn": "dc=example,dc=com",
"bind_dn": "cn=svc-netmon,ou=service,dc=example,dc=com",
"directory_type": "active_directory",
"expand_nested_groups": true
}
}
Example
curl -sS https://APPLIANCE/api/ldap/config \
-H "Authorization: Bearer $TOKEN"
Save LDAP configuration
POST/api/ldap/configsa
Creates or updates the LDAP configuration (single-row upsert). When enabled is true, an encrypted transport is mandatory: at least one of use_ssl (LDAPS) or use_tls (STARTTLS) must be set, otherwise the save is refused.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
enabled | boolean | yes | Master on/off switch for LDAP auth. |
host | string | required if enabled | Server hostname. Max 255. |
port | integer | no | 1–65535. |
use_ssl | boolean | no | Use LDAPS. |
use_tls | boolean | no | Use STARTTLS. |
verify_tls | boolean | no | Verify the server’s TLS certificate. Governs trust only, not whether encryption is required. |
base_dn | string | required if enabled | Search base. Max 512. |
bind_dn | string | required if enabled | Service-account DN. Max 512. |
bind_password | string | no | Service-account password. Encrypted at rest; only written when present. |
search_filter | string | no | Max 512. |
username_attribute | string | no | Max 64. |
email_attribute | string | no | Max 64. |
first_name_attribute | string | no | Max 64. |
last_name_attribute | string | no | Max 64. |
directory_type | string | no | active_directory or openldap. |
timeout | integer | no | 1–60 seconds. |
fallback_to_local | boolean | no | Allow local-account login if LDAP is unreachable. |
auto_provision | boolean | no | Create local user rows for directory users on first login. |
expand_nested_groups | boolean | no | Resolve transitive (nested) group membership. |
bind_password is write-only. It is encrypted before storage and never returned by Get LDAP configuration. Omit it on a save to leave the stored password unchanged; only send it when you intend to set a new password.
Response 200
{ "status": 201, "hasError": false, "message": "LDAP configuration saved" }
Errors
| Status | Body | When |
|---|---|---|
200 | {"status":false,"hasError":true,"message":"Enable SSL (LDAPS) or STARTTLS — LDAP authentication requires an encrypted connection."} | enabled is true but neither use_ssl nor use_tls is set. |
Example
curl -sS -X POST https://APPLIANCE/api/ldap/config \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"enabled":true,"host":"dc01.example.com","port":636,"use_ssl":true,
"base_dn":"dc=example,dc=com","bind_dn":"cn=svc-netmon,dc=example,dc=com",
"bind_password":"s3cret","directory_type":"active_directory"}'
Test the LDAP connection
POST/api/ldap/testsa
Attempts a bind against the supplied settings and reports success plus the count and list of groups discovered. If bind_password is omitted, the stored password is reused — but only when host, port, and bind_dn exactly match the saved configuration; testing any other target requires an explicit password.
Request body
The same fields accepted by Save LDAP configuration (host, port, bind_dn, base_dn, use_ssl/use_tls, bind_password, etc.). All are read from the request as-is; supply enough to make a bind.
Response 200
{
"status": 201,
"hasError": false,
"message": "Connected successfully",
"groups_found": 42,
"groups": ["CN=Netmon Admins,OU=Groups,DC=example,DC=com"]
}
Errors
| Status | Body | When |
|---|---|---|
200 | {"status":false,"hasError":true,"message":"Enter the bind password to test a different server, port, or bind DN."} | Password omitted while testing a target other than the saved one. |
200 | {"status":false,"hasError":true,"message":"<bind error>"} | The bind failed. |
Example
curl -sS -X POST https://APPLIANCE/api/ldap/test \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"host":"dc01.example.com","port":636,"use_ssl":true,
"bind_dn":"cn=svc-netmon,dc=example,dc=com","bind_password":"s3cret",
"base_dn":"dc=example,dc=com"}'
Browse LDAP groups
GET/api/ldap/groupssa
Returns groups from the directory using the saved configuration, optionally filtered by a search term. Use it to populate a group picker when building mappings.
Query parameters
| Field | Type | Required | Notes |
|---|---|---|---|
search | string | no | Substring filter applied to group names. |
Response 200
{
"status": 201,
"hasError": false,
"groups": ["CN=Netmon Admins,OU=Groups,DC=example,DC=com"]
}
Example
curl -sS "https://APPLIANCE/api/ldap/groups?search=netmon" \
-H "Authorization: Bearer $TOKEN"
List group-to-permission mappings
GET/api/ldap/mappingssa
Returns every directory-group-to-permission mapping, each resolved to its permission name and slug.
Response 200
{
"status": 201,
"hasError": false,
"mappings": [
{
"id": 3,
"ldap_group_dn": "CN=Netmon Admins,OU=Groups,DC=example,DC=com",
"ldap_group_name": "Netmon Admins",
"permission_id": 1,
"permission_name": "Super Admin",
"permission_slug": "sa"
}
]
}
Example
curl -sS https://APPLIANCE/api/ldap/mappings \
-H "Authorization: Bearer $TOKEN"
Create or update a mapping
POST/api/ldap/mappingssa
Maps a single directory group to a single permission. The pair (ldap_group_dn, permission_id) is unique — re-saving the same pair updates the stored group name rather than creating a duplicate.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
ldap_group_dn | string | yes | Group distinguished name. Max 512. |
ldap_group_name | string | no | Display name. Max 255. |
permission_id | integer | yes | Must reference an existing permission. |
Response 200
{
"status": 201,
"hasError": false,
"mapping": {
"id": 3,
"ldap_group_dn": "CN=Netmon Admins,OU=Groups,DC=example,DC=com",
"ldap_group_name": "Netmon Admins",
"permission_id": 1
}
}
Example
curl -sS -X POST https://APPLIANCE/api/ldap/mappings \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"ldap_group_dn":"CN=Netmon Admins,OU=Groups,DC=example,DC=com",
"ldap_group_name":"Netmon Admins","permission_id":1}'
Replace all permissions for a group
POST/api/ldap/mappings/bulksa
Sets the complete permission set for one directory group in a single call: all existing mappings for the group DN are removed and replaced with the supplied list. Send an empty permission_ids array to clear a group’s permissions.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
ldap_group_dn | string | yes | Group DN. Max 512. |
ldap_group_name | string | no | Display name. Max 255. |
permission_ids | array | yes | Integer permission ids; each must exist. |
Response 200
{ "status": 201, "hasError": false, "message": "Group permissions updated" }
Example
curl -sS -X POST https://APPLIANCE/api/ldap/mappings/bulk \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"ldap_group_dn":"CN=Ops,OU=Groups,DC=example,DC=com",
"ldap_group_name":"Ops","permission_ids":[5,6,7]}'
Delete a mapping
DELETE/api/ldap/mappings/{id}sa
Removes a single group-to-permission mapping by id.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | integer | Mapping id from the list endpoint. |
Response 200
{ "status": 201, "hasError": false, "message": "Mapping deleted" }
This permanently removes the mapping. Directory users who relied on this group for the mapped permission lose it on their next sync or login.
Example
curl -sS -X DELETE https://APPLIANCE/api/ldap/mappings/3 \
-H "Authorization: Bearer $TOKEN"
List group tag restrictions
GET/api/ldap/group-tagssa
Returns the device-tag restrictions attached to each directory group. A directory user inherits the tag restrictions of every group they belong to, limiting them to the matching devices.
Response 200
{
"status": 201,
"hasError": false,
"tags": [
{
"ldap_group_dn": "CN=Site-A,OU=Groups,DC=example,DC=com",
"tag_id": 11,
"slug": "site-a",
"name": "Site A"
}
]
}
Example
curl -sS https://APPLIANCE/api/ldap/group-tags \
-H "Authorization: Bearer $TOKEN"
Replace tag restrictions for a group
POST/api/ldap/group-tagssa
Sets the complete set of device-tag restrictions for one directory group: all existing tags for the group DN are removed and replaced with the supplied slugs. Send an empty tag_slugs array to clear a group’s tag restrictions (the field must still be present).
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
ldap_group_dn | string | yes | Group DN. Max 512. |
tag_slugs | array | yes (may be empty) | Device-tag slugs; each must exist. |
Response 200
{ "status": 201, "hasError": false, "message": "Group tags updated" }
Example
curl -sS -X POST https://APPLIANCE/api/ldap/group-tags \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"ldap_group_dn":"CN=Site-A,OU=Groups,DC=example,DC=com","tag_slugs":["site-a"]}'
Sync all LDAP users
POST/api/ldap/syncsa
Forces an immediate re-evaluation of every directory-backed user against the current group mappings and tag restrictions, applying permission and tag changes without waiting for each user’s next login. Takes no request body.
Response 200
{
"status": 201,
"hasError": false,
"message": "Synced 18 users",
"synced": 18,
"errors": 0
}
Example
curl -sS -X POST https://APPLIANCE/api/ldap/sync \
-H "Authorization: Bearer $TOKEN"
OS upgrade
These endpoints drive the out-of-band operating-system upgrade flow (Debian 11 → 12). The upgrade itself runs in a separate web interface on the appliance — these endpoints only report state, install the upgrader package bundled with the appliance release, start/stop the upgrader service, and hand back the one-time access token for its interface.
Get upgrade status
GET/api/osUpgrade/infosa
Returns a diagnostic snapshot the operator reviews before committing: the running OS codename, the installed appliance version, any PostgreSQL clusters present, and whether the out-of-band upgrader is installed, active, enabled, and available to install.
Response 200
{
"codename": "bullseye",
"netmon_version": "7.0.20",
"postgres_clusters": [
{ "version": "13", "cluster": "main", "port": "5432", "status": "online", "raw": "13 main 5432 online ..." }
],
"upgrader_installed": false,
"upgrader_active": "inactive",
"upgrader_enabled": "disabled",
"upgrader_package_available": true
}
Example
curl -sS https://APPLIANCE/api/osUpgrade/info \
-H "Authorization: Bearer $TOKEN"
Install the OOB upgrader
POST/api/osUpgrade/installsa
Installs the out-of-band upgrader package that ships bundled inside the appliance release. Idempotent — if the upgrader is already installed it returns immediately. Takes no request body.
Response 200
{ "ok": true }
When the upgrader is already present:
{ "ok": true, "already_installed": true }
This installs a system package via the OS package manager. It is a privileged system change and a prerequisite for the OS upgrade flow that follows. Run it deliberately, not speculatively.
Errors
| Status | Body | When |
|---|---|---|
404 | {"status":404,"message":"No netmon-upgrader package is bundled with this release."} | No upgrader package is staged in this build. |
500 | {"status":500,"message":"Failed to install the netmon-upgrader package."} | The package install failed. |
Example
curl -sS -X POST https://APPLIANCE/api/osUpgrade/install \
-H "Authorization: Bearer $TOKEN"
Start the OOB upgrader
POST/api/osUpgrade/startsa
Starts the out-of-band upgrader service and returns its interface URL plus a one-time access token. The token authenticates you to the upgrader’s own interface, which then owns the upgrade from there. Takes no request body.
Response 200
{
"url": "https://APPLIANCE:7443/",
"token": "a1b2c3d4e5f6…"
}
Starting the upgrader begins the out-of-band OS upgrade workflow, which reboots the appliance and performs a distribution upgrade. Only start it when you are ready to upgrade the operating system.
The token is rendered once and never persisted, logged, or returned again. Capture it from this response and open the upgrader interface immediately; if you lose it, stop and start the upgrader to mint a fresh one.
Errors
| Status | Body | When |
|---|---|---|
500 | {"status":500,"message":"Failed to start netmon-upgrader"} | The service failed to start. |
500 | {"status":500,"message":"Upgrader started but token file is unreadable"} | The service started but the token could not be read. |
Example
curl -sS -X POST https://APPLIANCE/api/osUpgrade/start \
-H "Authorization: Bearer $TOKEN"
These endpoints only bootstrap the out-of-band assistant; the screen-by-screen upgrade itself — the checkpoint, the two reboots, and the rollback path — is documented in the System Upgrade Guide.
Stop the OOB upgrader
POST/api/osUpgrade/stopsa
Stops the out-of-band upgrader service, which also invalidates its current access token (the next start mints a new one). Use it after the upgrade completes, or to abort before any phase has run. Idempotent. Takes no request body.
Response 200
{ "ok": true }
Errors
| Status | Body | When |
|---|---|---|
500 | {"status":500,"message":"Failed to stop netmon-upgrader"} | The service failed to stop. |
Example
curl -sS -X POST https://APPLIANCE/api/osUpgrade/stop \
-H "Authorization: Bearer $TOKEN"
OAuth client approval
OAuth clients may register themselves dynamically, but a self-registered client cannot complete an authorization flow until an operator approves it. These endpoints are the review queue: list the clients awaiting approval, approve one, or reject (delete) one.
Unlike the rest of this chapter, the client-approval endpoints require permission:system rather than permission:sa.
List pending clients
GET/api/oauth/clients/pendingsystem
Returns every dynamically-registered OAuth client still awaiting approval, oldest first.
Response 200
{
"clients": [
{
"client_id": "abc123",
"client_name": "Claude Desktop",
"redirect_uris": ["https://client.example/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "none",
"created_at": "2026-06-14T09:12:00Z"
}
]
}
Example
curl -sS https://APPLIANCE/api/oauth/clients/pending \
-H "Authorization: Bearer $TOKEN"
Approve a client
POST/api/oauth/clients/{clientId}/approvesystem
Approves a pending client so it can complete authorization flows. Idempotent — approving an already-approved client returns the current approval state without re-stamping it. The approving user’s id is recorded for audit.
Path parameters
| Name | Type | Notes |
|---|---|---|
clientId | string | The client’s client_id. |
Response 200
{
"client_id": "abc123",
"approved_at": "2026-06-15T10:00:00Z",
"approved_by_user_id": 1
}
Errors
| Status | Body | When |
|---|---|---|
404 | {"error":"not_found"} | No client with that id. |
Example
curl -sS -X POST https://APPLIANCE/api/oauth/clients/abc123/approve \
-H "Authorization: Bearer $TOKEN"
Reject a client
DELETE/api/oauth/clients/{clientId}system
Rejects and deletes a client. Works on both pending and already-approved clients — rejecting an approved client revokes it, and its refresh-token chain is dropped with it.
Path parameters
| Name | Type | Notes |
|---|---|---|
clientId | string | The client’s client_id. |
Response 200
{ "deleted": true }
Errors
| Status | Body | When |
|---|---|---|
404 | {"error":"not_found"} | No client with that id. |
This permanently deletes the client and, for an approved client, revokes its tokens. Any integration using that client stops working immediately.
Example
curl -sS -X DELETE https://APPLIANCE/api/oauth/clients/abc123 \
-H "Authorization: Bearer $TOKEN"