This page is the platform mechanism — signing, retries, the delivery log. For
the voice event catalogue specifically (what
voice.call.* means and when each
fires), see Voice webhooks.Choosing event types
Every event type is a<vertical>.<subject>.<action> token, and the set of
valid tokens is a server-side registry. The picker in each console renders
from that registry, so what you can select is exactly what something can
actually send.
You can subscribe to * for everything in the vertical, or use dot-bounded
globs such as voice.call.*.
Verifying the signature
Every delivery carries three headers:These header names are literal, on every brand. They are not brand-swapped,
so do not substitute your own brand name — match on
X-Clutchcall-Signature
exactly or your verification will never find the header.- HMAC the raw bytes. Parse the JSON after verifying. If you decode and re-serialize first, key order and spacing change and the MAC will not match.
- Compare in constant time, and reject a timestamp that is too far from now — that check is what makes the replay binding useful.
whsec_…. It is minted server-side, stored sealed, and
shown in cleartext exactly once — when you create the endpoint or rotate
the secret. There is no way to read it back afterwards; if you lose it, rotate.
Retries
A delivery is attempted up to 6 times. The schedule, with ±20% jitter:
Return 2xx to acknowledge. Anything else — including a timeout, and the
request timeout is 10 seconds — counts as a failure and schedules a retry.
After 20 consecutive failures the endpoint auto-pauses and its status
becomes
failing. That is a circuit breaker, not a deletion: nothing is
retried against a dead endpoint until you resume it from the console. Fix the
receiver, then resume.
Because retries exist, your handler must be idempotent. Deduplicate on
X-Clutchcall-Delivery, which is stable across attempts of the same delivery.
When something does not arrive
Each console’s Webhooks screen has a delivery log showing status, attempt count, the last response code, the last error, and when the next attempt is due. Use it before assuming an event never fired — the common answers are that the endpoint returned a non-2xx, or that it auto-paused after a run of failures. You can redeliver any past delivery from that log, and send a test event to an endpoint without waiting for real traffic.Endpoint URLs we refuse
A webhook URL must behttp(s) and must resolve to a routable address.
Link-local, cloud metadata and loopback addresses are refused unconditionally;
private RFC1918 ranges are refused unless the deployment is on-prem and enables
it.
The check runs twice — when you save, so you see the error in the form, and
again at send time, so a hostname repointed after creation still cannot reach
inward.
Related
- Voice webhooks — the voice event catalogue
- Telemetry — for metrics rather than events