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 internal stdin/stdout protocol used by OS-local uploaded drivers.
Source of truth:
apps/server/src/routes/is the canonical source for REST endpoints. This wiki is a human-friendly summary. If something looks wrong, check the route files directly.
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 |
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 | /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 |
| POST | /devices/:id/command | Dispatch a command (Standard or IR-mapped) |
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 |
| POST | /programs/:id/run | Execute a program |
| POST | /programs/:id/lighting/off | Turn off program lighting |
| DELETE | /programs/:id | Delete a program |
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 |
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/:pluginId | Plugin details |
| 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 |
| 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 |
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
- Server Internals — how the request pipeline, middleware, and route processing work internally
- HOS Overview — driver ecosystem overview and architecture diagrams
- AI Driver Builder MCP — generated local driver package workflow
- Mobile App — how the mobile app consumes these APIs