Skip to main content

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.

Overview

Skip the poll loop. Subscribe to webhooks and Amps delivers action lifecycle events to your endpoint as they happen. Two events fire: push.completed and push.failed. Both arrive only when an action reaches a terminal state, typically within 10 seconds in live (3 minutes in sandbox). Every delivery is signed with an HMAC-SHA256 signature, retried with exponential backoff on non-2xx, and stamped with an event ID delivered in the svix-id header for idempotency.

Step 1: Register the endpoint

Add the webhook URL in the Amps AI Dashboard under Webhooks settings. Pick the events to subscribe to (push.completed, push.failed) and copy the webhook secret. Store it in an environment variable; never commit it.

Step 2: Receive a push.completed payload

When a battery action completes, you receive a POST with this body. The event type and event ID are delivered in the svix-id, svix-timestamp, and svix-signature headers, not the body:
{
  "actionId": "act_inflight_002",
  "deviceId": "dev_abc123",
  "actionType": "battery:set_operation_mode",
  "parameters": {
    "mode": "charge",
    "target": { "value": 90, "unit": "percent" },
    "power": { "value": 3, "unit": "kw" }
  },
  "result": {
    "success": true,
    "message": "Mode applied"
  },
  "completedAt": "2026-05-08T22:00:05.000Z"
}
A push.failed payload mirrors the shape but carries an error object instead of result:
{
  "actionId": "act_inflight_002",
  "deviceId": "dev_abc123",
  "actionType": "battery:set_operation_mode",
  "parameters": {
    "mode": "charge",
    "target": { "value": 95, "unit": "percent" }
  },
  "error": {
    "code": "SCHEDULER_ACTIVE",
    "message": "Native scheduler is active; clear it before issuing a direct command."
  },
  "failedAt": "2026-05-08T22:00:32.000Z"
}

Step 3: Verify the signature

Every delivery includes three headers (svix-id, svix-timestamp, svix-signature). Verify the signature before trusting the body; the SDK reads all three. The signature is HMAC-SHA256 of {id}.{timestamp}.{rawBody} keyed by your webhook secret.
import express from "express";
import { Webhook } from "svix";

const app = express();
const wh = new Webhook(process.env.WEBHOOK_SECRET);
const seen = new Set();

app.post("/webhooks", express.raw({ type: "application/json" }), (req, res) => {
  let payload;
  try {
    payload = wh.verify(req.body, req.headers);
  } catch (err) {
    return res.status(400).send("Invalid signature");
  }

  const eventId = req.headers["svix-id"];
  if (seen.has(eventId)) {
    return res.status(200).send("duplicate");
  }
  seen.add(eventId);

  // Route by inspecting the payload shape: completed payloads carry `result`, failed payloads carry `error`.
  if (payload.result) {
    handleCompleted(payload);
  } else if (payload.error) {
    handleFailed(payload);
  }

  res.status(200).send("OK");
});
For deeper signature internals (timestamps, replay protection, manual verification), see Webhook Security.

Step 4: Make the endpoint idempotent

Webhooks are at-least-once. Retries fire on any non-2xx response, a timeout (>30s), or a transient network failure. Use the svix-id header as the idempotency key and persist seen IDs alongside the work the webhook triggers.
async function handleCompleted(payload, eventId) {
  const seen = await db.events.findOne({ eventId });
  if (seen) return;

  await db.events.insertOne({
    eventId,
    actionId: payload.actionId,
    deviceId: payload.deviceId,
    completedAt: payload.completedAt,
  });

  await notifyUserActionCompleted(payload);
}
In production, store seen IDs in an external store. In-process memory will not survive across instances.

Retry behaviour

ConditionEffect
Endpoint returns 2xx within 30 secondsDelivery succeeds, no retry.
Endpoint returns non-2xx or times outRetried with exponential backoff.
Repeated failuresBacked off and surfaced in the dashboard delivery log.
Always respond 200 OK as soon as the signature verifies and the event is recorded. Push business logic (email, dashboard updates) to async workers so the response stays inside the 30-second window.

What next

Webhook security details

Manual signature verification, timestamp checks, secret rotation.

Webhook event types

Full payload reference for every webhook event.

Charge overnight

A scheduled action that fires push.completed when the window closes.

Handle conflicts

push.failed events surface SCHEDULER_ACTIVE and other conflict codes.