API
The API is defined by the contract repository freedome_contract v1.0.0-rc.1 (pinned in this repo under
fixtures/contract/, see fixtures/contract/PIN). The server serves the contract documents themselves, so names and
shapes cannot drift.
| Transport | Endpoint | Contract source |
|---|---|---|
| REST | /api/v1/*; OpenAPI at /api/v1/openapi.json; Swagger UI /api/docs |
openapi/mediaserver.yaml |
| GraphQL | POST / GET /api/v1/graphql; subscriptions over graphql-transport-ws (and legacy graphql-ws) on the same path |
graphql/mediaserver.graphql |
| WebSocket | GET /api/v1/ws, sub-protocol freedome.v1 |
asyncapi/ws.yaml |
| socket.io | path /socket.io/, namespace /v1 (EIO v4) |
asyncapi/socketio.yaml |
| OSC | UDP / TCP 7000, replies 7001 | osc/addresses.yaml — see OSC |
| gRPC | unix:///run/freedome/mediaserver.sock, optional TCP 50062 |
proto/mediaserver/freedome/mediaserver/v1/mediaserver.proto (this repo) |
| Health | /health, /ready, /metrics (Prometheus, freedome_mediaserver_*) |
— |
Authentication
Section titled “Authentication”Authorization: Bearer <token> where the token is an API key fdk_<id>_<secret> (POST /api/v1/api-keys), a local
session JWT (POST /api/v1/auth/session, refresh with rotation) or a cloud token exchanged at
POST /api/v1/auth/token-exchange. Apps pair with a 6-digit code (POST /api/v1/auth/pairings, approved by an
operator). Roles: guest, operator, admin, superadmin = scope bundles; every operation declares its scope in the
OpenAPI. WebSocket: hello.token, the Authorization header or ?access_token=; socket.io: auth: {token}; GraphQL
WS: connection_init.payload.authorization; gRPC: bearer metadata, Unix peer credentials or mTLS; OSC: no tokens —
per-listener CIDR allow-list and role.
One operation, every transport
Section titled “One operation, every transport”WebSocket call, socket.io call, GraphQL mutations, gRPC OperationsService.Call and OSC addresses run the same
REST operation (operationId) in-process: same scopes, validation and errors. Errors are RFC 9457 problem objects
(application/problem+json, code from the contract catalogue) and are carried as GraphQL extensions.problem,
WS / socket.io error, gRPC status + freedome-problem-bin trailer, OSC /freedome/v1/error ,sss.
Events
Section titled “Events”One topic tree (events/topics.yaml): venues/{v}/players/{p}, venues/{v}/output, venues/{v}/displays/{d},
venues/{v}/calibration/jobs/{j}, assets/{a}, shows/{s}, engines/{name} (visual@node-1 on multi-node
installations), system/health, … Subscriptions accept + / # wildcards. Every event has a monotonically
increasing seq; clients resume with sinceSeq (ring buffer 10 000 events / 10 min, then resync). History:
GET /api/v1/events?topics=…&sinceSeq=….
Uploads
Section titled “Uploads”Large media use tus 1.0 at /api/v1/uploads (chunks ≤ 95 MB, resumable, sha256 checksums), then
POST /api/v1/assets {uploadId}. Simple multipart upload is accepted up to 100 MB.