API and events
Everything the web interface does goes through the same REST API, so scripts can do it too.
- Interactive documentation:
/docs(Swagger) and/redoc. - The OpenAPI schema:
/openapi.json. - Application endpoints live under
/v1/api; sign-in and first-admin setup under/v1/auth.
The OpenAPI documentation of the server you run is the exact reference for that version.
Authenticate
Create an API key and send it in the X-Minipam-Api-Key header. The key acts
with its user's role.
export MINIPAM=https://minipam.example.com
export MINIPAM_API_KEY=...
curl -fsS -H "X-Minipam-Api-Key: $MINIPAM_API_KEY" "$MINIPAM/v1/api/sites/"
Keep keys out of source control and shell history on shared machines.
An invalid or revoked key gets 401 (E2401), even when the request also carries a valid session cookie.
MiniPAM does not fall back from a bad key to the cookie.
Browser sessions and CSRF
The web interface signs in with POST /v1/auth/login and gets two cookies: the session cookie
(minipam_session by default, set by cookie-name) and a CSRF cookie with
the same name plus _csrf. Scripts that use a session instead of an API key must follow the same rule:
POST,PUT,PATCH, andDELETErequests need the headerX-Minipam-CSRF, with the same value as the CSRF cookie. Otherwise they fail with403and "The CSRF token is missing or invalid".GET /v1/auth/csrfreturns the current token as{"csrf_token": "…"}and sets the cookie again.- Requests with an API key need no CSRF token. For scripts, an API key is simpler.
Which role an endpoint needs
Every operation in /openapi.json carries an x-minipam-authorization field. It holds the lowest role that
may call it (viewer, editor, or admin), or "public": true for the few that need no sign-in:
curl -fsS "$MINIPAM/openapi.json" | jq '.paths["/v1/api/sites/"].post["x-minipam-authorization"]'
{ "minimum_role": "admin", "policy": null }
/openapi.json, /docs, and /redoc need no sign-in.
Lists, filters, and paging
List endpoints accept offset and limit (1 to 500, default 100), most accept site_id, and many accept
search and a structured filter:
curl -fsS -G -H "X-Minipam-Api-Key: $MINIPAM_API_KEY" "$MINIPAM/v1/api/networks/" \
--data-urlencode "site_id=1" \
--data-urlencode "filter=vlan_id:gt:10" \
--data-urlencode "limit=50"
They return the page and the total:
{
"offset": 0,
"limit": 50,
"count": 2,
"total": 2,
"items": [{ "id": 10001, "network_name": "Servers", "network_cidr": "192.168.10.0/24" }]
}
The filter syntax is the one from structured filters.
Services and gateways created without a site_id are global: templates in every site can read them. The web
interface only creates site-scoped ones.
Errors
Errors have a stable error code and a human-readable description. Match on the code, not the text:
{ "code": 404, "error": "E1404", "description": "Site 7 was not found." }
| Code | HTTP | Meaning |
|---|---|---|
E1404 | 404 | The resource was not found. |
E2400 | 400 | The request body or parameters are invalid. The description says which. |
E2401 | 401 | Not signed in, or the session or API key is invalid. Also wrong sign-in credentials. |
E2403 | 403 | Your role is too low, or the CSRF token is missing or invalid. Read the description. |
E2409 | 409 | Conflicts with an existing record or the current state. May include a conflict object. |
E2410 | 400 | Refers to a related record that does not exist. |
E2411 | 409 | The job cannot move to the requested status. |
E2413 | 413 | The uploaded file is too large. Import files are limited to 20 MB. |
E5000 | 500 | Unexpected server error. The server log has the details. |
A few features return their own codes. Template rendering, for example, returns TEMPLATE_RENDER_TIMEOUT
(408) and TEMPLATE_RENDER_CAPACITY (429). See
A template render or download fails.
Common tasks
Fetch the published output of a template, for example from a cron job:
curl -fsS -H "X-Minipam-Api-Key: $MINIPAM_API_KEY" \
-o nginx.conf "$MINIPAM/v1/api/configuration-templates/42/outputs/download"
The response's X-MiniPAM-Output-Version header says which output you got. A specific version is at
…/outputs/{version}/download.
Read the asset integrity summary for a site, or run all inventory checks (editor role):
curl -fsS -H "X-Minipam-Api-Key: $MINIPAM_API_KEY" "$MINIPAM/v1/api/asset-integrity/summary?site_id=1"
curl -fsS -X POST -H "X-Minipam-Api-Key: $MINIPAM_API_KEY" "$MINIPAM/v1/api/asset-integrity/run?site_id=1"
Search across all sites, like Ctrl+K in the interface:
curl -fsS -G -H "X-Minipam-Api-Key: $MINIPAM_API_KEY" "$MINIPAM/v1/api/search/" --data-urlencode "q=ip: 192.168.10."
Live events
The interface listens to server-sent events at /sse/ for job, log, and data changes. Any signed-in user
(viewer role) can subscribe. Each event's data is JSON with a stream_type and a payload:
| Event | Sent when |
|---|---|
connected (system.connected) | Once, when you subscribe |
heartbeat (system.heartbeat) | After 15 seconds without other events |
job.status | A job is created or changes status |
job.log | A job gets a new log entry |
agent.status | An agent goes online or offline |
agent.request.status | A request that is not stored as a job changes status |
agent.request.output | Such a request returns output |
discovery.review.changed | The review queue changed |
discovery.rules.changed | Review rules changed |
discovery.subjects.changed | Discovered devices changed |
discovery.introspection.changed | Device scans start, or their policy changes |
discovery.controls.changed | A field is set to Manual or Managed through the controls API |
Treat an event as a hint to re-read the REST resource, not as a record you must not miss:
- Each subscriber has a queue of 128 events. When a slow client falls behind, the oldest events are dropped.
- Nothing is replayed after a reconnect. Re-read what you show after every reconnect.
- Events are not filtered by site. Check
payload.site_idwhere it is present. - Events live in the server process. They are lost on restart.
Agents
Agents connect to /ws/agent over a WebSocket, authenticated with their token. That protocol is for the
MiniPAM agent only; integrations should use REST and events. To see how it works, read
Server and agent architecture.
Health
GET /health needs no authentication and returns {"status": "ok"} when the server is up. It does not check
agents, scans, or scheduled jobs.