Skip to main content

One webhook for the project

v2 has one webhook per project. It receives every event it is subscribed to, from every address: messages, conversations, calls, templates, campaigns, domains and invitations.
The 201 that creates it returns webhook.secret once. Keep it: later reads do not return it. POST /v2/webhook/secret rotates it, and the old one stops working at once. url must be HTTPS. An event name that does not exist is refused with 400, with the valid names in details.allowed.

Payload

No sender id appears anywhere in the payload. Project-level events (invitation.*, domain.*, broadcast.*) are not about one address: read data for them. The event names and their data are listed under WebhookEvent in the reference, and explained in Webhook events.

Signature

Every delivery carries X-Zavu-Signature, signed with the webhook’s secret:
v2 is HMAC_SHA256(secret, "{t}.{body}") over the raw body, and it is the default for a new v2 webhook. signatureVersion can also be v1 or v1+v2. Moving straight between v1 and v2 is refused with 400: go through v1+v2. Verification code is in Security.

Retries

A delivery that does not get a 2xx is retried, up to 5 attempts in total: after 1 minute, 5 minutes, 15 minutes and 1 hour. Each event has its own id; use it to skip a delivery you already processed.

Next to v1 webhooks

Setting up the v2 webhook is the opt-in. From then on each event goes to it in addition to any v1 sender webhook or v1 project webhook subscribed to the same event. They are separate deliveries with different event ids, and nothing is deduplicated. senderWebhooks on GET /v2/webhook lists the v1 sender webhooks still on. Once your v2 receiver works, switch them off in the same call:
They are only switched off. URL, events and secret stay, so v1 can turn one back on. DELETE /v2/webhook does not turn them back on. The v2 webhook is stored apart from the v1 project webhook (/v1/invitations/webhook). Neither API reads or writes the other’s.