| GET | /api/status | General core status fallback/read model. | Must include enough nested recorder state for legacy fallback from /api/recorder/status. Carries a recorder.perf object (or null when idle/warmup) mirroring the FPS-profiler window — framesSeen/Encoded/Muxed/Dropped, dropNoPoolSlot, dropQueueFull, p95EncodeMs, packetQueueDepthCurrent, poolAvailableCount/poolSlotCount, plus severity (good/degraded/severe/critical) and reason. Powers the stats overlay and any UI perf readout. |
| GET | /api/recorder/status | Current recorder/island/session state. | Should expose selected game, detection state, recording/paused phase, timing, terminal UI error if present. EC-286: also includes micEnabled / micMuted so the recording island reflects the live F7 mute state (the mic button previously only tracked its own click-toggles). |
| POST | /api/record/start | Start recording for the selected game. | Must enforce auth, selected-game constraints, start gates, and return stable block reasons. |
| POST | /api/record/stop | Stop current recording. | Should return success or stable denial such as not recording. |
| POST | /api/record/pause | Pause current recording. | Should return stable denial reasons when pause is not allowed. |
| POST | /api/record/resume | Resume paused recording. | Should return stable denial reasons when resume is not allowed. |
| POST | /api/overlay/toggle | Toggle recorder overlay visibility. | Should return visible state plus optional UI error directive. Legacy native-overlay control — see the overlay convergence note on /api/overlay/stats. |
| POST | /api/overlay/stats | Enable/disable the live performance HUD (FPS, bitrate, dropped frames, encode latency, queue/pool pressure). | Body { enabled: bool } → { success, enabled }. Core holds this as runtime-only state — the UI persists the showStatsOverlay preference and re-applies it on connect. The F8 hotkey toggles it at runtime; the resulting master state is reported as recorder.statsOverlayEnabled on /api/status (and /api/recorder/status) and as overlaysEnabled on /api/overlay/alt-held so the overlay reconciles instantly. F8 is the default but is now a configurable chord (toggle_overlay on /api/hotkeys, EC-475); it still registers best-effort and yields to the recording chords if it collides with one. Overlay convergence (now the default): the native Direct2D HUDs (stats / mic / GPU / preflight / game card) are suppressed and the cross-platform Electron overlay renders these widgets instead; F8 now shows/hides the whole Electron overlay (not just the stats HUD). Set PLAYROLL_LEGACY_OVERLAY=1 to fall back to the native HUDs (Windows only, for diagnosis). |
| GET | /api/overlay/alt-held | Fast overlay poll (~120 ms) that drives the Electron overlay. | Auth-gated. Returns { held, mic?: { level, muted, enabled }, game?: { focused, rect: { x, y, width, height } }, overlaysEnabled }. held is the global Alt-key state (GetAsyncKeyState, focus-independent) powering the overlay's Alt-hold-to-edit gesture while a game is foreground; mic drives the smooth VU meter; game.rect/focused position the transparent host window over the game; overlaysEnabled mirrors the F8 master state for an instant show/hide. Deliberately tiny (atomic reads only) — polled only while the overlay is on screen. Note: per-game gameSlug and the GPU/perf figures are not here — they ride /api/status's recorder + recorder.perf. |
| GET | /api/uploader/status | Uploader state and pending files. | Should include paused/uploading state, current file, progress, pending count, and last error when available. |
| GET | /api/uploader/history | Activity/history rows. | Must preserve row id and session identity separately. recording_session groups MP4 + CSV + JSON rows; session_id is legacy/internal-compatible. Failed rows need reason/error. EC-286: also returns rows with status held (manual-upload mode, kept on device) and per-row has_mic_audio / has_transcript flags (derived from the files on disk) so the UI gates the per-row "Transcribe" / "Review" actions. |
| POST | /api/uploader/action | Uploader command such as scan/pause/resume. | Must return accepted action and stable failure reason. |
| GET / PUT | /api/uploader/auto | EC-286: read/write the auto-upload toggle. | Backed by the auto_upload_enabled app setting. GET → { enabled }; PUT body { enabled } → { success, enabled }. Absent setting reads as true, so existing installs keep auto-uploading after upgrade. When false, finished recordings are held and transcription becomes on-demand. |
| POST | /api/uploader/release | EC-286: release held files into the upload pump. | Body { sessionId? } — release one recording, or omit (or "*") to release all held files ("Upload all"). Flips held → pending and wakes the pump. Response { success, released }. |
| GET | /api/environment/check | Blocking/warning environment checks. | Warning/blocker codes must be stable; UI may suppress known codes like multi-GPU. |
| GET | /api/environment/adapter | Hardware adapter snapshot (vendor, GPU name, NVENC driver). | Used by the onboarding system-check step to render a precise driver-version prompt. |
| GET | /api/hw/snapshot | Canonical HW snapshot — system (CPU/RAM/OS) and gpus[] (vendor/device/driver/VRAM). | Same payload the core writes into every recording's _meta.json::hardware. Consumed by the in-app bug-report flow; one schema across recording metadata, bug reports, and the device_hw_snapshots inventory. |
| GET | /api/settings | Read core settings. | Response should be tolerant to missing fields but stable for saved settings. |
| PUT | /api/settings | Update core settings. | Must merge without dropping unrelated settings. |
| GET | /api/sound-cues | Read sound cue bindings. | Snapshot should be deterministic and include enabled state per cue. |
| PUT | /api/sound-cues | Save sound cue bindings. | Must validate cue ids and file paths. |
| POST | /api/sound-cues/preview | Preview a sound cue. | Must not persist state. |
| GET | /api/audio/devices | Enumerate active mic (eCapture) endpoints. | Each entry has id, name, isDefault, sampleRate, channels. The default-communications endpoint is flagged so the UI can mark it. |
| GET | /api/audio/mic-config | Read mic recorder configuration. | Response shape: { deviceId, enabled, muted, aacBitrateBps }. deviceId empty string ⇒ default communications endpoint. |
| POST | /api/audio/mic-config | Partial-update mic recorder config. | Any subset of the four fields can be sent. muted applies immediately; deviceId change applies on the next recording session start. EC-263: flipping enabled to true is gated by the privacy gate — rejected with HTTP 403 + { success: false, reason: "MIC_PRIVACY_GATE_BLOCKED", message, config } when the local HW can't run on-device transcription. The current core-side config is returned in config so the caller can re-sync. |
| GET | /api/audio/mic-meter | Live VU level for the settings UI. | Short-poll JSON { level, running } with level peak-normalised to [0, 1]. UI polls at ~100 ms while the settings panel is open. |
| POST | /api/audio/mic-test | Record a short test clip to a temp .aac. | Body: { seconds } (1..30, default 5). Response: { success, path, seconds }. Force-enables the mic for the duration of the test even when enabled=false. Rejects with 409 if a real recording session is active. |
| GET | /api/transcribe/privacy-gate | Cached EC-263 privacy-gate verdict. | Response: { supported, reason, hw: { gpuVendor, gpuVramMb, totalRamMb } }. reason codes: OK, NO_NVIDIA_GPU, INSUFFICIENT_VRAM, INSUFFICIENT_RAM, NO_MODEL_FOR_TIER, REGISTRY_EMPTY, PRIVACY_GATE_UNAVAILABLE. The verdict is cached at cpp startup and is the source of truth for whether the mic toggle is allowed. |
| GET | /api/transcribe/recommended | Recommended Whisper model for current HW. | Response: { supported, modelId, backend, sizeBytes, tier, reason, hw }. supported=false for non-NVIDIA HW. |
| GET | /api/transcribe/models | Full bundled model catalog with per-entry install/download state. | Each entry: { id, family, filename, url, sha256, sizeBytes, tier, requirements: { minVramMb, minRamMb }, metrics: { werEnPct, approxRtfCuda }, installed, progress? }. |
| POST | /api/transcribe/download | Enqueue a model download. | Body: { modelId }. Response: { success, modelId, status } where status is started / already_queued / already_in_progress / already_installed. WinHTTP Range resume + sha256 verify + atomic .part → .bin promotion. |
| DELETE | /api/transcribe/model/:id | Uninstall a previously-downloaded model. | Removes the .bin + sidecar from disk; future downloads will re-fetch. |
| GET | /api/transcribe/models-path | Current models folder. | Response: { path, isDefault }. Default: %LOCALAPPDATA%\\Playroll\\models. Persisted in app_settings.transcription.models_path. |
| POST | /api/transcribe/models-path | Change the models folder. | Body: { path, moveExisting }. Cross-volume copy+delete fallback when moveExisting=true. Response: { success, outcome: { previousPath, newPath, movedCount, skippedCount, errors[] } }. |
| GET | /api/transcribe/jobs | Recent transcription queue snapshot (EC-264). | Response: { jobs: [{ id, sessionId, micPath, transcriptPath, modelId, status, attempts, enqueuedAtMs, startedAtMs, finishedAtMs, errorMessage, progressPercent }] }. Ordered DESC by enqueuedAtMs. status ∈ pending/in_progress/done/failed. Consumed by the launcher footer's TranscriptionStatusBadge (EC-265). EC-286: progressPercent now advances during inference (whisper decode progress mapped into the 20→90 band) instead of stalling at the post-decode value. |
| POST | /api/transcribe/run | EC-286: on-demand transcription for one session (manual-upload mode). | Body { sessionId } (the sessions.id PK). Resolves the session's mp4/_mic.aac and enqueues a job (upsert on session_id, so it is re-runnable after a prior done/failed). Response { sessionId, jobId }; errors: SESSION_NOT_FOUND / MP4_NOT_FOUND / MIC_AUDIO_NOT_FOUND / ENQUEUE_FAILED. |
| POST | /api/transcribe/file | EC-317: synchronous onboarding self-test — transcribe an arbitrary audio file (the mic-test clip) and return the transcript inline. | Body { path, language? } (language empty / omitted = auto-detect). Resolves the recommended installed model, runs the isolated child process (so a CUDA/ggml abort can't take down core), and blocks for the short inference. Success: { success: true, transcript: { schema_version, language, duration_seconds, segments: [{ id, start, end, text, confidence }], text, … } }. Failure: HTTP 422 { error, errorCode? } (errorCode ∈ MODEL_NOT_INSTALLED / INSUFFICIENT_VRAM / …). Unlike /run, this does not touch the SQLite job queue and uses a synthetic session_id of "selftest". |
| POST | /api/lobby/set | Mirror the active multi-POV lobby on core. | Body: { lobby_id, lobby_code, game_slug? }. Regex-validates UUID / 6-char [A-Z0-9] / kebab-case slug. See Lobby Mode. |
| POST | /api/lobby/clear | Drop the active lobby on core. | No body. |
| GET | /api/lobby/status | Read the active lobby. | Always 4 keys; identifier fields are empty strings when active=false. |
| GET | /api/encoders | Read available encoders. | Should include selected encoder and unavailable reasons. |
| POST | /api/encoders/select | Select encoder. | Must reject unavailable encoders with stable reason. |
| GET | /api/monitor/targets | Read game/process monitor targets. | Should reflect installed games known to core and selected-game constraints. |
| PUT | /api/monitor/targets | Replace/sync monitor targets. | Must be machine-independent and avoid hardcoded local paths. |
| POST | /api/monitor/rescan | Force monitor target rescan. | Should be idempotent and safe while UI is open. |
| PUT | /api/monitor/selection | Set selected game. | Switching selection must release monitors for the previous selected game. |
| POST | /api/settings-enforcement/apply | Apply per-game settings enforcement. | Should scope to the selected game/store id. |
| POST | /api/settings-enforcement/restore | Restore settings after a session. | Must be safe to call if nothing was applied. |
| GET | /api/settings-enforcement/status | Read enforcement status, optionally per game. | Supports query by game_store_id. |
| PUT | /api/settings-enforcement/sync-targets | Sync settings-enforcement targets. | Must stay aligned with monitor targets and selected game. |
| POST | /api/debug/toast | Dev/debug notification cycle. | Debug route; should remain non-player behavior. |
| POST | /api/debug/overlay/cycle | Dev/debug overlay cycle. | Debug route; should remain non-player behavior. |