HTTP API Reference

REST API served over HTTPS on port 8443. Used by the React, iOS, and macOS clients to monitor and control the server.

Endpoints Summary

EndpointMethodPurpose
/api/healthGETLightweight health check (no auth required)
/api/statusGETService status, tempo, client list
/api/service/controlPOSTStart/stop services
/api/tempoGETCurrent tempo and time reference
/api/programGET/POSTGet/set LED program
/api/logGETServer log tail
/api/devicesGETConnected device list with IPs and last seen time

All POST endpoints validate request body size (max 4 KB) and required JSON fields. When --api-token is set, all endpoints require Authorization: Bearer <token>.

— All responses are JSON with Content-Type: text/json; charset=utf-8.

Authentication

When the server is started with --api-token, every request must include a Bearer token:

Authorization: Bearer <token>

Unauthenticated requests receive a 401 Unauthorized response:

{ "error": "Unauthorized" }

Rate Limiting

POST endpoints are rate-limited to 60 requests per 10-second sliding window. Exceeding the limit returns 429 Too Many Requests:

{ "error": "Too many requests" }

Request Limits

All POST endpoints reject request bodies larger than 4 KB with a 400 Bad Request response.


Endpoints

GET /api/health

Lightweight health check endpoint. Returns a fixed response with no authentication required. Used by clients to check server reachability.

Response 200 OK

{ "status": "ok" }

GET /api/status

Returns the server health status, service states, current tempo, and connected device count.

Response 200 OK

{
  "message": "It's all good!",
  "status": {
    "beat_detector": true,
    "udp_server": false,
    "tempo_broadcaster": false
  },
  "tempo": 120.5,
  "deviceCount": 3
}
FieldTypeDescription
messagestringStatus message
statusobjectMap of service ID to running state (boolean)
temponumberCurrent detected tempo in BPM
deviceCountnumberNumber of connected Pico W devices

POST /api/service/control

Start or stop a server service.

Request body

{
  "id": "beat_detector",
  "status": true
}
FieldTypeRequiredDescription
idstringYesService identifier
statusbooleanYestrue to start, false to stop

Response 200 OK

{
  "status": true
}

Error responses

StatusCondition
400 Bad RequestMissing id or status field, body too large, or invalid JSON
404 Not FoundService ID not recognized
429 Too Many RequestsRate limit exceeded

GET /api/tempo

Returns the current tempo and beat time reference.

Response 200 OK

{
  "tempo": 128.0,
  "time_ref": 1707900000000000
}
FieldTypeDescription
temponumberCurrent tempo in BPM
time_refnumberBeat reference timestamp in microseconds since epoch

GET /api/program

Returns the active LED program and the list of available programs.

Response 200 OK

{
  "message": "Current program is 2",
  "programId": 2,
  "programs": [
    { "name": "Snakes!", "id": 0 },
    { "name": "Random data", "id": 1 },
    { "name": "Sparkles", "id": 2 },
    { "name": "Greys", "id": 3 },
    { "name": "Drops", "id": 4 },
    { "name": "Solid!", "id": 5 },
    { "name": "Fade", "id": 6 },
    { "name": "Fade Color", "id": 7 }
  ]
}
FieldTypeDescription
messagestringHuman-readable status
programIdnumberActive program ID
programsarrayAvailable LED programs with name and id

POST /api/program

Set the active LED program. The program change is broadcast to all connected Pico W devices.

Request body

{
  "programId": 3
}
FieldTypeRequiredDescription
programIdnumberYesProgram ID (0-7)

Response 200 OK

{
  "message": "Updated program to 3"
}

Error responses

StatusCondition
400 Bad RequestMissing programId field, body too large, or invalid JSON
429 Too Many RequestsRate limit exceeded

GET /api/log

Returns the server log tail as a JSON array.

Response 200 OK

[
  "2026-02-14 12:00:01 [info] Beat detected at 128.0 BPM",
  "2026-02-14 12:00:02 [info] Client registered: 192.168.1.42"
]

GET /api/devices

Returns the list of connected Pico W devices.

Response 200 OK

{
  "devices": [
    {
      "client_id": 1,
      "board_id": "E6614103E72B6A2F",
      "ip_address": "192.168.1.42",
      "last_seen": 1707900120000000
    }
  ],
  "count": 1
}
FieldTypeDescription
devicesarrayConnected device objects
devices[].client_idnumberServer-assigned client ID
devices[].board_idstringPico W unique board identifier (hex)
devices[].ip_addressstringDevice IP address
devices[].last_seennumberLast communication timestamp (microseconds)
countnumberTotal connected devices

CORS

When the server is started with --cors-origin, all API responses include:

Access-Control-Allow-Origin: <origin>
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization

OPTIONS and HEAD requests to any /api/* path return 200 OK for preflight support.


Error Format

All error responses use a consistent JSON format:

{
  "error": "Description of the error"
}