Webhooks
Receive signed event notifications when things happen in your workspace.
Webhooks push signed JSON notifications to your systems when events happen in your workspace — no polling needed.
Setting up
A workspace admin creates webhooks under Org Admin → Webhooks: name, destination URL, and the list of events to subscribe to. On creation you receive an HMAC secret, shown only once — store it securely. The admin page shows the last 100 deliveries per webhook with status and attempts, and lets you send a test ping.
Delivery
- All deliveries are
POST application/json. - Headers:
X-Elio-Event(event name),X-Elio-Signature(sha256=<hex>HMAC of the raw body), andX-Elio-Delivery-Id(stable across retries — use it for idempotency). - Failures (any non-2xx) are retried 5 times with exponential backoff (~30s up to 6h).
- Respond within 12 seconds; redirects are not followed.
Verifying signatures
import { createHmac, timingSafeEqual } from "crypto";
function isValid(req, secret) {
const sig = req.headers["x-elio-signature"]; // "sha256=<hex>"
if (!sig || !sig.startsWith("sha256=")) return false;
const expected = "sha256=" + createHmac("sha256", secret)
.update(req.rawBody, "utf8")
.digest("hex");
const a = Buffer.from(sig);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}Always verify against the raw request body bytes — not a re-serialized parsed JSON.
Event catalog
| Event | When it fires |
|---|---|
agent.run.completed | An agent finishes successfully |
agent.run.failed | An agent run errors out |
quote.created | A new CRM quote is created |
quote.sent | A quote is emailed/sent to a client |
quote.accepted | A client accepts a quote |
contact.created | A new CRM contact is added |
meeting.transcribed | A meeting transcript becomes available |
workflow.run.completed | A workflow run finishes |
Some integrations also emit agent.chat.completed, crm.quote.synced, agent.scheduled_task.completed, and agent.scheduled_task.failed — list them explicitly in your events array to receive them.
Payload envelope
{
"id": "<uuid>",
"type": "quote.created",
"organizationId": "<org-uuid>",
"createdAt": "2026-05-11T17:45:12.000Z",
"data": { /* event-specific fields */ }
}Always validate type and organizationId server-side before acting on an event.