Controller Public API
The Controller Public API is a REST integration surface on each Aida Controller (on-premises). It is intended for third-party systems — BMS adjuncts, custom dashboards, municipal integrations, and automation scripts — and is not used by the controller web UI.
Controller 2.0 exposes the same URL paths, request payloads, and response shapes as Controller 1.0 so existing integrators can migrate without client changes.
:::info Separate from Platform API
This API runs on the controller appliance (https://{controller-host}/aida/api/…). It is different from the Aida Platform cloud API (https://api.aida-platform.com/api/…) documented elsewhere on this site.
:::
Base URL
https://{controller-host}/aida/api/{endpoint}
| Example | URL |
|---|---|
| Local network | https://192.168.1.77/aida/api/getClusters |
| Via platform tunnel | https://controller.aida-platform.com/aida/api/getClusters |
Paths use camelCase endpoint names (for example getClusters, not /clusters).
Interactive docs (Swagger) on the controller: https://{controller-host}/docs — look for the public-api tag (second section after health).
Authentication
Obtain a token
POST /aida/api/authenticate — no auth required.
curl -s -X POST "https://192.168.1.77/aida/api/authenticate" \
-H "Content-Type: application/json" \
-d '{"username":"apiuser","password":"your-password"}'
Success:
{
"responseCode": 1,
"auth_token": "eyJhbG...",
"refresh_token": "eyJhbG...",
"tokenExpiresOn": "2026-06-16T12:00:00Z"
}
Failure:
{
"responseCode": 0,
"errorCode": "AuthFailed"
}
Notes:
- Use the field
auth_token, nottoken. - The account must have the
api_servicerole (or an admin/operator role used for integration testing). - Default access token lifetime is 3600 seconds (1 hour).
Refresh a token
POST /aida/api/refreshToken
{ "refresh_token": "eyJhbG..." }
Success: { "status": true, "message": "Token valid", "auth_token": "…" }
Authenticated requests
All other endpoints require:
Authorization: Bearer {auth_token}
| HTTP method | Permission |
|---|---|
| GET | read |
| POST | write |
Errors: 401 → {"status": 0, "message": "Authentication required"} · 403 → empty body
Targeting model
Control and read endpoints share these fields:
| Field | Type | Description |
|---|---|---|
targetType | integer | 1 = all, 2 = cluster, 3 = specific target |
targetId | integer | Required when targetType is 2 or 3 |
| Endpoint family | targetType=2 | targetType=3 |
|---|---|---|
| Lighting | cluster ID | node/fixture ID |
| Shades | cluster ID | shade ID (not node ID) |
IDs are integer legacy IDs (Controller 1.0 compatible). Controller 2.0 assigns and persists them automatically in device/cluster metadata.
Endpoints
Discovery & state
| Method | Path | Description |
|---|---|---|
| GET | /getClusters | List clusters with aggregate dim/CCT/RGBW/shade state |
| GET | /getActiveNodes | Online light nodes with current state |
| GET | /getNodesForCluster | Nodes in one cluster (?clusterId=&tagType=ALL|NODE|PERIPHERAL) |
| GET | /getLightLevels | Control state rows (?targetType=&targetId=) |
| GET | /getShades | All shades with position (shadeLevel 0–100) |
| GET | /getShadesForCluster | Shades in one cluster (?clusterId=) |
GET /getClusters response (array)
[
{
"id": 1,
"name": "Lobby",
"createdByName": "system",
"createdOn": "2024-01-15T10:30:00Z",
"nodeCount": 12,
"dimLevel": 80,
"shadeLevel": 50,
"colorLevel": 4000,
"rgbw": "255:128:0:100"
}
]
GET /getLightLevels response (array)
[
{
"Id": 1,
"ClusterId": 12,
"NodeId": 42,
"value": "80",
"valueType": "DIM_LEVEL",
"Synchronize": "",
"AllVal": ""
}
]
valueType values: DIM_LEVEL, COLOR_LEVEL, COLOR, SHADE_LEVEL, PPOWER
:::note Shade position
Controller 1.0 has no dedicated getShadePosition route. Read position from GET /getShades (shadeLevel field) or GET /getShadesForCluster.
:::
Control
| Method | Path | Description |
|---|---|---|
| POST | /channelControl | On / off / dim (command: ON, OFF, DIM) |
| POST | /setColorTemp | Color temperature in Kelvin (colorTemp, clamped 3000–5000) |
| POST | /setRGBW | RGBW + dim (R,G,B,W 0–255; DL 0–100 or 101 = keep current dim) |
| POST | /shadeControl | Shade motor (command: UP, DOWN, STOP, POS; posValue when POS) |
Control endpoints return:
{ "status": 1 }
(0 on failure). shadeControl also returns "shadeState".
Dim a cluster
curl -s -X POST "https://192.168.1.77/aida/api/channelControl" \
-H "Authorization: Bearer eyJhbG..." \
-H "Content-Type: application/json" \
-d '{
"targetType": 2,
"targetId": 12,
"channelId": 1,
"command": "DIM",
"dimLevel": 50
}'
Set shade position
curl -s -X POST "https://192.168.1.77/aida/api/shadeControl" \
-H "Authorization: Bearer eyJhbG..." \
-H "Content-Type: application/json" \
-d '{
"targetType": 3,
"targetId": 5,
"command": "POS",
"posValue": 75
}'
Set color temperature
curl -s -X POST "https://192.168.1.77/aida/api/setColorTemp" \
-H "Authorization: Bearer eyJhbG..." \
-H "Content-Type: application/json" \
-d '{"targetType": 2, "targetId": 12, "colorTemp": 4000}'
Example integration flow
# 1. Authenticate
TOKEN=$(curl -s -X POST "https://192.168.1.77/aida/api/authenticate" \
-H "Content-Type: application/json" \
-d '{"username":"apiuser","password":"secret"}' \
| jq -r '.auth_token')
# 2. List clusters
curl -s "https://192.168.1.77/aida/api/getClusters" \
-H "Authorization: Bearer $TOKEN"
# 3. Read light levels for cluster 12
curl -s "https://192.168.1.77/aida/api/getLightLevels?targetType=2&targetId=12" \
-H "Authorization: Bearer $TOKEN"
# 4. Read shade positions
curl -s "https://192.168.1.77/aida/api/getShades" \
-H "Authorization: Bearer $TOKEN"
Controller 2.0 vs internal API
| Topic | Public API (/aida/api/*) | Internal UI API (/api/v1/*) |
|---|---|---|
| Audience | External integrators | Controller web UI |
| IDs | Integer legacy IDs | UUIDs |
| Auth response | auth_token, responseCode | access_token, token_type |
| Path style | /aida/api/getClusters | /api/v1/clusters |
Do not mix the two APIs in one client without adapting IDs and response parsing.
Related integration paths
| Path | Use when |
|---|---|
| Controller Public API (this doc) | REST control from BMS scripts, legacy 1.0 clients |
| Controller BACnet/IP Server | BMS requires BACnet ReadProperty / WriteProperty |
| Municipal BMS Integration Brief | Government submittals, PICS, commissioning, Level 1 vs 2 |
| Aida Platform API | Multi-site cloud management, not per-controller control |
| Webex integration | Workspace widget → controller actions |
Creating API users
On Controller 2.0, create a user with role api_service via the controller admin UI or internal API (POST /api/v1/auth/users). That account can authenticate against /aida/api/authenticate.
Controller version: 2.0+ · Compatibility: Controller 1.0 public API contract