Skip to main content

Overview

To hold an HVAC device at a fixed mode, push an operation mode: heat, cool, or auto. The device’s own schedule is ignored until you release the hold. Use it for a manual override, a guest in the spare room, a skipped vacation week, or to drive the thermostat from your own logic. The companion command, follow_schedule, hands control back to the device’s native program. Together they form an open-and-close pair. The body is the canonical action envelope every device type shares: an action with a command and its parameters. See canonical actions.
Coming soon. Live control for HVAC devices. The sandbox environment runs the full thermostat command surface end to end, so the walkthrough below works against a sandbox device today. A live HVAC push returns 422 COMMAND_NOT_SUPPORTED until the live path opens.

Step 1: Set the hold

Push auto with a comfort band. heatSetpoint and coolSetpoint are {value, unit} quantities in degrees Celsius, each bounded 10 to 35. The device heats below heatSetpoint and cools above coolSetpoint.
curl -X POST https://api.amps.ai/hvac/device_hvac_001 \
  -H "x-api-key: sk_test_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "action": {
      "command": "auto",
      "parameters": {
        "heatSetpoint": { "value": 20, "unit": "celsius" },
        "coolSetpoint": { "value": 24, "unit": "celsius" }
      }
    }
  }'
To pin a single temperature instead of a band, push heat or cool with a target. You get back 202 Accepted, wrapped in the standard envelope. Because this is an immediate push, the action begins life in acknowledged rather than scheduled.
{
  "success": true,
  "data": {
    "id": "act_hvac_004",
    "deviceId": "device_hvac_001",
    "deviceType": "hvac",
    "command": "auto",
    "parameters": {
      "heatSetpoint": { "value": 20, "unit": "celsius" },
      "coolSetpoint": { "value": 24, "unit": "celsius" }
    },
    "state": "acknowledged",
    "createdAt": "2026-05-08T10:00:00.000Z",
    "links": { "self": "/actions/act_hvac_004" }
  },
  "meta": { "requestId": "req_5iA9wJmZ", "environment": "sandbox", "timestamp": "2026-05-08T10:00:00.000Z", "latencyMs": 79 }
}

Step 2: Confirm the hold applied

Poll the action to watch the lifecycle.
curl -X GET https://api.amps.ai/actions/act_hvac_004 \
  -H "x-api-key: sk_test_xxxxxxxxxxxxxxxxxxxxxxxx"
{
  "success": true,
  "data": {
    "id": "act_hvac_004",
    "deviceId": "device_hvac_001",
    "deviceType": "hvac",
    "command": "auto",
    "parameters": {
      "heatSetpoint": { "value": 20, "unit": "celsius" },
      "coolSetpoint": { "value": 24, "unit": "celsius" }
    },
    "state": "completed",
    "result": { "success": true, "message": "Mode applied" },
    "errorCode": null,
    "errorMessage": null,
    "createdAt": "2026-05-08T10:00:00.000Z",
    "updatedAt": "2026-05-08T10:00:02.000Z",
    "acknowledgedAt": "2026-05-08T10:00:01.000Z",
    "completedAt": "2026-05-08T10:00:02.000Z",
    "start": null,
    "end": null,
    "links": { "self": "/actions/act_hvac_004" }
  },
  "meta": { "requestId": "req_6jB0xKnA", "environment": "sandbox", "timestamp": "2026-05-08T10:00:03.000Z", "latencyMs": 11 }
}
The hold persists until you release it or push a different mode. follow_schedule is the canonical release.

Step 3: Release the hold

When the override is no longer needed, hand control back to the device’s schedule. follow_schedule is a command in the same envelope and carries no parameters.
curl -X POST https://api.amps.ai/hvac/device_hvac_001 \
  -H "x-api-key: sk_test_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "action": { "command": "follow_schedule" }
  }'
{
  "success": true,
  "data": {
    "id": "act_hvac_005",
    "deviceId": "device_hvac_001",
    "deviceType": "hvac",
    "command": "follow_schedule",
    "parameters": null,
    "state": "acknowledged",
    "createdAt": "2026-05-08T11:00:00.000Z",
    "links": { "self": "/actions/act_hvac_005" }
  },
  "meta": { "requestId": "req_7kC1yLoB", "environment": "sandbox", "timestamp": "2026-05-08T11:00:01.000Z", "latencyMs": 14 }
}
A follow-up read confirms the device is back on its own schedule. follow_schedule is immediate-only: its execution array is ["immediate"], so it takes neither start nor end. Releasing the schedule is something you do now, not something you defer. Supplying a start or end alongside it returns 422 EXECUTION_NOT_SUPPORTED.

Adjusting the hold

Push another operation mode with new values to raise or lower the setpoints, or switch from a band to a single-temperature hold. The new write supersedes the previous one. No explicit cancel needed.
curl -X POST https://api.amps.ai/hvac/device_hvac_001 \
  -H "x-api-key: sk_test_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "action": {
      "command": "heat",
      "parameters": { "target": { "value": 22, "unit": "celsius" } }
    }
  }'
If a previous push is still being applied, you get 409 CONFLICT with the in-flight action ID. Add onConflict: "cancel_and_replace" to drop the in-flight action and run the new one. Thermostats declare only cancel_and_replace, so queue_after returns 422 STRATEGY_NOT_SUPPORTED. See the conflict cookbook page for resolution.

Why this works

heat, cool, auto, and idle all map to one underlying operation: only one is active at a time, which is why pushing a new mode supersedes the old one and why onConflict governs an in-flight write. follow_schedule is a separate operation, so it cleanly relinquishes whatever mode was held. The whole flow is the canonical action model applied to a thermostat. The same read-pick-build-post loop drives a battery and an EV charger. See canonical actions and capabilities.

What next

EV charger power cap

Set the charging-power ceiling as a device setting.

Subscribe to webhooks

Get push.completed events on mode transitions.

Handle conflicts

Resolve 409s when an HVAC write is already in flight.

Canonical actions

Where HVAC commands sit in the canonical model.