Unified REST API for all SpaceMusic services.


Overview

The API gateway at api.spacemusic.tv is a custom SvelteKit application that provides a single REST interface to all SpaceMusic backend services. It proxies requests to LiveKit, MinIO, Centrifugo, Authentik, Grafana, and Kuvasz, handling authentication, rate limiting, and CORS.

Stack: SvelteKit 2.x (adapter-node), shadcn-svelte, Tailwind CSS v4

Deployment: Docker Compose + GitHub Actions SSH (migrated from devpush to standalone Docker for stable container hostname and internal service communication)

Authentication

The API supports three authentication methods:

  1. SSO headers -- When accessing via browser, Traefik forwards X-authentik-username headers from Authentik. Used by the dashboard UI.
  2. API key -- X-API-Key header or ?api_key= query parameter. Manage keys at api.spacemusic.tv/keys.
  3. Bearer token -- Authorization: Bearer <token> validated against Authentik's user API.

Public endpoints (no auth required): GET /api/health, GET /api/openapi.json, GET /api/monitor/status

Endpoints

52 endpoints across 8 service groups:

Service Base Path Endpoints Technology
Stream /api/stream/* 12 LiveKit
Storage /api/storage/* 7 MinIO
Relay /api/relay/* 8 Centrifugo
Auth /api/auth/* 10 Authentik
Dashboards /api/dashboard/* 6 Grafana
Monitor /api/monitor/* 7 Kuvasz
Connect /api/connect/* -- Node-RED (stub, 501)
Data /api/data/* -- SpacetimeDB (stub, 501)

Stream Endpoints

Method Path Purpose
GET /api/stream/rooms List active rooms
POST /api/stream/rooms Create room
GET /api/stream/rooms/{name} Room detail + participants
DELETE /api/stream/rooms/{name} Delete room
GET /api/stream/rooms/{name}/participants List participants
POST /api/stream/tokens Generate LiveKit JWT
GET /api/stream/ingress List ingress streams
POST /api/stream/ingress Create ingress (RTMP/WHIP/URL)
DELETE /api/stream/ingress Delete ingress
GET /api/stream/egress List egress (recordings)
POST /api/stream/egress Start recording/restream
DELETE /api/stream/egress Stop egress

Storage Endpoints

Method Path Purpose
GET /api/storage/buckets List all buckets
GET /api/storage/buckets/{bucket} Check bucket exists
GET /api/storage/buckets/{bucket}/objects List objects
GET /api/storage/buckets/{bucket}/objects/{key} Download object
PUT /api/storage/buckets/{bucket}/objects/{key} Upload object
DELETE /api/storage/buckets/{bucket}/objects/{key} Delete object
POST /api/storage/presigned Generate presigned URL

Relay Endpoints

Method Path Purpose
POST /api/relay/publish Publish to a channel
POST /api/relay/broadcast Publish to multiple channels
GET /api/relay/channels List active channels
GET /api/relay/channels/{channel}/presence Connected clients
GET /api/relay/channels/{channel}/history Message history
DELETE /api/relay/channels/{channel}/history Clear history
POST /api/relay/tokens Generate JWT token
GET /api/relay/info Server node info

Auth Endpoints

Method Path Purpose
GET /api/auth/me Current user profile
GET /api/auth/users List users
POST /api/auth/users Create user
GET /api/auth/users/{id} Get user
PATCH /api/auth/users/{id} Update user
DELETE /api/auth/users/{id} Delete user
GET /api/auth/groups List groups
POST /api/auth/groups Create group
GET /api/auth/tokens List API tokens
POST /api/auth/tokens Create API token

Dashboard Endpoints

Method Path Purpose
GET /api/dashboard/dashboards Search dashboards
GET /api/dashboard/dashboards/{uid} Get dashboard JSON
GET /api/dashboard/alerts List alert rules
GET /api/dashboard/annotations List annotations
POST /api/dashboard/annotations Create annotation
POST /api/dashboard/query Proxy datasource query

Monitor Endpoints

Method Path Purpose
GET /api/monitor/monitors List HTTP monitors
POST /api/monitor/monitors Create monitor
GET /api/monitor/monitors/{id} Get monitor + stats
PATCH /api/monitor/monitors/{id} Update monitor
DELETE /api/monitor/monitors/{id} Delete monitor
GET /api/monitor/heartbeats/{id} Uptime event history
GET /api/monitor/status Public status page data

Response Format

All endpoints use a consistent envelope:

// Success
{ "data": { ... }, "error": null }

// Error
{ "data": null, "error": { "code": "ROOM_NOT_FOUND", "message": "...", "status": 404 } }

Interactive Docs

Full interactive API documentation is available at api.spacemusic.tv/docs with a Stripe-style two-column layout. Each endpoint includes parameter tables, curl examples, and a "Try It" panel for live request execution.

The OpenAPI 3.1 specification is available at api.spacemusic.tv/api/openapi.json.

Rate Limiting

In-memory sliding window: 100 requests per 60 seconds per identity. Returns 429 Too Many Requests with Retry-After header. Public endpoints are exempt.

CORS

Allows requests from *.spacemusic.tv and localhost (any port). OPTIONS returns 204 with a 24-hour Access-Control-Max-Age.

Monitoring

Structured JSON request logs go to stdout and are scraped by Loki. The "API Gateway" Grafana dashboard (uid: api-gateway) shows health status, container metrics, and request logs.