REST API and agent protocol
The binding reference of every route, body and error code is section 7 (REST) and section 8 (agent) of
navin-manager/CONTRACT.md. The running server also publishes its OpenAPI description at
/api/v1/openapi.json.
Authentication
| Client | How |
|---|---|
| Browser | POST /api/v1/auth/login sets the cookie nm_session and returns csrf_token. Send it in the header X-CSRF-Token with every POST, PUT, PATCH and DELETE. |
| Automation | Authorization: Bearer nmt_<id>_<secret>: an API token created in Profile, API tokens (POST /api/v1/me/tokens). No CSRF header. |
TOKEN=nmt_0123456789ab_...
curl -s -H "Authorization: Bearer $TOKEN" https://<manager-host>:8460/api/v1/clusters
The language of the messages follows the cookie nm_lang (en or fr), then the header Accept-Language.
Errors and lists
Every error has the same shape, with the message in both languages:
{"error": {"code": "cluster_not_empty", "message": "...", "message_i18n": {"en": "...", "fr": "..."},
"details": {}}}
| Status | Typical codes |
|---|---|
| 401 | unauthenticated, session_expired, token_invalid, invalid_credentials, agent_signature_invalid |
| 403 | permission_denied (details give the permission), csrf_invalid, account_disabled, password_expired |
| 404 | not_found, service_unknown, operation_not_found |
| 409 | cluster_not_empty, host_has_components, service_in_use, connection_in_use, artifact_missing, sandbox_only_service, last_admin |
| 422 | validation_error, config_invalid (details give the fields), password_policy |
| 423 | account_locked |
| 429 | too_many_attempts (header Retry-After) |
Lists take ?limit= (50 by default, 500 at most) and ?cursor= and return {"items": [...], "next_cursor": ...}.
A secret is never returned: it reads {"secret": true, "set": true}; sending that value back keeps the stored secret.
Main routes
| Area | Routes |
|---|---|
| Session | /auth/providers, /auth/setup, /auth/login, /auth/mfa/*, /auth/password/change, /auth/session, /auth/logout, /auth/oidc/{id}/start and /callback, /me, /me/tokens |
| Administration | /users, /roles, /auth-config/ldap, /auth-config/oidc, /auth-config/policy, /audit, /audit/verify, /audit/export, /settings, /connections |
| Catalog | /stack, /stack/services/{name}, /mirror, /mirror/reload |
| Clusters and hosts | /clusters, /clusters/{id}/summary, /topology, /bootstrap-tokens, /hosts/ssh-bootstrap, /hosts, /hosts/{id}, /hosts/{id}/metrics, /preflight, /facts/refresh, /parameters, /decommission |
| Services | /clusters/{id}/services, /services/validate, /services/{name}, /actions, /commands/{command}, /components, /logs, /client-config |
| Configurations | /clusters/{id}/services/{name}/config, /config/versions, /config/diff, /config/versions/{v}/restore, /config/groups, /config/preview, /config/apply, /clusters/{id}/blueprint |
| Operations | /clusters/{id}/operations, /operations/running, /operations/{id}, /operations/{id}/tasks/{task}, /logs, /abort, /retry |
| Alerts | /clusters/{id}/alerts, /alerts/{id}, /alerts/{id}/ack, /alert-definitions, /notification-targets |
| Monitoring | /system/health, /clusters/{id}/sd/prometheus, /pki/ca, /clusters/{id}/certificates; outside /api/v1: /healthz, /readyz, /metrics |
All paths above are below /api/v1.
Following an operation
Every action returns {"operation_id": "..."}. Poll GET /api/v1/operations/{id} for the stages, tasks and
progress, and GET /api/v1/operations/{id}/tasks/{task}/logs?after_seq=<n> for the log lines of a task (next_seq
is the value of the next call, done turns true when the task is finished).
OP=$(curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"action": "rolling_restart", "batch_size": 1}' \
https://<manager-host>:8460/api/v1/clusters/$CLUSTER/services/opa/actions | jq -r .operation_id)
curl -s -H "Authorization: Bearer $TOKEN" https://<manager-host>:8460/api/v1/operations/$OP | jq .status
Webhook notifications
A webhook target receives a JSON POST with X-NM-Signature: t=<unix>,v1=<hex>. Check it on the receiving side:
v1 must equal HMAC-SHA256(secret, "<t>.<raw body>") and t must be less than 5 minutes old.
Agent protocol
The agent calls the manager, never the other way round:
POST /agent/v1/registeron port 8460 with the bootstrap token, the facts and a certificate request; the response holds the host id, the agent secret, the certificate and the manager CA, whose sha256 fingerprint the agent compares with--ca-sha256.- On port 8461, with the client certificate:
POST /agent/v1/heartbeatevery 15 seconds (metrics, component states, facts when asked),GET /agent/v1/tasks?wait=25(long poll),POST /agent/v1/tasks/{id}/logsandPOST /agent/v1/tasks/{id}/result,POST /agent/v1/renewbefore the certificate expires. - Each request is signed:
Authorization: NM-HMAC <host_id>:<unix ts>:<hex>where the HMAC-SHA256 covers the method, the path with its query, the timestamp and the sha256 of the body. A timestamp more than 300 seconds away is refused.
The task types and their payloads are listed in section 9 of the contract.