API reference

All /api/* routes (except setup-status and setup) require a valid session cookie — log in via the web UI, or POST /api/login directly.

Method & path Auth Body Result
GET /api/setup-status none {needs_setup}
POST /api/setup none, once only {username, password} creates the first admin account + session
POST /api/login none {username, password} session cookie
POST /api/logout session 204
GET /api/session session {id, username, role}
GET /api/agents session list of agents (with live online status)
GET /api/agents/{id} session one agent
DELETE /api/agents/{id} session, admin {"confirm": true} 204 — deletes the agent record, force-closing its live session if connected
GET /api/agents/{id}/shell session — (WebSocket upgrade) bridges to a live PTY on the agent
GET /api/enrollment-tokens session, admin list of tokens
POST /api/enrollment-tokens session, admin {label, max_uses, ttl_seconds} {..., token} — raw value shown once
DELETE /api/enrollment-tokens/{id} session, admin {"confirm": true} 204 — revokes the token
GET /api/audit-log session, admin — (query: ?limit=N) list of audit entries, newest first

Destructive endpoints (DELETE /api/agents/{id}, DELETE /api/enrollment-tokens/{id}) require an explicit {"confirm": true} in the request body — a bare DELETE with no body (or {"confirm": false}) is rejected with 400.

The shell WebSocket

GET /api/agents/{id}/shell?cols=N&rows=N upgrades to a WebSocket. Binary messages carry terminal I/O in both directions. A JSON text message {"type": "resize", "cols": N, "rows": N} (client → server) adjusts the PTY's size mid-session.

The endpoint enforces same-origin by default (the Origin header must be unset or match the Host header) — it isn't meant to be embedded cross-origin.