Files
CartoLite-Server/docs/public-api.md
T

79 lines
3.0 KiB
Markdown

# Public API v2
All endpoints are public and intentionally sanitized. State responses use `Cache-Control: no-store`.
## Endpoints
- `GET /healthz` reports process liveness and build identity.
- `GET /readyz` succeeds only when checkpoint state is healthy, MQTT is connected and subscribed, the ingest queue is healthy, and no packets have been dropped. Normal RF silence remains ready.
- `GET /api/state` returns the authoritative `StateV2` snapshot.
- `GET /api/events?bootId=<boot>&after=<seq>` is a same-origin `text/event-stream` with 15-second keepalives. It replays a bounded sequence window before switching to live events; `Last-Event-ID` is honored on native reconnects. An expired cursor, changed boot, or retention-pruned topology receives `reset` and must rehydrate from `/api/state`.
## State schema
```ts
type StateV2 = {
schemaVersion: 2;
bootId: string;
seq: number;
serverTime: number;
status: {
feed: "connected" | "disconnected";
activity: "active" | "quiet";
lastPacketAt?: number;
dropped: number;
version: string;
gitSha: string;
};
map: { center: [0, 20]; zoom: 1.4 };
nodes: NodeV2[];
routes: RouteV2[];
};
type NodeV2 = {
id: string;
label: string;
role: "repeater" | "companion" | "room_server" | "sensor" | "unknown";
observer: boolean;
lat: number;
lng: number;
lastSeen: number;
};
type RouteV2 = {
id: string;
fromId: string;
toId: string;
packetCount: number;
lastHeard: number;
intensity: 0 | 1 | 2 | 3 | 4;
lastKind: "Advert" | "Trace" | "Text" | "ACK" | "Control" | "Other";
traffic: number;
};
```
Every `fromId` and `toId` references one node in the same snapshot. Endpoint labels and coordinates are not duplicated on routes. `lastKind` is the single sanitized kind from the newest packet observed on the route. `traffic` is a bounded activity score measured at `lastHeard`; clients decay it with a 15-minute half-life. It is not packet history or a per-kind counter. Routes older than 24 hours are omitted.
## Event stream
Event names are `hello`, `node`, `packet`, `status`, and `reset`. State-changing events carry the increasing sequence as their SSE `id`; `hello` deliberately has no SSE ID so a disconnect cannot skip its following replay.
Route packet events use the same normalized identifiers:
```ts
type RoutePacketEventV2 = {
seq: number;
id: string;
at: number;
payloadType: "Advert" | "Trace" | "Text" | "ACK" | "Control" | "Other";
mode: "route";
segments: Array<{ routeId: string; fromId: string; toId: string }>;
};
```
Observer packet events contain one sanitized `{ id, label, lat, lng }` point instead of `segments`. No event contains message content, public keys, raw paths, packet hashes, credentials, or resolver details.
## Compatibility
Schema v2 intentionally replaces the embedded `route.from` and `route.to` objects from v1. Clients must reject unknown `schemaVersion` values. Additive fields may appear within v2; removing or changing an existing field requires another schema version.