Skip to content

Latest commit

 

History

History
69 lines (57 loc) · 3.59 KB

File metadata and controls

69 lines (57 loc) · 3.59 KB

The SUB/WAVE API

SUB/WAVE exposes a large HTTP API, an MCP server, Icecast stream mounts, and outbound webhooks. The easiest way to discover and try all of it is the built-in Connect page.

Connect (admin → Connect)

Sign into the admin panel and open Connect (/admin/connect). It has four tabs:

  • Endpoints — the curated integration subset of the HTTP API, grouped and searchable. Each endpoint expands to its description, parameters, a sample response, a Copy as curl button, and an inline playground that fires the real request against this station (admin auth is handled for you). Endpoints that change the live broadcast are flagged on-air and ask for confirmation before sending.
  • MCP — connect an agent (Claude Code, Claude Desktop, any MCP client) to the station's 17 MCP tools. The controller serves MCP over HTTP at /api/mcp, so the tab gives a copy-ready claude mcp add --transport http … command with this station's URL — no clone, no local process. A stdio setup is offered as the local-only alternative.
  • Integrations — the stream URLs (with live on/off state per mount), now-playing feeds, and paste-ready recipes for Music Assistant and Home Assistant.
  • Webhooks — the push direction: register outbound HTTP POSTs that fire on station events (track changes, requests, on-air segments), with every payload shape documented.

Building a public station page

The unauthenticated reads are enough to render a full programming guide without an admin credential:

  • GET /schedule — show definitions, the 7×24 grid, and a persona index (id, name, tagline, avatar). Each show carries personaId for its host and guestPersonaIds for its co-hosts; both are ids you join against that index, and both are resolved against the live roster, so a persona deleted after the show was saved simply drops out.
  • GET /personas — the same persona index on its own, for a "meet the DJs" page that doesn't need the week grid.
  • GET /dj — who is on air right now (a scheduled show can put someone other than activePersonaId behind the mic).
  • GET /now-playing — the current track, plus context.activeShow with the live show's host and guests already hydrated.

Persona souls are opt-in. A persona's soul is its system prompt rather than a written bio, so the roster-wide reads above publish it only when the operator turns on Settings → Station → Public API → publish persona souls. Off (the default), the field is absent rather than empty — both /schedule and /personas report which mode you're in via soulsPublished, so a client can hide the bio column instead of rendering blank cards. tagline is the field intended for public display and is always present. GET /dj publishes the on-air persona's soul regardless, as it always has.

OpenAPI

The Connect page's Download OpenAPI button (and GET /api/connect/openapi.json, admin-gated) returns an OpenAPI 3.1 document generated from the same catalog. Import it into Postman/Insomnia or use it for client codegen.

Where the catalog lives

The documented surface is a single hand-curated manifest in the controller: controller/src/connect/catalog.ts. A drift guard (npm run test:connect in controller/) asserts every documented endpoint still resolves to a real Express route, so the explorer can't rot. To document a new endpoint, add an entry there — the admin page, the OpenAPI export, and the test all pick it up.