Configure webhooks
Manage the full webhook lifecycle via the public API — or use the dashboard Webhooks page (/webhooks). A webhook is configured per number; once configured, events are delivered automatically (no API-key linking is required).

The Webhooks page — create, edit, deactivate, or delete a webhook and inspect its delivery events.
Endpoints
Number scoping
A webhook belongs to a single WhatsApp number.- With a number-scoped key the number comes from the key itself; a
whatsappNumberIdin the body must match it (else 400NUMBER_MISMATCH). - With a tenant-scoped key, pass the target number via the
whatsappNumberIdbody field or thex-whatsapp-number-idheader — omitting both returns 400NUMBER_REQUIRED; a number outside your tenant returns 404NUMBER_NOT_FOUND. GET /v1/webhookslists only the webhooks visible to the key’s scope (a number-scoped key sees only its own number’s webhooks). A webhook outside the key’s scope returns 404WEBHOOK_NOT_FOUND.
Examples
Event gating
- On
PATCH,eventsreplaces the whole subscription list (it is not a merge). - Events the number’s provider cannot emit are silently dropped.
Rules and errors
The signing
secret is never returned by any of these endpoints.Verify the signature
The signing secret is configured on the dashboard’s Webhooks page — it cannot be set or read through/v1/webhooks (the API strips it from every response). When a secret is set, every delivery includes the header x-pilot-status-signature: the hex-encoded HMAC-SHA256 of the raw request body, keyed with the secret. Compute the HMAC over the raw bytes exactly as received (before any JSON parsing) and compare with a constant-time comparison:
Node
Idempotency-Key header — stable per event — use it to deduplicate retries.
Dashboard
Everything above is also available in the dashboard at/webhooks: create/edit webhooks per number, pick events, pause/resume, and inspect delivery logs. The New/Edit Webhook UI includes the notice that message.read only fires when the recipient has WhatsApp read receipts enabled.