REST API Reference
Comprehensive REST API documentation for host administration, scoped API tokens, telemetry, and self-updater.
Authentication & Scoped Tokens#
All API endpoints require authentication using Basic Auth (admin credentials) or Scoped Bearer Tokens via the Authorization: Bearer <token> header.
State-changing requests (POST, DELETE) from browser clients validate CSRF tokens via X-CSRF-Token. Non-browser API clients (curl, scripts, Home Assistant) are exempt from CSRF checks.
Scoped API Tokens Endpoints#
Mint, list, and revoke automation tokens. The plaintext token is returned only on create.
/api/tokensList active automation tokens with assigned scopes (hashes omitted).
Scopes: tokens:manage
Response Example
{
"status": true,
"status_code": 200,
"tokens": [
{
"name": "home-assistant",
"scopes": ["stream:control", "logs:get"]
}
]
}Stream Telemetry & Adaptive Bitrate#
Host-side latency, bitrate bounds, client network feedback, and error counters.
/api/stream/latencyHost-side latency breakdown in milliseconds.
Response Example
{
"status": true,
"capture_ms": { "min": 0.8, "max": 2.1, "avg": 1.1, "samples": 300 },
"encode_ms": { "min": 1.2, "max": 3.4, "avg": 1.8, "samples": 300 }
}Host Self-Updater Endpoints#
Linux in-app updater. Active streams block apply until idle unless forced.
/api/updateQuery updater state, progress, and release notes.
Game Scanner & Health Check#
/api/games/scanScan host for Steam, Lutris, and Heroic installed games.
Response Example
[
{
"name": "Hades",
"path": "/home/user/.steam/steam/steamapps/common/Hades/Hades",
"launcher": "steam"
}
]/api/healthHealth check endpoint for container orchestrators and load balancers.
Response Example
{
"status": "ok",
"status_code": 200,
"version": "2026.909.1",
"uptime": 3600
}Transport, auth & envelopes#
Base URL is https://<host>:47990/api/... — the Web UI port is the GameStream port (default 47989) plus one, and port is configurable. TLS uses the configured cert/pkey pair (self-signed by default; pass -k/--insecure to curl or install a trusted cert). Every JSON response carries Strict-Transport-Security, X-Frame-Options: DENY, and frame-ancestors none. Success envelope is {status: true, status_code: 200, ...}; failures are {status: false, status_code, error} with 400 validation, 401 unauthenticated (+ WWW-Authenticate: Basic realm="Sunshine Gamestream Host"), 403 wrong scope / origin / CSRF, 404 unknown path, 413 bodies over 1 MiB, 429 rate-limited. Auth tries Authorization: Bearer <64-hex-token> first (SHA-256 of plaintext:salt vs api_tokens entries), then HTTP Basic (always full admin, bypasses scopes). A * token is admin. Full scope vocabulary: config:get, config:set, apps:get, apps:launch, apps:close, clients:list, clients:pair, clients:unpair, logs:get, display:reset, tokens:manage, *. Login failures are bucketed per IP (10 fails / 30 s → 429); success resets. Mutating browser calls need X-CSRF-Token (or ?csrf_token=); mint one via GET /api/csrf-token (1 h TTL, per client id). Same-origin and origin-allowlisted (csrf_allowed_origins plus auto localhost) calls skip the token; curl/scripts with no Origin/Referer are exempt.
curl -ku admin:pass https://localhost:47990/api/config | jq .version
TOK=sf_hex_here
curl -sk -H "Authorization: Bearer $TOK" https://localhost:47990/api/sessions?limit=5 | jq .
CSRF=$(curl -sk -u admin:pass https://localhost:47990/api/csrf-token | jq -r .csrf_token)
curl -sk -u admin:pass -H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' -d '{}' https://localhost:47990/api/config -w '%{http_code}\n'Apps, covers, browser & game scanner#
/api/appsReturn the apps.json catalog as {apps[]}. An empty file yields {apps:[]}.
/api/appsCreate (index -1) or update (index N) an app: {name, output, cmd, index, exclude-global-prep-cmd, elevated, auto-detach, wait-all, exit-timeout, prep-cmd[{do, undo, elevated}], detached[], image-path}.
/api/apps/{index}Delete the app at numeric index. Path regex only matches digits.
/api/apps/closeTerminate the running streamed process.
/api/covers/{index}Return image/png artwork for the app index. 404 when none is set.
/api/covers/uploadUpload artwork as {key, url|data}. Key must not contain /../ or NUL; url host must be images.igdb.com, otherwise send base64 data. Saved to appdata/covers/<key>.png.
/api/browseBrowse host paths: ?path=&type=directory|executable|file|any returns {path, parent, entries[{name, path, type}]}. Empty path lists / (Linux) or drives (Windows). Combine with least-privilege tokens and origin_web_ui_allowed to limit exposure.
Clients & pairing#
/api/clients/listList paired clients as {status, named_certs[]}.
/api/clients/unpairUnpair one client: {uuid}.
/api/clients/unpair-allErase all pairings and terminate running sessions.
/api/clients/updateEnable or disable a cert: {uuid, enabled}. Disabling kills that client sessions.
/api/pinPair with the Moonlight PIN: {pin: 0000-9999, name}. Returns {status}.
/api/passwordSet credentials: {currentUsername, currentPassword, newUsername, newPassword, confirmNewPassword}. First-run with no username set is unauthenticated and redirects to /welcome otherwise.
Config, logs & system#
/api/configDump effective config: {status, platform, version, ...sunshine.conf vars plus solarflare audio_fx/headless/adaptive/trusted defaults}.
/api/configWrite {key: value} pairs. Arrays, scalars, or empty objects are rejected with 400 (they would wipe the file); write failures return {status: false, error}.
/api/configLocaleReturn {status, locale} for the Web UI boot path.
/api/logsReturn text/plain host logs (not JSON).
/api/csrf-tokenMint a CSRF token: {csrf_token} (32 random bytes, 1 h TTL).
/api/stream/telemetryHost resource monitor: {status, status_code, telemetry{host_cpu_pct[], host_gpu_pct[], host_ram_used_mb[], window_s}}. Non-Linux returns window_s only.
/api/sessionsSession history with ?limit=100&app=&client=. Records match webhook payloads minus the event wrapper.
/api/reset-display-device-persistenceReset Windows display-device persistence. Windows-only.
/api/restartRestart the host process. May not return a body.
/api/vigembus/statusViGEmBus driver state: {installed, version, version_compatible, packaged_version}. Non-Windows returns error with empty values.
/api/vigembus/installRun vigembus_installer.exe /quiet. Non-Windows returns {status: false, error}.
Webhook payloads#
On stream start/stop SolarFlare POSTs application/json to every webhook_url_N (http(s) only, 5 s connect/timeout, 2 retries with backoff, no retry on 4xx). With webhook_secret set, each request carries X-Solarflare-Signature: sha256=HMAC(secret, body). Body: {event: stream.start|stream.end, t_start, t_end, app_name, client_name, client_address, codec, width, height, fps, avg_bitrate_kbps, avg_rtt_ms, avg_encode_ms, dropped_frames, error}. Identical to GET /api/sessions items except for the event wrapper — verify the HMAC before acting on callbacks.