Skip to main content
Webhook bodies are flat. The fields below are the body verbatim, delivered as the HTTP POST body. The event type and the per-delivery ID ride in the svix-id, svix-timestamp, and svix-signature headers, not in the body. There is no event or data envelope to unwrap: a field like command sits at the top level, so you read body.command, never body.data.command.

Device connection events

Connection events track a device’s link to your account. They carry the device identifiers plus a timestamp, and device.disconnected adds a reconnectionUrl when the OEM’s auth flow supports re-entry.

device.connected

Fires when a new device finishes registration through the Auth Journey.
{
  "deviceId": "device_abc123",
  "deviceType": "battery",
  "timestamp": "2026-06-01T10:30:00.000Z"
}

device.reconnected

Fires when an already-registered device’s credentials are refreshed.
{
  "deviceId": "device_abc123",
  "deviceType": "battery",
  "timestamp": "2026-06-01T12:00:00.000Z"
}

device.disconnected

Fires when stored credentials become invalid. The body carries a reconnectionUrl pointing at the Auth Journey in reconnection mode when the OEM’s auth flow supports re-entry.
{
  "deviceId": "device_abc123",
  "deviceType": "battery",
  "timestamp": "2026-06-01T11:00:00.000Z",
  "reconnectionUrl": "https://auth.amps.ai/?reconnect=true&token=..."
}

Action events

Webhooks are only sent for actions that reach a terminal state (completed or failed). When an action is first created, it starts in the acknowledged state, but no webhook is sent at that time. You can check the action status by polling the API at GET /actions/{actionId} (one device-agnostic route for every device type), but webhooks are only delivered when the action completes or fails.

push.completed

Fires when an action completes successfully. This webhook is only sent when the action reaches the completed terminal state. The body mirrors the dispatch and the read response: the canonical command, the constraints-only parameters, the clean deviceType, and a result.
{
  "actionId": "act_abc123",
  "deviceId": "device_xyz789",
  "deviceType": "hvac",
  "command": "auto",
  "parameters": {
    "heatSetpoint": { "value": 20, "unit": "celsius" },
    "coolSetpoint": { "value": 24, "unit": "celsius" }
  },
  "result": {
    "success": true,
    "message": "Command executed successfully"
  },
  "completedAt": "2026-06-01T10:30:05.000Z"
}

push.failed

Fires when an action fails to complete. This webhook is only sent when the action reaches the failed terminal state. The body adds top-level errorCode and errorMessage, and result carries the OEM error envelope (result.success is false).
{
  "actionId": "act_abc123",
  "deviceId": "device_xyz789",
  "deviceType": "hvac",
  "command": "auto",
  "parameters": {
    "heatSetpoint": { "value": 20, "unit": "celsius" },
    "coolSetpoint": { "value": 24, "unit": "celsius" }
  },
  "result": {
    "success": false,
    "error": {
      "code": "DEVICE_OFFLINE",
      "message": "Device is currently offline"
    }
  },
  "errorCode": "DEVICE_OFFLINE",
  "errorMessage": "Device is currently offline",
  "failedAt": "2026-06-01T10:30:05.000Z"
}

Action states

When you send a push command via the API, the action goes through the following states:
  1. acknowledged - The action has been created and is being processed immediately. No webhook is sent at this stage.
  2. scheduled - The action has a start time and will execute at that time. Scheduled actions (battery, EV charger, or HVAC) can be cancelled via POST /actions/{actionId}/cancel.
  3. completed - The action completed successfully. A push.completed webhook is sent.
  4. failed - The action failed to complete. A push.failed webhook is sent.
  5. cancelled - The action was cancelled before execution. No webhook is sent.
To check the status of an action while it’s still processing, use the action polling endpoint, GET /actions/{actionId} (one device-agnostic route for every device type). Webhooks are only sent for terminal states (completed or failed).

Common error codes

DEVICE_OFFLINE
string
Device is currently offline and cannot receive commands
COMMAND_NOT_SUPPORTED
string
The requested command is not supported by this device model
TIMEOUT
string
The command timed out waiting for device response
RATE_LIMITED
string
Too many commands sent to the device in a short period
AUTHENTICATION_FAILED
string
Authentication with the OEM failed

Webhook payload fields

The body is flat. These are the top-level fields a push event carries.
actionId
string
required
Identifier of the action that reached a terminal state. Dedupe push events by this value, or by the svix-id header.
deviceId
string
required
Identifier of the device the action targeted.
deviceType
string
required
The clean device type, for example battery, hvac, or ev_charger.
command
string
required
The canonical command that was dispatched, for example charge or auto.balanced.
parameters
object
The constraints-only parameters for the command, or null.
result
object
required
The OEM result envelope. result.success is true on push.completed and false on push.failed.
completedAt
string
ISO 8601 timestamp for the terminal transition on a push.completed event.
errorCode
string
Machine-readable failure code, present on push.failed.
errorMessage
string
Human-readable failure description, present on push.failed.
failedAt
string
ISO 8601 timestamp for the terminal transition on a push.failed event.

Handling webhooks

Idempotency

The per-delivery ID arrives in the svix-id header. Use it as the idempotency key to drop duplicates. Push events can also be deduped by actionId.
// Store processed delivery IDs from the svix-id header.
const processedDeliveries = new Set();

function handleWebhook(req) {
  const deliveryId = req.headers["svix-id"];
  if (processedDeliveries.has(deliveryId)) {
    return; // Already processed
  }

  // Process the flat body
  processEvent(req.body);

  // Mark as processed
  processedDeliveries.add(deliveryId);
}

Response requirements

Your webhook endpoint must:
  • Return 200 OK for successful processing
  • Respond within 30 seconds
  • Handle duplicate deliveries gracefully

Next steps

Webhook Overview

Learn about webhook setup

Security

Verify webhook signatures