Deliveries fail with HTTP 401 on my side
95% of the time: signature mismatch from framework body re-parse. Your framework (Express, FastAPI, Rails, etc.) is probably parsing the JSON body before your handler sees it, then re-serializing when you compute the HMAC. Re-serialization drifts whitespace or key order → signature mismatch. Fix: verify against the raw bytes. In Express, useexpress.raw({ type: "application/json" }). In FastAPI, use
await request.body() before any JSON parsing. See
signature verification for code.
Second most common: clock skew. Your server’s clock is off by
more than 5 minutes. Run timedatectl status (Linux) or check
Windows Time service. Sync with NTP.
Every delivery fails with 404
Your webhook URL is wrong. Check the dashboard → Webhooks → the subscription → URL field. A typo in the path or a missing route in your app returns 404 on our side, which we dead-letter without retry (see retries).Deliveries were working, now they’re all failing
Check the delivery log
Dashboard → Webhooks → Delivery log. Click a failed row to see the
HTTP status and response snippet. Often your handler logs the
error body there.
Check if auto-disable fired
If the subscription shows
disabled_at set, you crossed the
consecutive-failures threshold. Re-enable from the dashboard
after fixing the root cause.I got duplicate events
Expected. Retries reuse the sameevent_id. Also:
- At-least-once delivery — we don’t guarantee exactly-once. If your 200 response was lost in the network, we’ll retry.
- Parallel subscriptions — each subscription receives its own delivery. Two subs to the same URL will POST twice for the same event.
event_id in your handler. Store processed IDs in
Redis or DB with a TTL >= 7.5 hours (our total retry window).
I’m missing events I should have received
Is the subscription subscribed to that event type?
Is the subscription subscribed to that event type?
Dashboard → Webhooks → subscription → Event types. The full
list is in the event catalog.
Is the subscription disabled?
Is the subscription disabled?
Look for
disabled_at or is_active: false. Re-enable if appropriate.Did the event fire at all?
Did the event fire at all?
Some events have preconditions — e.g.
call.ended only fires on
calls that reached CHANNEL_HANGUP. A call that never answered
fires call.started and nothing else.Is the delivery still pending?
Is the delivery still pending?
Delivery log will show
status: pending or status: failed with a
next_retry_at. The retry sweep fires every 30s.Did auto-disable kick in since your last successful delivery?
Did auto-disable kick in since your last successful delivery?
See above.
Force a test delivery
Dashboard → Webhooks → your subscription → Test fire. We POST a synthetic event (event_id prefixed withtest_) to your endpoint
and show you the outcome right in the dashboard — HTTP status,
response body, duration. Lets you debug without waiting for real
events.
My signing_secret is leaked or lost
Lost: we can’t recover it — only a hash lives on our side. Delete and recreate the subscription. Leaked: delete the subscription immediately. Recreate with a new URL if you can (so attackers who captured the old URL also need to rediscover the new one). Signing-secret rotation without downtime is a v1.1 feature.Still stuck?
Emailsupport@yotel.in with:
- The
X-Zetta-Deliveryheader value from a failing delivery - Your subscription ID (from the dashboard URL)
- Timestamp range of the failures