Skip to content

Public API

Panes exposes a small public API under /api/pub/v1 so an external app running on the same machine — a dashboard, a provisioning script, a fleet console — can read the monitors and set their commands without going through the web UI’s login.

The API is served on the same loopback address as the UI: https://127.0.0.1:31077.

The public API has no session login. It is gated two ways instead:

  • Browser origin allowlist. A request that carries an Origin header (i.e. a browser fetch) must come from an allowed origin, or it’s rejected with 403. The allowlist is deny-by-default; add origins in Settings → Origins in the UI (admin only). A request with no Origin header (a non-browser local caller like curl or a script) is allowed — which is safe only because the server is bound to loopback.
  • Rate limit — 120 requests per minute per IP.
Method & path Purpose
GET /api/pub/v1/health Liveness — { status, name, version }. Ungated, not rate-limited.
GET /api/pub/v1/openapi.json OpenAPI document for generating clients. Ungated.
GET /api/pub/v1/monitors List monitors: { id, label, connected, primary, width, height }.
GET /api/pub/v1/status Per-command status: { command_id, state, pid, placed, last_error }.
POST /api/pub/v1/monitors/{id}/commands Append one command to a monitor. Returns its id.
PUT /api/pub/v1/monitors/{id}/commands Replace all of a monitor’s commands (empty list clears them).

Both write endpoints reconcile immediately, so the change launches right away.

Terminal window
# What monitors does this machine have?
curl -sk https://127.0.0.1:31077/api/pub/v1/monitors
# Put a dashboard on one of them, fullscreen Chrome kiosk.
curl -sk -X POST https://127.0.0.1:31077/api/pub/v1/monitors/<monitor-id>/commands \
-H 'Content-Type: application/json' \
-d '{
"name": "Dashboard",
"preset": "chrome_kiosk",
"exe_path": "https://dash.example.internal",
"placement": "fullscreen",
"launch_at_startup": true,
"watchdog": true
}'