Appearance
Integration API
A versioned, read-only REST API under /integration/v1/ that lets external systems — hospital call systems, dashboards, middleware — retrieve live beacon locations and system alerts such as panic button presses.
Every SafeCall server self-hosts interactive, Swagger-UI-based documentation for this API (works offline, always matches the running server version):
- Interactive docs:
https://<your-server>/integration/docs - OpenAPI 3.1 spec:
https://<your-server>/integration/v1/openapi.json
Source of truth: server/src/integration_http.ts (handlers), server/src/integration_openapi.ts (spec), server/src/api_access.ts (api-role allowlist).
Getting access
- An administrator creates an account with the api role (admin UI → Users, or
safecall user --create). - api accounts have no web interface and can only call the endpoints below — every other endpoint returns
403. - They are system-wide: responses are not location-scoped.
Authentication
Standard JWT flow shared with the rest of the server:
bash
# 1. Log in — returns a short-lived JWT (~15 min) and a long-lived refresh token
curl -s https://<server>/login \
-H "Content-Type: application/json" \
-d '{"email": "integration@hospital.example", "password": "********"}'
# → payload.token, payload.refresh_token
# 2. Call the API with the JWT
curl -s https://<server>/integration/v1/beacons/locations \
-H "Authorization: Bearer $TOKEN"
# 3. Before the JWT expires, exchange the refresh token for a fresh one
curl -s https://<server>/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "'$REFRESH_TOKEN'"}'Endpoints
| Methods | Path | Purpose |
|---|---|---|
| GET | /integration/v1/beacons | Active trackable beacons (watch, panic, navigation, sos); optional ?type= filter |
| GET | /integration/v1/beacons/locations | Bulk snapshot: current zone, floor map, and last radio sighting per beacon |
| GET | /integration/v1/beacons/:mac/location | Same for one beacon (MAC accepted in any separator format); 404 if unknown/untrackable |
| GET | /integration/v1/alerts | Beacon events incl. panic presses; filters: since, until, status, type, after_id, limit |
| GET | /integration/v1/zones | Zone directory for resolving zone ids to physical places |
| GET | /integration/v1/openapi.json | OpenAPI spec (no auth) |
| GET | /integration/docs | Swagger UI (no auth) |
Conventions:
- All timestamps are Unix epoch milliseconds (UTC).
- Responses use the standard envelope
{ "type": "success" | "error", "message": string, "payload": { ... } }. - Locations are zone-based:
zoneis the live tracking prediction and isnulluntil the tracking engine has observed the beacon (live state resets on server restart);last_seen(radio sighting) persists independently.
Polling for alerts
Alerts have monotonically increasing ids. Remember payload.next_after_id from each response and pass it as after_id on the next poll — results are then ordered oldest-first so the cursor only advances and no alert is missed:
bash
curl -s "https://<server>/integration/v1/alerts?after_id=$LAST_SEEN_ID" \
-H "Authorization: Bearer $TOKEN"Alert status semantics:
alert— button press (single click,double click,triple click,long push (hold)) on apanicorwatchbeaconwarning— presence/motion signals (not pushed,motion)active— anything else
Extending the API
When adding an endpoint, keep three places in sync (the integration test suite enforces this):
- Handler in
server/src/integration_http.ts+ route inserver/src/routes/http.ts - Allowlist entry in
server/src/api_access.ts(api-role accounts are denied otherwise) - Path documentation in
server/src/integration_openapi.ts
Tests: server/tests/api/integration.test.ts.