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

# Webhooks

> Receive events when an action finishes or a device's connection changes.

Amps sends an HTTP `POST` to your endpoint when an action reaches `completed` or `failed`, and when a device connects, reconnects, or disconnects. Use webhooks instead of polling `GET /actions/{actionId}`.

## Set up an endpoint

1. In the [dashboard](https://app.amps.ai), open **Settings → Webhooks**.
2. Pick the environment. Sandbox and live have separate endpoints.
3. Add your endpoint URL.
4. Copy the endpoint's signing secret (`whsec_...`) into your server's environment.

Events from a sandbox key go to your sandbox endpoints. Events from a live key go to your live endpoints. You can add more than one endpoint per environment.

## Events

| Event | Fires when |
| - | - |
| `push.completed` | An action reaches `completed`. |
| `push.failed` | An action reaches `failed`. |
| `device.connected` | An end user links a new device through Link UI. |
| `device.reconnected` | An end user links a device that was already connected. |
| `device.disconnected` | The device's manufacturer credentials stop working. |

Payloads for each are in [Events](/guides/webhooks/events). No event is sent when an action is created, starts, or is cancelled.

## Payload

The request body is the event's fields as flat JSON. There's no wrapper and no `type` field.

```json theme={null}
{
  "actionId": "action_qjSucnQFAk",
  "deviceId": "device_abc123",
  "deviceType": "battery",
  "command": "charge",
  "parameters": { "target": { "value": 80, "unit": "percent" } },
  "result": { "success": true },
  "completedAt": "2026-05-07T10:30:05.000Z"
}
```

Tell events apart by their fields. `errorCode` means `push.failed`. `actionId` without `errorCode` means `push.completed`. No `actionId` means a `device.*` event. See [Events](/guides/webhooks/events#identify-the-event).

## Handle a delivery

1. [Verify the signature](/guides/webhooks/verify-signatures) using the raw request body.
2. Skip it if you've already processed it.
3. Return a `2xx` quickly. Do slow work in the background.

Any other response, or no response, is retried with exponential backoff. You can see each delivery attempt in the dashboard, and resend from there.

## Duplicates

Deliveries are at least once, so the same event can arrive more than once.

| Event | Dedupe on |
| - | - |
| `push.completed`, `push.failed` | `actionId`. Each action sends one final event. |
| `device.*` | The `svix-id` header. It stays the same across retries. |

## Timing

Events are sent after a short delay. In live, every event arrives about 10 seconds after it happens. In sandbox, the delay is longer so you have time to start a tunnel to your local machine: about 3 minutes for push events and `device.disconnected`, and about 1 minute for `device.connected` and `device.reconnected`.

## Test in sandbox

Push to a sandbox device to get a `push.completed`. To get a `push.failed`, add a `sandbox` block to the push:

```bash theme={null}
curl -X POST https://api.amps.ai/battery/device_abc123 \
  -H "x-api-key: $AMPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": { "command": "charge" },
    "sandbox": { "result": "failed", "errorCode": "DEVICE_OFFLINE" }
  }'
```

An immediate push like this one returns the simulated error straight away, and the `push.failed` follows. Add a `start` to get a `202` first and the failure when the action runs.

## Next steps

<CardGroup cols={2}>
  <Card title="Verify signatures" icon="shield" href="/guides/webhooks/verify-signatures">
    Confirm each request came from Amps.
  </Card>

  <Card title="Events" icon="list" href="/guides/webhooks/events">
    Every event and its payload.
  </Card>

  <Card title="Push" icon="arrow-up" href="/guides/push">
    Action states and how actions finish.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.