> ## Documentation Index
> Fetch the complete documentation index at: https://docs.amps.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Types

> Webhook event reference. push.completed, push.failed, and the device connection events fire with flat payloads; the event type rides in the svix headers.

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.

```json theme={null}
{
  "deviceId": "device_abc123",
  "deviceType": "battery",
  "timestamp": "2026-06-01T10:30:00.000Z"
}
```

### `device.reconnected`

Fires when an already-registered device's credentials are refreshed.

```json theme={null}
{
  "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.

```json theme={null}
{
  "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`.

```json theme={null}
{
  "actionId": "act_abc123",
  "deviceId": "device_xyz789",
  "deviceType": "hvac",
  "command": "auto.maintain",
  "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 failure is reported through top-level `errorCode` and `errorMessage`; `result` is `null` on a failed action. The `errorMessage` is the API-owned message for the code; the manufacturer's raw text never reaches the payload.

```json theme={null}
{
  "actionId": "act_abc123",
  "deviceId": "device_xyz789",
  "deviceType": "hvac",
  "command": "auto.maintain",
  "parameters": {
    "heatSetpoint": { "value": 20, "unit": "celsius" },
    "coolSetpoint": { "value": 24, "unit": "celsius" }
  },
  "result": null,
  "errorCode": "DEVICE_OFFLINE",
  "errorMessage": "The device is currently offline at the manufacturer.",
  "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.

<Tip>
  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`).
</Tip>

## Common error codes

Codes that commonly appear as `errorCode` on a `push.failed` event. Every code is drawn from the same canonical taxonomy the API uses on push responses, and the `errorMessage` is the API-owned message for the code. See the [device error codes](/reference/error-codes) reference for the full set and the exact message per code.

<ResponseField name="DEVICE_OFFLINE" type="string">
  The device is currently offline at the manufacturer.
</ResponseField>

<ResponseField name="COMMAND_NOT_SUPPORTED" type="string">
  The device manufacturer does not support this command.
</ResponseField>

<ResponseField name="TIMEOUT" type="string">
  The device manufacturer did not respond in time.
</ResponseField>

<ResponseField name="RATE_LIMITED" type="string">
  The device manufacturer is rate limiting requests. Please try again shortly.
</ResponseField>

<ResponseField name="INVALID_CREDENTIALS" type="string">
  The device manufacturer rejected the supplied credentials.
</ResponseField>

## Webhook payload fields

The body is flat. These are the top-level fields a push event carries.

<ResponseField name="actionId" type="string" required>
  Identifier of the action that reached a terminal state. Dedupe push events by this value, or by the `svix-id` header.
</ResponseField>

<ResponseField name="deviceId" type="string" required>
  Identifier of the device the action targeted.
</ResponseField>

<ResponseField name="deviceType" type="string" required>
  The clean device type, for example `battery`, `hvac`, or `ev_charger`.
</ResponseField>

<ResponseField name="command" type="string" required>
  The canonical command that was dispatched, for example `charge` or `auto.balance`.
</ResponseField>

<ResponseField name="parameters" type="object">
  The constraints-only parameters for the command, or `null`.
</ResponseField>

<ResponseField name="result" type="object">
  The OEM result envelope on `push.completed` (`result.success` is `true`). It is `null` on `push.failed` — read `errorCode` and `errorMessage` for the failure.
</ResponseField>

<ResponseField name="completedAt" type="string">
  ISO 8601 timestamp for the terminal transition on a `push.completed` event.
</ResponseField>

<ResponseField name="errorCode" type="string">
  Machine-readable failure code, present on `push.failed`.
</ResponseField>

<ResponseField name="errorMessage" type="string">
  Human-readable failure description, present on `push.failed`.
</ResponseField>

<ResponseField name="failedAt" type="string">
  ISO 8601 timestamp for the terminal transition on a `push.failed` event.
</ResponseField>

## 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`.

```javascript theme={null}
// 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

<CardGroup cols={2}>
  <Card title="Webhook Overview" icon="webhook" href="/guides/webhooks/receive">
    Learn about webhook setup
  </Card>

  <Card title="Security" icon="shield" href="/guides/webhooks/verify-signatures">
    Verify webhook signatures
  </Card>
</CardGroup>
