REST API Reference
6 minute read
REST API Reference
The Exaviz Management Platform exposes a REST API for programmatic access to all board management features. Every action available in the dashboard is also available through the API.
Base URL
https://<board-ip>/api/v1
The API is served over HTTPS on the same port as the dashboard (default: 443).
Authentication
Login
Obtain a Bearer token by authenticating with the board password.
curl -k -X POST https://<board-ip>/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"password": "your-password"}'
Response:
{
"token": "a1b2c3d4...",
"expires_at": "2026-04-10T10:00:00Z",
"must_change_password": true
}
On first boot, the default password is admin. The response includes "must_change_password": true until the password is changed.
The password must be changed before any other API endpoints will accept requests. Call POST /api/v1/auth/change-password first.
Change Password
curl -k -X POST https://<board-ip>/api/v1/auth/change-password \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"current_password": "admin", "new_password": "minimum8chars"}'
Changing the password invalidates all existing tokens. You must log in again.
Using Tokens
Include the token in all subsequent requests:
Authorization: Bearer <token>
Tokens expire after 24 hours. Login is rate-limited to 10 attempts per minute per IP address.
Logout
curl -k -X POST https://<board-ip>/api/v1/auth/logout \
-H "Authorization: Bearer <token>"
Public Endpoints (No Auth Required)
GET /api/v1/board
Board identification and hardware metadata.
curl -k https://<board-ip>/api/v1/board
{
"board_type": "cruiser",
"variant": "cruiser-raspberrypi-cm5",
"compute_module": "Raspberry Pi CM5",
"serial": "CRU-000011",
"board_revision": "1.0",
"firmware_version": "1.0.2+21230d7",
"poe_controller": "TPS23861 (Texas Instruments)",
"os_version": "Debian GNU/Linux 13 (trixie)",
"total_poe_ports": 8
}
GET /api/v1/branding
Current branding configuration (logo, colors, product name).
curl -k https://<board-ip>/api/v1/branding
{
"product_name": "exaviz Management",
"logo_url": "/assets/logo.svg",
"primary_color": "#90FF80",
"support_url": "https://exa-pedia.com/docs/",
"company_url": "https://www.exaviz.com"
}
GET /api/v1/help
Contextual help content for the dashboard. Adapts to enabled features and branding.
PoE Ports
GET /api/v1/poe/ports
Returns all PoE port statuses.
curl -k -H "Authorization: Bearer <token>" \
https://<board-ip>/api/v1/poe/ports
{
"ports": [
{
"pse": 0,
"index": 0,
"name": "poe0",
"state": "delivering",
"class": 4,
"power_alloc_w": 25.5,
"power_w": 4.9,
"voltage_v": 52.1,
"current_ma": 94.0,
"current_limit_ma": 600.0,
"temp_c": 42.0,
"temp_limit_c": 150.0,
"event": "none",
"updated_at": "2026-03-29T10:00:00Z"
}
],
"count": 8
}
Port states: delivering, searching, disabled, fault, backoff, unknown
GET /api/v1/poe/ports/{pse}/{index}
Returns a single port status.
Parameters:
pse- PSE controller number (0 or 1)index- Port index on the PSE (0-3)
POST /api/v1/poe/ports/{pse}/{index}/enable
Enable power delivery on a port.
curl -k -X POST -H "Authorization: Bearer <token>" \
https://<board-ip>/api/v1/poe/ports/0/0/enable
POST /api/v1/poe/ports/{pse}/{index}/disable
Disable power delivery on a port.
POST /api/v1/poe/ports/{pse}/{index}/reset
Power-cycle a port (disable, wait, re-enable).
PUT /api/v1/poe/ports/{pse}/{index}/label
Set a custom label for a port.
curl -k -X PUT -H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"label": "Lobby Camera"}' \
https://<board-ip>/api/v1/poe/ports/0/0/label
PUT /api/v1/poe/ports/{pse}/{index}/mode
Switch PoE mode (at = PoE+ 30W, af = PoE 15.4W).
curl -k -X PUT -H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"mode": "at"}' \
https://<board-ip>/api/v1/poe/ports/0/0/mode
GET /api/v1/poe/labels
Returns all port labels.
GET /api/v1/poe/history
Returns power and temperature sparkline data (60 samples, 1 per minute).
Port Groups
GET /api/v1/poe/groups
List all port groups.
POST /api/v1/poe/groups
Create a new port group.
curl -k -X POST -H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name": "All Cameras", "ports": [{"pse": 0, "index": 0}, {"pse": 0, "index": 1}]}' \
https://<board-ip>/api/v1/poe/groups
PUT /api/v1/poe/groups/{id}
Update a group’s name or port membership.
DELETE /api/v1/poe/groups/{id}
Delete a port group.
POST /api/v1/poe/groups/{id}/enable
Enable all ports in the group.
POST /api/v1/poe/groups/{id}/disable
Disable all ports in the group.
POST /api/v1/poe/groups/{id}/reset
Reset all ports in the group.
Switch Ports
GET /api/v1/switch/ports
Returns all network switch ports with link status and traffic counters.
curl -k -H "Authorization: Bearer <token>" \
https://<board-ip>/api/v1/switch/ports
{
"ports": [
{
"name": "poe0",
"oper_state": "up",
"carrier": true,
"speed_mbps": 1000,
"duplex": "full",
"mac": "76:69:7a:00:00:01",
"stats": {
"rx_bytes": 123456789,
"rx_packets": 100000,
"rx_errors": 0,
"tx_bytes": 987654321,
"tx_packets": 200000,
"tx_errors": 0
}
}
],
"count": 10
}
System Health
GET /api/v1/system/health
Board health metrics.
curl -k -H "Authorization: Bearer <token>" \
https://<board-ip>/api/v1/system/health
{
"cpu_temp_c": 52.3,
"mem_total_mb": 2048,
"mem_used_mb": 384,
"mem_percent": 18.75,
"uptime_secs": 86400,
"load_avg_1": 0.15,
"load_avg_5": 0.10,
"load_avg_15": 0.08,
"hostname": "cruiser",
"kernel_version": "6.12.0-rpi",
"arch": "arm64"
}
POST /api/v1/system/reboot
Reboot the board.
curl -k -X POST -H "Authorization: Bearer <token>" \
https://<board-ip>/api/v1/system/reboot
PUT /api/v1/board/name
Set the board’s display name (shown in fleet view and mDNS).
curl -k -X PUT -H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name": "Building A Switch"}' \
https://<board-ip>/api/v1/board/name
Alerts
GET /api/v1/system/alerts/active
Returns all active (unresolved) alerts.
{
"alerts": [
{
"id": 1,
"type": "cpu_temp",
"severity": "warning",
"message": "CPU temperature 85C exceeds 80C threshold",
"created_at": "2026-03-29T10:00:00Z",
"resolved": false
}
]
}
POST /api/v1/system/alerts/{id}/resolve
Mark an alert as resolved.
Audit Log
GET /api/v1/system/audit
Query the audit log with pagination.
curl -k -H "Authorization: Bearer <token>" \
"https://<board-ip>/api/v1/system/audit?limit=50&offset=0"
{
"entries": [
{
"timestamp": "2026-03-29T10:00:00Z",
"action": "port_disable",
"actor": "10.0.1.50",
"target": "pse0/port3",
"detail": "Port disabled by user"
}
],
"total": 156
}
TLS Certificate Management
GET /api/v1/system/tls/info
Current certificate information (expiry, CN, SANs).
POST /api/v1/system/tls/upload
Upload a custom TLS certificate and key.
curl -k -X POST -H "Authorization: Bearer <token>" \
-F "cert=@server.crt" -F "key=@server.key" \
https://<board-ip>/api/v1/system/tls/upload
The certificate is hot-swapped atomically. No service restart required.
PUT /api/v1/system/tls/mode
Switch TLS mode.
curl -k -X PUT -H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"mode": "acme"}' \
https://<board-ip>/api/v1/system/tls/mode
Modes: self-signed, upload, acme
POST /api/v1/system/tls/acme/request
Request a certificate from Let’s Encrypt via ACME.
GET /api/v1/system/tls/acme/status
Check the status of an ACME certificate request.
Backup and Restore
GET /api/v1/system/backup
Download a full board configuration backup as a .tar.gz archive.
curl -k -H "Authorization: Bearer <token>" \
-o backup.tar.gz \
https://<board-ip>/api/v1/system/backup
POST /api/v1/system/restore
Restore from a backup archive.
curl -k -X POST -H "Authorization: Bearer <token>" \
-F "backup=@backup.tar.gz" \
https://<board-ip>/api/v1/system/restore
User Preferences
GET /api/v1/user/prefs/{key}
Get a user preference (e.g., theme, view_mode).
PUT /api/v1/user/prefs/{key}
Set a user preference.
curl -k -X PUT -H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"value": "light"}' \
https://<board-ip>/api/v1/user/prefs/theme
Fleet Endpoints
Fleet endpoints are available when fleet management is enabled.
GET /api/v1/fleet/peers
List discovered boards on the network (via mDNS).
GET /api/v1/fleet/boards
Aggregated status of all trusted (paired) boards.
GET /api/v1/fleet/events
Server-Sent Events stream for fleet status updates.
POST /api/v1/fleet/pair
Initiate pairing with a discovered board.
POST /api/v1/fleet/pair/respond
Respond to a pairing challenge (board-to-board).
POST /api/v1/fleet/pair/confirm
Confirm pairing after visual code verification.
GET /api/v1/fleet/pair/pending
List pending pairing requests.
POST /api/v1/fleet/pair/accept
Accept a pending pairing request.
POST /api/v1/fleet/pair/reject
Reject a pending pairing request.
DELETE /api/v1/fleet/peers/{serial}
Remove a trusted peer.
PUT /api/v1/fleet/board-order
Save the board display order in fleet view.
GET /api/v1/fleet/diagnostics
Fleet debug information (peer list, trust state, aggregator status).
Fleet Authentication (Board-to-Board)
Fleet API requests between paired boards use Ed25519 signature authentication instead of Bearer tokens:
| Header | Value |
|---|---|
X-Fleet-Serial | Board serial number |
X-Fleet-Sig | Ed25519 signature of the timestamp |
X-Fleet-Time | Unix timestamp (5-minute replay window) |
Real-Time Updates (SSE)
GET /api/v1/events
Server-Sent Events stream delivering PoE port status, switch port status, and system health every 2 seconds.
curl -k -N -H "Authorization: Bearer <token>" \
https://<board-ip>/api/v1/events
Events are delivered as JSON objects. The dashboard uses this endpoint for real-time updates without polling.
Prometheus Metrics
GET /metrics
Prometheus-compatible metrics endpoint. No authentication required.
curl -k https://<board-ip>/metrics
Available metric families:
- Go runtime (goroutines, memory, GC)
- Board identity (serial, type, firmware)
- System health (CPU temp, memory, uptime, load)
- PoE ports (total power, count by state)
- SSE clients (connected dashboard sessions)
- Fleet stats (total boards, online count)
Error Responses
All errors return JSON:
{"error": "description of what went wrong"}
| Status | Meaning |
|---|---|
| 400 | Bad request (invalid parameters) |
| 401 | Unauthorized (missing or invalid token) |
| 404 | Not found |
| 429 | Rate limited (login attempts) |
| 500 | Server error |
Last modified April 9, 2026