Docs
Webhooks
Outbound: events sent to you
Add an endpoint in Settings → Webhooks (or POST /v1/webhooks) and choose the events it receives, or * for all. The signing secret (whsec_…) is shown once. Endpoints must use https and a public address.
Events: account.dormant, account.declining, nps.answered, invoice.overdue, record.created, record.updated, record.archived, deal.won, deal.lost, deal.stage_changed, activity.created, meeting.recorded, meeting.upcoming, insight.captured, run.finished, approval.needed, account.state_changed, signal.fired, sequence.replied, booking.no_show, quote.stalled, call.completed.
Each delivery is a POST with a JSON body, signed per Standard Webhooks:
webhook-id: the event's id (use it to drop duplicates);webhook-timestamp: seconds since 1970;webhook-signature:v1,and the base64 HMAC-SHA256 ofid.timestamp.body, keyed with the secret afterwhsec_. During the 24 hours after you rotate the secret, both secrets sign, separated by a space.
import { createHmac, timingSafeEqual } from "node:crypto";
// body: the raw request body, as a string, before any JSON parsing.
function verify(secret, headers, body) {
const id = headers["webhook-id"], ts = headers["webhook-timestamp"], sigs = headers["webhook-signature"];
if (!id || !ts || !sigs) return false;
const t = Number(ts);
if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300) return false; // more than five minutes off
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const want = createHmac("sha256", key).update(`${id}.${ts}.${body}`).digest();
return sigs.split(" ").some((sig) => {
const got = Buffer.from(sig.replace(/^v1,/, ""), "base64");
return got.length === want.length && timingSafeEqual(got, want);
});
}Answer with any 2xx within 15 seconds. A failed delivery is tried again after 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours, 10 hours (7 more attempts), then marked failed. Deliveries are kept for 30 days (GET /v1/webhooks/{id}/deliveries) and can be sent again (POST /v1/webhook-deliveries/{id}/resend). Pause an endpoint with enabled: false.
Inbound: start an agent from another system
Give an agent a webhook trigger (POST /v1/agents/{id}/triggers, or in the agent's settings). Its URL and secret are shown once. The other system posts JSON to that URL with Authorization: Bearer <secret>. The trigger maps the body's fields to the agent's inputs; the body is data for the run, never instructions. Send an Idempotency-Key header so a retried call doesn't start a second run. Zapier, Make and n8n work the same way. Recent firings, including duplicates and ones refused because the agent isn't live, are at GET /v1/triggers/{id}/fires; POST /v1/triggers/{id}/rotate-secret replaces the secret.
Approvals, limits and what an agent may do alone: Approvals and policy.