Developers · Webhooks
A call event that fires is not the same as one that arrives.
Zumu’s voice AI webhooks sign every delivery, retry the ones that fail, and put a person in the loop the moment retries run out, so the callback your CRM was counting on does not just vanish into a 500 nobody noticed.
- HMAC signed, every delivery
- Secret rotation with overlap
- Dead-letter instead of a silent drop
- Replay from the dashboard or the API
The delivery ledger
What happened to two events, in full
One endpoint recovered on its own. The other needed a person to notice. Below is the same attempt-by-attempt record you would see for either one in your own deliveries viewer.
- Attempt 1POST /webhooks/zumu500
- Backoff30s before the next attempt
- Attempt 2POST /webhooks/zumu200 OK
- VerifiedHMAC-SHA256 against X-Zumu-SignatureMatched the previous secret, inside its rotation overlap window
- Attempt 1POST /webhooks/zumu500
- Attempt 2POST /webhooks/zumuTimeout
- Attempt 3POST /webhooks/zumu500
- Retries exhaustedMoved to the dead-letter queueVisible in the deliveries viewer, not dropped
- ReplayedAn operator resent it from the dashboard
- Attempt 4POST /webhooks/zumu200 OK
One endpoint recovered on its own. The other needed a person to notice and resend it. Neither event just disappeared.
Signing and rotation
A payload you can't verify is a payload you can't trust
Every delivery is signed. Rotating the secret does not mean picking a day to break verification.
Every delivery is signed
Each request carries an HMAC signature in X-Zumu-Signature, alongside X-Zumu-Event-Id, X-Zumu-Event-Type, and X-Zumu-Schema-Version. Compute the same signature over the raw request body with your endpoint secret and compare it before you trust the payload.
Rotate a secret without a gap
Generate a new secret whenever you need to. During the rotation overlap window, a delivery verifies successfully against either the current or the previous secret, so you can update your endpoint on your own schedule instead of racing a hard cutover.
Configurable payload profiles
Each endpoint can shape its own payload profile, so you receive the fields your integration actually needs instead of parsing a payload built for someone else.
Retries, dead-letter, replay
A down endpoint is not a lost event
Zumu assumes your endpoint will fail sometimes and builds the delivery pipeline around that, instead of dropping the event the moment it does.
Failures retry with backoff
A 500, a timeout, or a dropped connection counts as a failed attempt, not a lost event. Zumu retries the delivery with increasing backoff between attempts.
Exhausted retries land in a dead-letter state
When an endpoint stays down long enough that retries run out, the event does not vanish. It moves to a dead-letter state, visible in the deliveries viewer and on the webhooks tab of the call it belongs to.
Replay from the dashboard or the API
A dead-lettered delivery, or any past delivery, can be resent on demand. An operator who just fixed the endpoint does not have to wait for the next real call to prove the fix worked.
What you can subscribe to
Events, grouped by what they tell you
A representative set, not an exhaustive schema reference. Every event here carries the same signature and delivery guarantees described above.
Call lifecycle
- call.started
- call.ended
- call.completed
The moments most integrations subscribe to first: a call begins, a call ends, and a call finishes processing with its full record attached.
Call intelligence
- call.flagged
Fires when a call matches one of your flag rules, graded by an LLM rather than a fixed keyword list. Covered in its own section below.
Handoff and tools
- handoff.initiated
- tool.called
- transcript.updated
The events that let an external system follow what the agent is doing mid-call: a transfer starting, a tool firing, or the transcript gaining a new turn.
Operational
- error.occurred
- webhook.test
- carrier.updated
Housekeeping events: a runtime error worth knowing about, a manual test delivery you can trigger yourself, and a change on the carrier side of a call.
LLM-graded flag rules
Subscribe to a sentence, not a keyword list
The rule on the right is a real example of the kind of thing you can write, not a hypothetical.
- Write the rule in plain language
- A flag rule is a sentence, not a query. "The caller sounded ready to cancel" or "the agent could not verify the caller’s identity" is a complete rule on its own.
- An LLM grades every call against it
- Each rule carries a severity of info, warn, or critical. An LLM reads the call against the rule you wrote and decides whether it matches, the way a person skimming a transcript would.
- A match fires call.flagged
- When a call matches, it fires the same call.flagged event your other integrations already listen for, with the rule and severity attached, so a flagged call reaches the same webhook pipeline as everything else.
Flag rule
The caller sounded ready to cancel
This is a judgment call from a model reading a transcript, not a certified accuracy figure. Treat a flag as a reason to look, not a verdict.
Verifying a delivery
The whole check, in one function
Swap in your framework's raw-body access and this runs as written. No package to install.
import crypto from 'node:crypto'// secrets = [currentSecret, previousSecret] inside a rotation overlap windowfunction isValidSignature(rawBody, signature, secrets) { return secrets.some((secret) => { const expected = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex') const expectedBuffer = Buffer.from(expected, 'hex') const signatureBuffer = Buffer.from(signature, 'hex') return ( expectedBuffer.length === signatureBuffer.length && crypto.timingSafeEqual(expectedBuffer, signatureBuffer) ) })}Reject the delivery if isValidSignature returns false. Do not parse the body into JSON before you verify it, since re-serializing it can change the bytes the signature was computed over.
Where this fits
Webhooks are one surface of the developer platform
- Platform API
The REST surface behind the dashboard
Everything a webhook tells you after the fact, the API can also tell you on demand: calls, transfers, agent config, and the OpenAPI spec that documents all of it.
Read the API docs - MCP server
Query the same events from Claude Code or Cursor
The MCP server reaches the same calls and transcripts a webhook fires on, so you can look one up from your editor instead of building a second dashboard.
See the MCP server - Platform
How the rest of the platform handles failure
Retries and dead-lettering are not unique to webhooks. See the same discipline applied to calls, transfers, and provider fallbacks.
Read about reliability
Questions
The delivery mechanics, answered plainly
Book a demo
Bring us the webhook that failed quietly
Show us the integration where a call event never showed up, and nobody knew until a customer complained. We will wire up the same event with a signed delivery, real retries, and a dead-letter queue you can actually see, while you watch it happen.
- No credit card for the demo
- You see every delivery attempt, not just the successful ones