Appearance
API Reference
The HOS server exposes four public communication surfaces: REST API (HTTP), Socket.IO (real-time client events), raw WebSocket (remote driver protocol), and SSE (server-sent events for live state). This page documents those surfaces plus the local process protocol used by OS-local uploaded drivers.
This page is a human-friendly summary of the HOS API surfaces. If an endpoint behaves unexpectedly, the running server is always the source of truth.
REST API — OS API
Base paths: /app/os, /api/os, /v1/os
Auth: Bearer token required (scope: os_api_admin). Pass as Authorization: Bearer <token>. Obtain a token via POST /auth/login.
Do not include actual tokens in requests from this docs page. Use
<token>as a placeholder when sharing examples.
Auth
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /auth/login | None | Login with credentials, returns bearer token |
| GET | /auth/me | Required | Authenticated principal info |
| POST | /auth/stream-token | Required | Issue a short-lived token for SSE clients that cannot send auth headers |
Bootstrap and Preferences
| Method | Path | Description |
|---|---|---|
| GET | /bootstrap | Full system bootstrap — devices, spaces, programs, media, and current state in one payload |
| GET | /preferences/home | Home screen preferences |
| POST | /preferences/home | Update home preferences |
| GET | /preferences/home/favorites | Current home favorite device keys |
| POST | /preferences/home/favorites | Save home favorite device keys |
| GET | /design-profiles | List available design profiles |
| POST | /design-profiles/select | Select the active design profile |
| GET | /design/live | Current live design |
Devices
| Method | Path | Description |
|---|---|---|
| GET | /devices | List all logical devices |
| GET | /devices/:id | Device details |
| GET | /devices/:id/apps | List launchable apps for app-capable devices |
| GET | /devices/:id/apps/:appId/icon | Stream a device app icon |
| POST | /devices/:id/apps/:appId/launch | Launch an app on a supported device |
| GET | /devices/:id/equalizer | Read equalizer-capable command/state summary |
| POST | /devices/:id/equalizer | Dispatch an equalizer or sound-mode command |
| POST | /devices/:id/command | Dispatch a command (Standard or IR-mapped) |
| GET | /devices/:id/scenes | List scenes exposed by a supported device |
| POST | /devices/:id/metadata | Update tags, primary room, or remote-source metadata |
IR Device Properties
Devices using the GENERIC_IR driver include specific metadata in their properties object:
extenderIp: The target hardware bridge IP address.irCommands: A dictionary of command keys to raw IR pulse objects.json{ "turn_on": { "freq_khz": 38, "raw": [4500, 4500, 560, ...] } }
Spaces
| Method | Path | Description |
|---|---|---|
| GET | /spaces | List all spaces |
| POST | /spaces/save | Create or update a space |
| POST | /spaces/:id/remove | Remove a space |
| GET | /spaces/:id/devices | Devices assigned to a space |
| GET | /spaces/:id/remote-sources | Remote sources for a space |
| POST | /spaces/:id/remote-sources/:sourceId/activate | Activate a remote source |
| POST | /spaces/:id/devices/assign | Assign devices to a space |
Programs
| Method | Path | Description |
|---|---|---|
| GET | /programs | List all programs |
| POST | /programs/save | Create or update a program. Accepts canonical script arrays and YAML authoring fields; see Program YAML Scripts. |
| POST | /programs/:id/run | Execute a program |
| POST | /programs/:id/run-off | Execute the program off path |
| POST | /programs/:id/remove | Remove a program |
| POST | /programs/:id/copy | Duplicate a program |
| POST | /programs/:id/timer | Update a program timer |
| POST | /programs/:id/script | Update a program script |
| POST | /programs/:id/lighting/off | Turn off program lighting |
Activities, Zones, Macros, and Alerts
| Method | Path | Description |
|---|---|---|
| GET | /activity-presets | List activity presets generated from programs and mapped controls |
| POST | /activity-presets/:id/run | Run an activity preset |
| GET | /zones | List zones with resolved device/program references |
| POST | /zones/:id/volume | Set zone volume on one or more volume-capable devices |
| POST | /zones/:id/program/run | Run a program assigned to a zone |
| GET | /zone-groups | List zone groups |
| POST | /zone-groups/save | Create or update a zone group |
| POST | /zone-groups/:id/remove | Remove a zone group |
| POST | /zone-groups/:id/zones/assign | Assign zones to a zone group |
| GET | /macros | List macros |
| POST | /macros/save | Create or update a macro |
| POST | /macros/:id/remove | Remove a macro |
| POST | /macros/:id/run | Run a macro |
| GET | /alerts/submissions | List submitted alert events |
| POST | /alerts/submissions | Submit an alert event |
State Stream
| Method | Path | Description |
|---|---|---|
| GET | /state/snapshot | Current device state snapshot (point-in-time) |
| GET | /state/stream | SSE live state stream — see SSE section below |
| GET | /state/telemetry/:deviceId | Telemetry data for a specific device |
Haptique Music API
The dedicated developer guide for music apps and playback endpoints is now available at Haptique Music API.
Core music routes:
| Method | Path | Description |
|---|---|---|
| GET | /media/players | Canonical playable media-player roster |
| POST | /media/players/:id/command | Normalized media-player command |
| GET | /media-services/status | Full music-service status snapshot |
| POST | /media-services/status | Full music-service status snapshot with request-body options |
| GET | /media-services/players | Music Services player roster |
| GET | /media-services/endpoints | Local and provider playback endpoints |
| POST | /media-services/endpoints/discover | Refresh endpoint discovery |
| POST | /media-services/endpoints/update | Update endpoint label or enabled state |
| POST | /media-services/endpoints/airplay/pair/start | Start AirPlay endpoint pairing |
| POST | /media-services/endpoints/airplay/pair/finish | Finish AirPlay endpoint pairing |
| POST | /media-services/search | Search connected music sources |
| POST | /media-services/play | Start playback on a target |
| POST | /media-services/command | Send target-level playback command |
| POST | /media-services/transfer | Transfer playback or queue to another target |
| GET | /media-services/queue/:targetId | Read a playback queue |
| POST | /media-services/bridge/endpoints/register | Register a Music Bridge playback endpoint |
Local Media Controller
These endpoints expose the local OS media-controller state and commands, currently used for local Apple Music style control surfaces.
| Method | Path | Description |
|---|---|---|
| GET | /media-controller/state | Current local media-controller snapshot |
| POST | /media-controller/control | Execute a local media-controller action |
| GET | /media-controller/stream | SSE stream for local media-controller now-playing changes |
Integration Releases
| Method | Path | Description |
|---|---|---|
| GET | /integration-releases | List integration releases |
| GET | /integration-releases/:key | Get details for a specific release |
| GET | /integration-releases/:key/submission-package | Get the submission package |
| POST | /integration-releases/save | Save a release |
| POST | /integration-releases/:key/submit | Submit a release |
| POST | /integration-releases/:key/unsubmit | Unsubmit a release |
| POST | /integration-releases/:key/rollback | Roll back a release |
Fleet Management (Phase 06)
These endpoints manage the HOS fleet and bridge connectivity.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /hos-fleet-devices | osApiAuth | List HOS devices with their Fleet Release status |
| POST | /hos-fleet-devices/releases/:key/status | osApiAuth | Update Fleet Release status for a specific OS logical device |
| POST | /device/hos/category | appAuth | Create or update an HOS device category |
| POST | /integration/hos/device/command | appAuth | Dispatch a command to a specific HOS device in the fleet |
| POST | /bridge/devices/:fleetDeviceId/command | osBridgeAuth | Send a command to a fleet device via the OS bridge |
Bridge (Fleet)
Bridge endpoints serve two auth modes: osApiAuth (for HOS admin-level callers) and osBridgeAuth (for bridge/fleet peer callers).
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /bridge/link | osApiAuth | Get bridge link info |
| POST | /bridge/link/save | osApiAuth | Save bridge link |
| POST | /bridge/token | osApiAuth | Get bridge token |
| GET | /bridge/health | osBridgeAuth | Bridge health check |
| GET | /bridge/capabilities | osBridgeAuth | Bridge capabilities |
| GET | /bridge/devices | osBridgeAuth | List bridge devices |
| GET | /bridge/devices/state | osBridgeAuth | Device states from bridge |
| POST | /bridge/devices/register | osBridgeAuth | Register a bridge device |
| POST | /bridge/devices/update | osBridgeAuth | Update a bridge device |
| POST | /bridge/devices/:fleetDeviceId/command | osBridgeAuth | Send command to a fleet device |
HomeKit
| Method | Path | Description |
|---|---|---|
| GET | /homekit/status | HomeKit bridge status |
| GET | /homekit/accessories | List HomeKit accessories |
| GET | /homekit/import-accessories | List importable accessories |
| GET | /homekit/plugins | List HomeKit plugins |
| GET | /homekit/plugins/search | Search plugin catalog |
| GET | /homekit/plugins/resolve | Resolve plugin metadata |
| GET | /homekit/plugins/:pluginId/config-schema | Plugin configuration schema |
| GET | /homekit/plugins/:pluginId | Plugin details |
| POST | /homekit/plugins/custom | Add a custom plugin catalog entry |
| POST | /homekit/plugins/:pluginId/catalog-remove | Remove a plugin catalog entry |
| POST | /homekit/plugins/:pluginId/install | Install a plugin |
| POST | /homekit/plugins/:pluginId/uninstall | Uninstall a plugin |
| POST | /homekit/plugins/:pluginId/enable | Enable a plugin |
| POST | /homekit/plugins/:pluginId/disable | Disable a plugin |
| POST | /homekit/plugins/:pluginId/config | Configure a plugin |
| POST | /homekit/settings | Update HomeKit settings |
| POST | /homekit/resync | Resync HomeKit bridge |
| POST | /homekit/import-accessories/resync | Refresh importable HomeKit accessories |
| POST | /homekit/import-accessories/:accessoryId/import | Import a HomeKit accessory as an OS logical device |
| POST | /homekit/import-accessories/:accessoryId/remove | Remove an imported HomeKit accessory |
| GET | /homekit/plugin/bootstrap | Plugin bridge bootstrap (plugin bridge auth) |
| GET | /homekit/plugin/state/stream | Plugin state stream SSE (plugin bridge auth) |
| POST | /homekit/plugin/devices/:id/command | Send command via plugin bridge |
| POST | /homekit/plugin/external-accessories/sync | Sync external accessories from a plugin bridge |
| GET | /homekit/plugin/import-commands | Pull pending import commands for a plugin bridge |
| POST | /homekit/plugin/import-commands/:commandId/ack | Acknowledge a plugin import command |
AI
| Method | Path | Description |
|---|---|---|
| GET | /ai/status | Get AI service status (installed, running, modelReady, download progress) |
| GET | /ai/health | Check AI service health |
| GET | /ai/suggestions | Get AI chat suggestions/prompts |
| GET | /ai/models | List available AI models |
| POST | /ai/install | Install a specific AI model |
| POST | /ai/start | Start the AI service |
| POST | /ai/stop | Stop the AI service |
| POST | /ai/prompt | Send a prompt to the AI. Use ?sync=true for immediate response. |
| GET | /ai/events | SSE stream for AI events (generation progress, status updates) |
| DELETE | /ai/uninstall | Uninstall the current AI model |
REST API — App API
Base paths: /app, /api
Auth: appAuth middleware (session-based for the legacy app surface)
This is the legacy API surface consumed by earlier mobile client versions and the web admin panel. Key endpoint families:
| Prefix | Purpose |
|---|---|
/auth/* | App login, register, logout |
/devices/* | Device listing and commands |
/entity/* | Entity-level operations |
/room/* | Room/space operations (legacy) |
/integration/* | Integration management |
/programs/* | Program CRUD and execution |
/sequences/* | Sequence operations |
/zones | Zone listing |
/action-maps | Action map listing |
/media-services/* | Media service status and commands |
REST API — Other Route Families
| Prefix | Auth | Purpose |
|---|---|---|
/remote, /v1/remote | remoteAuth | Remote-controller API for pairing and command dispatch |
/admin | Admin auth | Admin panel routes |
/os | Session | Server-rendered EJS web UI (the OS frontend) |
/dev | None (dev only) | Debug routes — available in development only |
Socket.IO Events
Connection path: /socket.io (default Socket.IO path)
The server exposes multiple Socket.IO namespaces. Each namespace handles a specific concern.
Namespaces and Events
| Namespace | Event | Direction | Payload |
|---|---|---|---|
/socket/device-state | device:state:update | server → client | { deviceId: string, state: object } |
/socket/device-state | device:state:snapshot | server → client | { deviceId: string, state: object } |
/socket/haptique-protocol | haptique:command | client → server | { command: string, payload: object } |
/socket/haptique-protocol | haptique:response | server → client | { command: string, data: unknown, ok: boolean } |
/socket/haptique-protocol | haptique:event | server → client | HaptiqueProtocolEvent |
/socket/remote-connect | remote:pairing | client → server | Pairing request payload |
/socket/remote-connect | remote:pairing:status | server → client | Pairing result |
/socket/designer | designer:published | server → client | Design payload |
/socket/designer | designer:refresh | server → client | Refresh signal |
/socket/device-ir-test | ir:data | server → client | IR signal data |
Haptique Protocol Commands
Commands are sent client → server via the haptique:command event on the /socket/haptique-protocol namespace. Format: { command: "<COMMAND_NAME>", payload: { ... } }.
| Command | Description |
|---|---|
GET_PROTOCOL_CAPABILITIES | List capabilities supported by the protocol hub |
LIST_EVENTS | List available protocol event types |
SYSTEM_SNAPSHOT | Full system state snapshot |
LIST_INTEGRATIONS | List all loaded integrations |
LIST_CONNECTIONS | List active integration connections |
LIST_SCENES | List all scenes |
SCENE_RUN | Execute a scene by ID |
LIST_ENTITY_DOMAINS | List entity domains (lighting, climate, etc.) |
LIST_ENTITIES | List all entities |
GET_ENTITY | Get a single entity by ID |
ENTITY_ACTION | Perform an action on an entity |
LIST_STATES | List all device states |
GET_DEVICE_STATE | Get state for a specific device |
LIST_SENSORS | List sensor entities |
LIST_PROGRAMS | List all programs |
LIST_AUTOMATIONS | List all automations |
LIST_ACTION_MAPS | List action maps |
LIST_ZONES | List zones |
LIST_DRIVERS | List active drivers |
LIST_DEVICES | List all devices (protocol-level) |
LIST_DEVICE_COMMANDS | List commands available for a device |
GET_DEVICE_COMMAND | Get a specific device command definition |
EXECUTE_DEVICE_COMMAND | Execute a device command |
GET_HOME_GRAPH | Get the home graph structure |
LIST_CAPABILITY_MODEL | List the capability model definitions |
LIST_PROGRAM_SEMANTICS | List program semantic definitions |
UPSERT_PROGRAM_SEMANTIC | Create or update a program semantic |
DELETE_PROGRAM_SEMANTIC | Delete a program semantic |
GET_CONTEXT_SNAPSHOT | Get contextual system snapshot |
INTENT_PARSE | Parse a natural language intent |
INTENT_EXECUTE | Execute a parsed intent |
PROGRAM_RUN | Run a program by ID |
AUTOMATION_RUN | Run an automation by ID |
ACTION_MAP_TRIGGER | Trigger an action map |
DEVICE_ACTION | Dispatch a raw device action |
DRIVER_MESSAGE | Forward a message to a driver |
Remote Driver WebSocket Protocol
Transport: Raw WebSocket (ws library — NOT Socket.IO)
Path: /driver on DRIVER_WS_PORT (defaults to the same port as PORT if DRIVER_WS_PORT is not set)
This protocol is for external SDK-style driver processes only. Mobile clients and external callers should use the Socket.IO or REST surfaces above. OS-local uploaded Python, Lua, and JavaScript drivers use the local process protocol described below instead of opening this WebSocket.
For comprehensive driver protocol documentation with full message schemas, connection lifecycle diagrams, and driver authoring guidance, see the
sdk/docs/directory. The SDK has detailed protocol guides for driver authors.
Registration Handshake
When a driver WebSocket connection is established, the driver must immediately send a registration message:
json
{
"method": "driver.register",
"driverKey": "MY_DRIVER",
"instanceId": "my-driver-001",
"protocolVersion": 1
}| Field | Type | Description |
|---|---|---|
method | "driver.register" | Must be exactly this string |
driverKey | string | Unique identifier for the driver type (e.g., "HUE", "DENON") |
instanceId | string | Unique identifier for this driver instance |
protocolVersion | number | Protocol version — use 1 |
Driver → Server Event Types
After registration, drivers send events using the following types:
| Event Type | Purpose |
|---|---|
DEVICE_DISCOVERED | Notify server of a new device found by this driver |
DEVICE_UPDATED | Notify server that device metadata has changed |
DEVICE_REMOVED | Notify server that a device is no longer available |
STATE_UPDATE | Push a device state update to the server |
ACTION_RESULT | Report the result of a command execution requested by the server |
METRIC_UPDATE | Push telemetry/metric data for a device |
Server → Driver Messages
| Message Type | Purpose |
|---|---|
ACTION | Server instructs driver to execute a command on a device |
DRIVER_STATUS | Server sends a status notification to the driver |
Local Driver Process Protocol
OS-local drivers uploaded through Integration Manager are launched by DriverManager from a *.driver.json manifest. They communicate with HOS over newline-delimited JSON on stdin/stdout.
Supported local upload runtimes:
Manifest driverType | File extension |
|---|---|
python | .py |
javascript | .js |
lua | .lua |
Runtime rules:
- The manifest supplies
driverKey,driverFile, setupproperties,commands,io, andenvMap. - HOS writes one command JSON object per stdin line.
- Drivers write one event JSON object per stdout line.
- JavaScript drivers are plain Node-compatible
.js; TypeScript must be compiled before upload. - JavaScript should prefer Node 20+ built-ins (
fetch,net,dgram,readline) and only includepackage.jsonwhen external dependencies are required.
Common local incoming messages:
| Message Type | Purpose |
|---|---|
ACTION | Execute a user, automation, or mapped device action |
COMMAND_EXECUTE | Execute a command-catalog action |
PING | Optional runtime health probe |
Common local outgoing events match the WebSocket protocol event names: DEVICE_DISCOVERED, DEVICE_UPDATED, DEVICE_REMOVED, STATE_UPDATE, ACTION_RESULT, and optional METRIC_UPDATE.
SSE Stream
Endpoint: GET /app/os/state/stream
Auth: Bearer token passed as a query parameter: ?accessToken=<token>
The SSE stream delivers real-time device state changes and protocol events to any HTTP client that supports server-sent events.
Events
| Event | Payload | When |
|---|---|---|
ready | {} | Sent immediately on connection established |
snapshot | Full device state map (all devices) | Sent immediately after ready |
state | { deviceId: string, state: object } | Sent on every device state change |
event | HaptiqueProtocolEvent | Sent on protocol hub events |
ping | {} | Periodic heartbeat to keep connection alive |
Example SSE consumer (Node.js)
typescript
const EventSource = require('eventsource');
const es = new EventSource('http://localhost:8080/app/os/state/stream?accessToken=<token>');
es.addEventListener('snapshot', (e) => {
const allState = JSON.parse(e.data);
console.log('Initial state:', allState);
});
es.addEventListener('state', (e) => {
const { deviceId, state } = JSON.parse(e.data);
console.log(`${deviceId} updated:`, state);
});Cross-References
- HOS Overview — driver ecosystem overview and architecture diagrams
- AI Driver Builder MCP — generated local driver package workflow