Coop API reference

REST + SSE, fully documented

Coop serves plain JSON over HTTP plus one Server-Sent Events stream. Perch is just its best-known client — everything below is fair game for your own scripts and tools. Base URL in a default install: http://127.0.0.1:2667.

Authentication model

Read endpoints

EndpointReturns
GET /api/bootstrapEverything for first paint: device, full node roster, recent packets/messages/signal, port counts, waypoints, home, server time.
GET /api/streamSSE live feed — see events below.
GET /api/healthKPIs: link status, node/packet counts, rate, MQTT stats, capture-DB stats. Includes "engine":"coop" so probes can identify a real Coop.
GET /api/counts?window=SECSWindowed packet/message/active-node counts (DB-backed when capture is on — full history, not just memory).
GET /api/dbCapture stats: rows, size, span, path — or {"enabled":false}.
GET /api/db/configCapture settings (enabled, path, retention, platform default path).
GET /api/serialportsVisible serial ports (for connect UIs).
GET /api/mqttObserver status + rx/decoded/decrypt-fail counters.
GET /api/channels/export, GET /api/qrCurrent channel set as URL / QR.
GET /api/weatherLocal weather for home (Open-Meteo, cached, keyless).
GET /api/clubsKnown community MQTT presets.

Write endpoints

EndpointDoes
POST /api/sendTransmit text. {"text","dest","channel","wantAck","emoji","replyId"} — dest empty/omitted broadcasts; emoji:1 + replyId is a tapback. Returns the packet id for delivery tracking. 233-byte payload cap.
POST /api/tracerouteRoute discovery to a node — hop chain with per-link SNR, both directions. Takes up to a minute; see Mesh services.
POST /api/request_positionAsk a node for a fresh fix: {"dest":"!id"}.
POST /api/config/ownerSet node long/short name.
POST /api/config/loraRegion / modem preset (reboots the radio).
POST /api/channels/importApply a channel URL (reboots the radio).
POST /api/db/configCapture settings: {"enabled","dbPath","retentionDays"} — applies live, persists to coop.json.
POST /api/clubs/joinRe-point the MQTT observer at a club.

The SSE stream

One connection, JSON frames {"type", "data", "t"}:

typedata
packetEach decoded packet (portnum, from/to, SNR/RSSI, text if any, source mqtt when observed).
messageNew chat message (rx and your own tx echoes).
msgstatusDelivery updates for sent messages: sent → delivered / failed / no-ack.
nodeRoster upsert — names, position, telemetry, neighbors as they're learned.
deviceYour radio's state (connection, config, battery…).
waypointsFull current list of mesh-shared waypoints whenever it changes.
# watch your mesh from a terminal
curl -N http://127.0.0.1:2667/api/stream

# send to the primary channel
curl -X POST http://127.0.0.1:2667/api/send \
  -H 'Content-Type: application/json' -d '{"text":"hello from the API"}'

# remote, with a control key
curl -X POST https://coop.example.ts.net/api/send \
  -H 'X-Coop-Key: my-secret' -d '{"text":"hi"}'

/api/connect and /api/wifi currently answer with a friendly "not implemented yet" — transport switching and WiFi provisioning from the API are on the roadmap.