Skip to content

API Reference

Eight.ly OS is a single Go binary. Everything the dashboard does, it does by calling this same HTTP API — there is no separate backend for the UI.

Base URL: http://box.example.lan:8080/api/


The spec

The API is described by an OpenAPI 3.1 document, generated straight from the Go router by scripts/gen-openapi.py — it isn't hand-written, so it can't describe a route that doesn't exist. Every box serves its own copy live:

curl http://box.example.lan:8080/api/openapi.json

Fetch it and read it with any OpenAPI tool (Swagger UI, Postman, eosctl api) rather than copying routes out of this page by hand — this page gives you the shape of the API, not the whole spec.


Authentication

Two ways to authenticate:

  • API key — Authorization: Bearer eos_.... Create one from Settings > Security > API Keys in the dashboard. See API Keys.
  • Signed-cookie session — what the dashboard itself uses. POST /api/auth/login issues an HMAC-SHA256 signed cookie (not a JWT); every subsequent request just needs the cookie.
curl -c cookies.txt -X POST http://box.example.lan:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "your-password"}'
{
  "success": true,
  "data": { "id": "...", "username": "admin", "role": "admin", "status": "active" }
}
curl -b cookies.txt http://box.example.lan:8080/api/health

Repeated failed logins are throttled per-IP and per-username (429 Too Many Requests with a Retry-After header); every login attempt, success or failure, is audit-logged.

A state-changing request (POST/PUT/PATCH/DELETE) made with a session cookie must also carry a double-submit CSRF token — the server rejects it otherwise. A request authenticated with Authorization: Bearer eos_... is exempt: a bearer token can't be replayed cross-origin the way a cookie can, so there's nothing for CSRF to protect against on that path. If you're scripting against the API, using an API key sidesteps CSRF entirely — that's the main reason the CLI, the MCP server, and any automation should use one rather than logging in.

API keys

curl -H "Authorization: Bearer eos_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  http://box.example.lan:8080/api/health

Full detail — creating, listing, and revoking keys, and what a key can do — is on the API Keys page.


Response envelope

Success responses across the API share one shape:

{
  "success": true,
  "data": { }
}

Parse .data.

Error bodies are less consistent. The spec's own declared response schema says {"success": false, "message": "..."}, but some handlers don't follow it — a few return {"success": false, "error": "..."} instead, and a handful of older ones return a bare {"error": "..."} with no success field at all. Check the HTTP status code first, and look for a message under either message or error rather than assuming one key name.

Common status codes: 400 bad request, 401 not authenticated, 403 not authorized, 404 not found, 429 rate limited, 500 server error.


API areas

Counted straight from the spec: 521 distinct paths, 695 operations, across 69 subsystem groups.

This table shows the largest groups and a representative slice — not the full spec.

Area Base path Ops (paths) Covers Guide
storage /api/storage/* 80 (69) SnapRAID, MergerFS/array, disks, cache, the Shelver Storage
auth /api/auth/* 52 (35) Login, session, API keys, users, groups, roles, 2FA, realms Datacenter Management
node /api/node/* 49 (38) Host info, services, disks, network, shell (WebSocket) Node Management
firewall /api/firewall/* 33 (9) nftables rules, aliases, IP sets, groups Firewall
zfs /api/zfs/* 28 (17) ZFS pool create, import, dataset, snapshot, health Storage
samba / nfs /api/samba/*, /api/nfs/* 23 + 7 SMB shares, NFS exports, users File Sharing
system /api/system/* 22 (22) System info, GPU, sensors, updates Node Management
nova /api/nova/* 20 (17) AI assistant — models, chat, engines, chats, memory Nova AI
snapraid /api/snapraid/* 19 (14) Parity sync, scrub, check, fix, config Storage
ha /api/ha/* 18 (11) Rehome high availability — fencing, groups, affinity Advanced Features
health /api/health/* 18 (18) System health, subsystem status Node Management
network /api/network/* 17 (14) Interfaces, Docker networks, ports Networking
sdn /api/sdn/* 17 (11) Software-defined networking (experimental) Advanced Features
apps /api/apps/* 14 (12) App Store catalog, search, install, taxonomy Getting Started with Apps
vm /api/vm/* 14 (10) VM lifecycle, templates, ISOs VM Management
vpn /api/vpn/* 14 (12) Cloudflare tunnel, VPN —
cluster /api/cluster/* 13 (11) Multi-node clustering Advanced Features
notifications /api/notifications/* 13 (8) Email/webhook targets, event rules, history Notifications
acme /api/acme/* 11 (6) Let's Encrypt certificate management ACME Certs
docker /api/docker/* 11 (8) Docker networks, stacks Web Dashboard
backup /api/backup/* 10 (6) Local + EBS backup jobs, restore Backup
license /api/license/* 10 (10) Activation, heartbeat, catalog sync Licensing
lxc /api/lxc/* 9 (6) LXC container lifecycle, App Store install LXC
containers /api/containers/* 4 (4) Docker container lifecycle, stats, exec shell Web Dashboard
files /api/files/* 4 (4) File browser (list, mkdir, upload, delete) Web Dashboard
ceph /api/ceph/* 3 (1) Ceph distributed storage (experimental) Advanced Features
events /api/events* 7 (5) SSE event stream + stream management —

RBAC is enforced per subsystem, deny-by-default — each API package wires its own role requirements, and an endpoint with no role wired rejects the request. Three roles:

Role Access
admin Full access to all endpoints
operator Deploy apps, manage containers/VMs, view storage — no user management or security settings
viewer Read-only access to all GET endpoints

An API key has no role of its own — it inherits whichever of these three roles the account that created it holds. See API Keys.


Common endpoints

# System health
curl -b cookies.txt http://box.example.lan:8080/api/health

# List containers
curl -b cookies.txt http://box.example.lan:8080/api/containers

# List VMs
curl -b cookies.txt http://box.example.lan:8080/api/vm/list

# Storage status
curl -b cookies.txt http://box.example.lan:8080/api/storage/status

# App catalog
curl -b cookies.txt http://box.example.lan:8080/api/apps

# Nova AI chat
curl -X POST -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{"message": "how much disk space is free?"}' \
  http://box.example.lan:8080/api/nova/chat

Prefer not to hand-write curl calls at all? eosctl is a command line client generated from this same spec, and eosctl-mcp exposes it to AI assistants as MCP tools.


Streaming

curl -N -b cookies.txt http://box.example.lan:8080/api/events

One shared SSE connection streams system metrics, container state changes, storage events, and Docker events — the dashboard uses a single EventSource for all of it.

Nova AI chat responses stream as NDJSON, emitting thinking, tool_call, tool_result, and content events.

WebSocket endpoints

Endpoint Purpose
/api/node/shell Host web terminal (PTY over WebSocket, tmux-backed, admin-only)
/api/containers/shell/{id} Container console