API Reference
Control Sapphire from Stream Decks, scripts, and other automation over its local REST and WebSocket API.
Base URL
The API is served by the Sapphire backend running on the same machine as the app. In development it listens on http://localhost:8000; the packaged desktop app assigns a dynamic port on launch — read it from Settings → Integrations. The examples below use the dev port.
Authentication
Every /api/control/* endpoint requires an X-API-Key header. Each session has its own key — copy or rotate it in Settings → Integrations, or fetch it programmatically. Rotate the key if it ever leaks.
# Fetch the session key (unauthenticated bootstrap)
curl http://localhost:8000/api/control/$SID/key
# Push a verse live to every display
curl -X POST http://localhost:8000/api/control/$SID/push \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"ref":"John 3:16"}'Authentication & keys
Every /api/control/* endpoint requires an X-API-Key header matching the session's key. Fetch it once, then reuse it. Non-control endpoints (/api/scripture/*) are unauthenticated on the local-trusted deployment.
/api/control/{session_id}/keyFetch (or lazily create) the API key for a session. Unauthenticated bootstrap — anyone who knows the session ID can read it.
/api/control/{session_id}/key/rotateAPI keyRotate the key. The previous key is invalidated immediately.
Verse control
Put a verse on the audience display, or read back what is currently live.
/api/control/{session_id}/pushAPI keyResolve a reference and broadcast it live to every display client. Accepts a canonical code (JHN:3:16) or free text (John 3:16).
{ "ref": "John 3:16" }/api/scripture/override/{session_id}Broadcast a manually chosen verse, honouring the session's active translation. Unauthenticated (local-trusted).
{ "reference": "John 3:16" }/api/scripture/clear/{session_id}Clear the current verse from all screens without ending the session.
/api/control/{session_id}/stateAPI keySnapshot of the session: current verse, staging queue, NDI / OSC status, and the LAN host + port for OSC controllers.
Staging queue (On Deck)
Stage verses for the operator to push, rather than going live immediately.
/api/control/{session_id}/queueAPI keyResolve a reference and add it to the On Deck queue.
{ "ref": "Romans 8:28" }/api/control/{session_id}/dismissAPI keyRemove a queued item by its ID.
{ "item_id": "..." }/api/control/{session_id}/reorderAPI keyReorder the queue. ordered_ids must list every current item ID.
{ "ordered_ids": ["...", "..."] }NDI video output
Drive the per-session NDI sender — the reserved default output OBS / vMix discovers as “Sapphire”.
/api/control/{session_id}/ndi/enableAPI keyStart the default NDI sender. Idempotent. Returns available + reason so a missing NDI runtime is explained, not silent.
/api/control/{session_id}/ndi/disableAPI keyStop the default NDI sender. Idempotent.
/api/control/{session_id}/ndi/themeAPI keyApply a theme to the NDI renderer and re-render the current verse. Pass null to clear.
Multi-output channels
Run several independent outputs per session, each with its own name, type (external browser window or ndi source), and theme.
/api/control/{session_id}/channelsAPI keyList output channels and the max-channel cap.
/api/control/{session_id}/channelsAPI keyCreate a channel. Enforces the channel cap and rejects NDI source-name collisions.
{ "name": "Foyer", "type": "ndi", "enabled": true }/api/control/{session_id}/channels/{channel_id}API keyUpdate a channel. Partial — only provided fields change.
/api/control/{session_id}/channels/{channel_id}API keyDelete a channel (the reserved default channel cannot be deleted).
OSC control surface
Toggle the global OSC server so TouchOSC / Stream Deck (via an OSC bridge) can drive Sapphire. Session ID is passed as a query parameter, not in the path.
/api/control/osc/enable?session_id={session_id}API keyStart the global OSC server (UDP, default port 8010). Idempotent.
/api/control/osc/disable?session_id={session_id}API keyStop the global OSC server. Idempotent.
WebSocket protocol
One session ID ties a host to its display clients. Message shapes are JSON; audio frames are raw binary.
/ws/stream/{session_id}HostSend raw 16 kHz PCM audio; receive transcript, scripture, suggestions, status, and tts_audio messages.
/ws/display/{session_id}DisplayRead-only: receive scripture, status, and display_clear messages.
/ws/textTextStateless — send { "text": "Turn to John 3:16" }, receive a scripture message. Useful for testing extraction without audio.
Full schema
The running backend also serves the complete machine-readable OpenAPI schema at http://localhost:8000/openapi.json — point your own tooling or a client generator at it for the exhaustive surface.