XGuarden Home API
Read the state of connected devices, send commands, run scenes and build automations for a home through one JSON REST interface.
Authentication
Authenticate with a secret key sent as a bearer token. Keys are scoped to a single home and can be limited to read-only access. Never embed a key in a mobile app or a public repository.
Request
curl https://xguarden.tech/v2/homes/home_5aT2k/devices \ -H "Authorization: Bearer xg_live_••••••••••••••••" \ -H "Accept: application/json"
Response when the key is missing or invalid (401)
{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The API key provided is missing or invalid.",
"request_id": "req_8f2c1a9d4e7b"
}
}
xg_test_ connect to simulated devices, so you can try commands without touching a real home.Device object
A device exposes one or more capabilities. state is the last reported value and desired holds a command that has not been confirmed by the device yet.
{
"id": "dev_9Xq2LmT4",
"object": "device",
"home_id": "home_5aT2k",
"room_id": "room_living",
"name": "Living room thermostat",
"type": "thermostat",
"manufacturer": "Aurora",
"model": "T-210",
"firmware": "3.8.2",
"protocol": "zigbee",
"online": true,
"battery": null,
"capabilities": ["temperature.target", "temperature.current", "mode"],
"state": {
"temperature.current": 21.4,
"temperature.target": 22.0,
"mode": "heat"
},
"desired": {},
"last_seen_at": "2026-10-03T19:58:41Z"
}
Send a command
Commands are asynchronous. The API returns 202 as soon as the hub accepts the command, and the device state changes once the device confirms it. Use an Idempotency-Key header to make retries safe.
curl -X POST https://xguarden.tech/v2/devices/dev_9Xq2LmT4/commands \
-H "Authorization: Bearer xg_live_••••••••••••••••" \
-H "Idempotency-Key: 7c1d2a4e-5b0f-4e6e-9a3d-0f8e2b6c1a77" \
-H "Content-Type: application/json" \
-d '{"capability":"temperature.target","value":22.5}'
Response (202)
{
"id": "cmd_4Hn8wQ1z",
"object": "command",
"device_id": "dev_9Xq2LmT4",
"capability": "temperature.target",
"value": 22.5,
"status": "pending",
"created_at": "2026-10-03T20:01:12Z",
"expires_at": "2026-10-03T20:02:12Z"
}
Device endpoints
| Method | Path | Description |
|---|---|---|
| GET | /v2/homes/{id}/devices | List devices. Filter by room_id, type or online. |
| GET | /v2/devices/{id} | Retrieve a device and its current state. |
| PUT | /v2/devices/{id} | Rename a device or move it to another room. |
| DELETE | /v2/devices/{id} | Remove a device from the home. |
| POST | /v2/devices/{id}/commands | Send a command to a device. |
| GET | /v2/commands/{id} | Check whether a command was confirmed, failed or expired. |
| GET | /v2/devices/{id}/history | State changes over time. Pass from, to and capability. |
| GET | /v2/health | Service health. Does not require authentication. |
Capabilities
| Capability | Type | Description |
|---|---|---|
power | boolean | Turn a plug, light or appliance on or off. |
brightness | integer, 0 to 100 | Light level in percent. |
color.temperature | integer, 2000 to 6500 | White tone in kelvin. |
temperature.target | number | Target temperature in °C. |
lock | locked, unlocked | Door lock state. Unlocking requires a key with the locks:write scope. |
position | integer, 0 to 100 | Blinds and garage doors, 0 is closed. |
motion | boolean | Motion detected. Read-only. |
contact | open, closed | Door and window sensors. Read-only. |
Rooms
Rooms group devices so a command or scene can target everything in one place.
| Method | Path | Description |
|---|---|---|
| GET | /v2/homes/{id}/rooms | List rooms with device counts. |
| POST | /v2/homes/{id}/rooms | Create a room. |
| POST | /v2/rooms/{id}/commands | Send one command to every compatible device in the room. |
Scenes
A scene is a saved set of commands that runs together.
POST /v2/homes/home_5aT2k/scenes
{
"name": "Evening",
"actions": [
{ "room_id": "room_living", "capability": "brightness", "value": 35 },
{ "device_id": "dev_9Xq2LmT4", "capability": "temperature.target", "value": 21.5 },
{ "device_id": "dev_Lk3p7WcA", "capability": "position", "value": 0 }
]
}
Run it with POST /v2/scenes/{id}/activate. The response lists the command created for each action.
Automations
Automations run a scene or commands when a trigger fires and every condition is true. Supported triggers are schedule, sunrise, sunset, device_state and presence.
{
"id": "aut_2Wn5Rj8c",
"name": "Close blinds at sunset",
"enabled": true,
"trigger": { "type": "sunset", "offset_minutes": -15 },
"conditions": [
{ "type": "weekday", "in": ["mon", "tue", "wed", "thu", "fri"] }
],
"actions": [
{ "room_id": "room_living", "capability": "position", "value": 0 }
],
"last_run_at": "2026-10-03T17:41:00Z"
}
Energy
Devices with power metering report consumption in watt-hours. Totals are available per home, room or device and can be grouped by hour, day or month.
GET /v2/homes/home_5aT2k/energy?from=2026-10-01&to=2026-10-03&group_by=day
{
"unit": "Wh",
"data": [
{ "date": "2026-10-01", "total": 11840, "by_room": { "room_living": 4210, "room_kitchen": 5120 } },
{ "date": "2026-10-02", "total": 12310, "by_room": { "room_living": 4390, "room_kitchen": 5370 } },
{ "date": "2026-10-03", "total": 10975, "by_room": { "room_living": 3980, "room_kitchen": 4760 } }
]
}
Webhooks
Register an HTTPS endpoint to receive events. Each request is signed with an HMAC-SHA256 of the raw body using your webhook secret, sent in the X-XGuarden-Signature header. Respond with any 2xx status within 10 seconds. Failed deliveries are retried up to 8 times over 24 hours.
| Event | Sent when |
|---|---|
device.state_changed | A device reported a new state. |
device.offline | A device has not reported for more than 10 minutes. |
device.battery_low | A battery-powered device dropped below 15 percent. |
command.failed | A command expired or was rejected by the device. |
scene.activated | A scene started, manually or from an automation. |
hub.offline | A hub lost its connection to the cloud. |
POST /hooks/xguarden HTTP/1.1
Content-Type: application/json
X-XGuarden-Event: device.state_changed
X-XGuarden-Signature: sha256=5f3a1c0e9b7d...
{
"id": "evt_0d7a2f9e41",
"type": "device.state_changed",
"created_at": "2026-10-03T20:01:14Z",
"data": {
"device_id": "dev_9Xq2LmT4",
"capability": "temperature.target",
"previous": 22.0,
"value": 22.5
}
}
Event stream
For dashboards that need updates without running a server, open a Server-Sent Events connection. The stream sends a heartbeat comment every 25 seconds and resumes from the last event ID if you reconnect with the Last-Event-ID header.
curl -N https://xguarden.tech/v2/homes/home_5aT2k/events \ -H "Authorization: Bearer xg_live_••••••••••••••••" \ -H "Accept: text/event-stream"
Errors
The API uses standard HTTP status codes. Every error body contains a machine-readable code and a request_id to include when contacting support.
| Status | Meaning |
|---|---|
| 400 | The request is malformed, or the value is outside the range the capability accepts. |
| 401 | The API key is missing, invalid or revoked. |
| 403 | The key is read-only or lacks the required scope, such as locks:write. |
| 404 | The home, device or room does not exist. |
| 409 | The device is offline, or another command for the same capability is still pending. |
| 422 | The device does not support this capability. |
| 429 | Too many requests. Retry after the interval in the Retry-After header. |
| 500, 503 | A temporary problem on our side. Retry with exponential backoff. |
| 504 | The hub did not answer in time. The command was not delivered. |
Rate limits
Each key can make 100 requests per second, with bursts up to 300. Each device accepts at most 10 commands per minute to protect battery-powered hardware. Every response includes X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers.
Changelog
2.4 — September 2026
Added the hub.offline event and per-room energy totals.
2.3 — June 2026
Added the Server-Sent Events stream and sunrise and sunset triggers for automations.
2.2 — March 2026
Added scopes for keys, including read-only access and locks:write.