For the complete documentation index, see llms.txt. This page is also available as Markdown.

Developer Documentation

Control Sonoran Studio smart lighting and Streamer.bot from local tools

Sonoran Studio Desktop exposes a versioned HTTP API for local games, scripts, stream tools, and automation software. Use it to activate saved lighting scenes, control individual bulbs, play temporary lighting sequences, and invoke Streamer.bot actions.

The API runs in the Windows and macOS desktop app, not on sonoran.studio. Keep the desktop app open and signed in. Lighting and Streamer.bot control require Sonoran Studio Pro or Sonoran One.

Quick start

The default base URL is:

http://127.0.0.1:9990/api/v1

The port is shown and can be changed at the bottom of the desktop app's Smart Lighting panel. Local requests do not need an API key.

Confirm that the API is running:

curl.exe http://127.0.0.1:9990/api/v1/status

Activate the saved available scene:

curl.exe --request POST http://127.0.0.1:9990/api/v1/lighting/state ^
  --header "Content-Type: application/json" ^
  --data "{\"state\":\"available\"}"

On macOS, Linux, or a shell other than Windows Command Prompt, use normal multiline shell syntax:

curl --request POST http://127.0.0.1:9990/api/v1/lighting/state \
  --header 'Content-Type: application/json' \
  --data '{"state":"available"}'

All POST requests must use Content-Type: application/json.

Endpoint reference

Method
Path
Purpose

GET

/api/v1

Discover the API version and endpoint paths

GET

/api/v1/status

Read API, entitlement, lighting, and Streamer.bot status

GET

/api/v1/lighting/states

List every named lighting state and whether it has a saved sequence

POST

/api/v1/lighting/state

Activate a saved lighting state

GET

/api/v1/lighting/bulbs

List unique bulbs used by saved scenes

POST

/api/v1/lighting/bulbs

Immediately set one or more bulbs to a color

POST

/api/v1/lighting/sequence

Start a temporary, finite multi-frame sequence

GET

/api/v1/streamerbot/actions

List enabled actions reported by Streamer.bot

POST

/api/v1/streamerbot/actions

Invoke any Streamer.bot action by ID or name

POST

/api/v1/streamerbot/events

Invoke the action mapped to a Sonoran event

POST

/lighting

Legacy FiveM-compatible named lighting state endpoint

POST

/fivem

Bundled FiveM integration endpoint for gameplay moments

POST

/lspdfr

Bundled LSPDFR plugin endpoint for lighting state, gameplay moments, and validated overlay events

Successful JSON responses contain "ok": true. Errors contain "ok": false, an error code, and a human-readable message.

The unversioned /fivem and /lspdfr routes are reserved for bundled Sonoran Studio game integrations. Third-party integrations should use the versioned /api/v1 endpoints; LSPDFR overlay events are accepted only through the signed-in Studio desktop session.

Status and discovery

Discover endpoints

This route returns the API name, apiVersion, and the paths supported by the installed desktop app. Clients should use it when they need to detect API capabilities.

Get status

Example response:

Discovery and status remain available without a paid entitlement so clients can explain why a control request is unavailable.

Lighting states

List states

Each result includes the API state, display label, saved frame count, and whether at least one saved frame contains a bulb.

Activate a saved state

Supported state values are:

The desktop app plays the sequence saved for that state. Multi-frame saved scenes continue looping until another state is activated. panic has priority: while it is active, other named states return HTTP 409 until restore is sent.

Bulbs

List configured bulbs

The response contains each unique bulb used in at least one saved scene. Credentials are never returned.

Use the returned id in control and sequence requests. IDs are formed from the provider and device ID, are case-insensitive when supplied, and should otherwise be treated as opaque strings.

Set configured bulbs

Omit color to use the bulb's saved color. Up to 64 bulbs can be controlled in one request. #RRGGBB and rgb(r, g, b) colors are accepted; #000000 turns supported bulbs off.

Direct control cancels the currently looping scene and sets the current named state to restore.

Control an ad-hoc bulb descriptor

A bulb does not have to appear in a saved scene. Supply its provider descriptor instead of id:

The provider must already be connected in the desktop app. type can be wyze, philips, govee, or goveebt. mac is the provider's device identifier rather than necessarily a network MAC address. Wyze and Govee Wi-Fi requests also require the device model. Using IDs returned by GET /lighting/bulbs is recommended because Studio fills these fields for you.

Temporary sequences

Start a finite sequence with one to 40 frames:

delay is the number of milliseconds before the next frame and is clamped to 50–60000. repeat is optional, defaults to 1, and is clamped to 1–100. Each frame can contain up to 64 configured IDs, ad-hoc bulb descriptors, or a mixture of both.

The endpoint returns HTTP 202 as soon as Studio accepts the sequence. Playback continues locally. A later state, bulb, or sequence request cancels it. The final colors remain active after the last frame.

Streamer.bot actions

Enable and connect Streamer.bot in Sonoran Studio before using these endpoints.

List actions

The result contains the ID, name, and optional group for every enabled action reported by Streamer.bot:

Invoke any action

Supply id, name, or both. IDs are safer if action names may change. args is optional and is passed to Streamer.bot's DoAction request. It can contain up to 50 flat string, finite number, or boolean values; nested objects and arrays are rejected.

Invoke a mapped Sonoran event

Use this endpoint when Sonoran Studio already maps an event to an action:

Supported mapped events are:

If no action is mapped to the event, Studio returns HTTP 409.

Complete client examples

JavaScript

This example uses the built-in fetch available in current Node.js versions:

Python

This example uses only Python's standard library:

FiveM Lua

Legacy lighting endpoint

Existing integrations can continue to use:

The default full URL is http://127.0.0.1:9990/lighting. Its state behavior and response codes match POST /api/v1/lighting/state. New integrations should use the versioned route.

LAN access and authentication

The server binds only to 127.0.0.1 by default. This is the safest and recommended configuration.

To call Studio from another computer on the same trusted network:

  1. Enable Allow LAN control at the bottom of the desktop Smart Lighting panel.

  2. Select Copy LAN token.

  3. Replace 127.0.0.1 with the Studio computer's private LAN address.

  4. Send the token in X-Sonoran-Token or as a Bearer token.

Never put the token in a public repository, browser URL, stream overlay, or client-side webpage. LAN mode does not add TLS; use it only on a trusted private network. Do not expose port 9990 through a router or public firewall.

Browser and security behavior

Native programs and command-line tools do not send an Origin header and can call the loopback API normally. Browser JavaScript is accepted only when its page is also served from localhost, 127.0.0.1, or ::1. Requests from public web origins are rejected to prevent a website from silently controlling local lights or Streamer.bot actions.

Request bodies are limited to 256 KiB. Provider credentials stay encrypted in the desktop app and are never accepted by or returned from this API.

HTTP status codes

Status
Meaning

200

Request completed

202

Temporary sequence accepted for local playback

400

Invalid JSON field, state, bulb, sequence, event, or argument

403

Pro entitlement, LAN permission/token, or browser-origin check failed

404

Endpoint does not exist

409

Current state prevents the change or no action is mapped to an event

413

Request body is larger than 256 KiB

415

A POST request did not use application/json

500

Unexpected desktop error

503

Streamer.bot integration is unavailable

Client code should use the HTTP status and the response's message; it should not depend on the exact wording of provider errors.

Last updated

Was this helpful?