End of life — September 2026. SolarFlare is no longer maintained and this site is kept for reference only. No further releases, updates, bug fixes, or security patches will be published. Users are encouraged to migrate to Slipstream, the successor project, which remains actively maintained.

On this page
Developer & APIREST API

REST API Reference

Comprehensive REST API documentation for host administration, scoped API tokens, telemetry, and self-updater.

9 min readUpdated August 2026

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.

GET/api/tokens
Auth: Admin or tokens:manage

List active automation tokens with assigned scopes (hashes omitted).

Scopes: tokens:manage

Response Example

json
{
  "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.

GET/api/stream/latency
Auth: logs:get

Host-side latency breakdown in milliseconds.

Response Example

json
{
  "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.

GET/api/update
Auth: config:get

Query updater state, progress, and release notes.

Game Scanner & Health Check#

GET/api/games/scan
Auth: apps:get scope

Scan host for Steam, Lutris, and Heroic installed games.

Response Example

json
[
  {
    "name": "Hades",
    "path": "/home/user/.steam/steam/steamapps/common/Hades/Hades",
    "launcher": "steam"
  }
]
GET/api/health
Auth: Unauthenticated

Health check endpoint for container orchestrators and load balancers.

Response Example

json
{
  "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.

bash
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#

GET/api/apps
Auth: apps:get

Return the apps.json catalog as {apps[]}. An empty file yields {apps:[]}.

POST/api/apps
Auth: config:set + CSRF, Content-Type: application/json

Create (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}.

DELETE/api/apps/{index}
Auth: config:set + CSRF

Delete the app at numeric index. Path regex only matches digits.

POST/api/apps/close
Auth: apps:close + CSRF

Terminate the running streamed process.

GET/api/covers/{index}
Auth: apps:get

Return image/png artwork for the app index. 404 when none is set.

POST/api/covers/upload
Auth: config:set

Upload 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.

GET/api/browse
Auth: config:get

Browse 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#

GET/api/clients/list
Auth: clients:list

List paired clients as {status, named_certs[]}.

POST/api/clients/unpair
Auth: clients:unpair + CSRF + JSON

Unpair one client: {uuid}.

POST/api/clients/unpair-all
Auth: clients:unpair + CSRF

Erase all pairings and terminate running sessions.

POST/api/clients/update
Auth: admin + CSRF + JSON

Enable or disable a cert: {uuid, enabled}. Disabling kills that client sessions.

POST/api/pin
Auth: clients:pair + CSRF + JSON

Pair with the Moonlight PIN: {pin: 0000-9999, name}. Returns {status}.

POST/api/password
Auth: admin + CSRF + JSON (unauth on first run)

Set credentials: {currentUsername, currentPassword, newUsername, newPassword, confirmNewPassword}. First-run with no username set is unauthenticated and redirects to /welcome otherwise.

Config, logs & system#

GET/api/config
Auth: config:get

Dump effective config: {status, platform, version, ...sunshine.conf vars plus solarflare audio_fx/headless/adaptive/trusted defaults}.

POST/api/config
Auth: config:set + CSRF, JSON object only

Write {key: value} pairs. Arrays, scalars, or empty objects are rejected with 400 (they would wipe the file); write failures return {status: false, error}.

GET/api/configLocale
Auth: Unauthenticated

Return {status, locale} for the Web UI boot path.

GET/api/logs
Auth: logs:get

Return text/plain host logs (not JSON).

GET/api/csrf-token
Auth: Any authenticated caller

Mint a CSRF token: {csrf_token} (32 random bytes, 1 h TTL).

GET/api/stream/telemetry
Auth: logs:get

Host resource monitor: {status, status_code, telemetry{host_cpu_pct[], host_gpu_pct[], host_ram_used_mb[], window_s}}. Non-Linux returns window_s only.

GET/api/sessions
Auth: logs:get

Session history with ?limit=100&app=&client=. Records match webhook payloads minus the event wrapper.

POST/api/reset-display-device-persistence
Auth: display:reset + CSRF

Reset Windows display-device persistence. Windows-only.

POST/api/restart
Auth: admin + CSRF

Restart the host process. May not return a body.

GET/api/vigembus/status
Auth: config:get

ViGEmBus driver state: {installed, version, version_compatible, packaged_version}. Non-Windows returns error with empty values.

POST/api/vigembus/install
Auth: admin + CSRF

Run 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.