Webhooks
Allerto posts JSON events to the URL in the agent's delivery (or to a call's callback_url).
| Event | When |
|---|---|
call.completed | Once per call, when it has ended for good: with outcome, result, summary, sentiment |
{
"id": "evt-uuid",
"type": "call.completed",
"version": "2",
"created_at": "2026-09-21T14:29:14Z",
"livemode": true,
"partner_id": "…",
"call": { "…": "the call object, see Calls and campaigns" }
}
livemode: false marks events produced by test keys. For inbound agents with review: on_issues, the event is sent after an operator approves the data when something was missing.
Signing secret
One secret per account signs every event:
POST /v1/webhook-secret → {"secret": "whsec_…"}
allerto webhook-secret rotate
It is shown once. Rotating takes effect immediately: every delivery from then on, including retries of events that failed before the rotation, is signed with the new secret. Update your receiver right after rotating, then retry failed events. An agent whose delivery uses a webhook cannot be published until a secret exists.
Verify every request
Headers:
Content-Type: application/json
Idempotency-Key: <event id>
X-Allerto-Event-Id: <event id>
X-Allerto-Timestamp: <unix seconds>
X-Allerto-Signature: sha256=<hex HMAC-SHA256 of "<timestamp>.<raw body>">
Node.js:
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody, headers, secret) {
const ts = headers["x-allerto-timestamp"];
const got = Buffer.from(
String(headers["x-allerto-signature"]).replace(/^sha256=/, ""),
"hex",
);
const want = createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest();
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
return fresh && got.length === want.length && timingSafeEqual(got, want);
}
Python:
import hmac, hashlib, time
def verify(raw_body: bytes, headers, secret: str) -> bool:
ts = headers["X-Allerto-Timestamp"]
got = headers["X-Allerto-Signature"].removeprefix("sha256=")
want = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest()
return abs(time.time() - int(ts)) < 300 and hmac.compare_digest(got, want)
Always verify against the raw body, before parsing JSON.
Delivery guarantees
- At least once: store the event id and ignore repeats. The id and payload never change between retries; timestamp and signature do.
- Any
2xxacknowledges. Redirects are not followed. Timeout: 10 seconds. - Up to 5 attempts with growing delays (15 s, 30 s, 60 s, …, max 1 h).
- Destinations must be HTTPS on port 443 and resolve to public addresses.
GET /v1/events(orallerto events list) shows recent events and their delivery status.
Email delivery
Inbound agents can also send each result by email (delivery.mode: "email" or "both"), with the subject and introduction you configure and, optionally, a short AI summary. Test keys never send emails.