Skip to main content
Webhooks notify your server when call events happen. You register an endpoint, Wave POSTs signed JSON to it, and retries on failure.

Register an endpoint

Webhook endpoints are managed in the Wave dashboard under Webhooks: add a URL, choose the events, and copy the signing secret (shown once). The URL must be a public https URL. Wave refuses a URL that points to a loopback, private, link-local or other internal address (400 WEBHOOK_URL_INVALID). Wave checks the address again before each delivery, and does not follow redirects.

One environment per endpoint

Each endpoint belongs to one environment: sandbox or production. It receives only the events of its environment, so test events never reach your live endpoint. In a production project, the dashboard shows the endpoints of the selected Environment view, and a new endpoint takes that view’s environment.
  • You can add the same URL once in each environment; each copy has its own signing secret.
  • The limit of 5 endpoints counts per environment.
  • A sandbox project cannot add a production endpoint. Add it on the Go-Live form instead: it stays inactive until Wave approves your request, and the form shows its signing secret once. If Wave rejects the request, the endpoint is removed.

Events

You can subscribe to any event below (max 5 endpoints per project). The How it is sent column tells you what an event needs before it reaches you:
  • Sent directly by the API — the API sends the event as soon as the action happens.
  • Sent through the event stream (enabled per environment) — the event comes from the voice engine or the messaging provider through Wave’s event stream. Where the event stream is not enabled, these events are not sent.
  • Not sent yet — you can subscribe now, but nothing sends the event yet.
Sandbox keys. A sandbox callback to +966500000014 sends a simulated call.initiated → call.answered → call.ended sequence; one to +966500000015 sends call.initiated → call.missed; one to +966500000016 sends call.initiated → call.timeout. These are sent directly by the API, with "simulated": true in data.

Payload

Each delivery is a JSON body with the event type, the environment and a data object. The X-Wave-Event-Id header carries a unique id for idempotency.
environment sits next to event, outside data. It is "sandbox" or "production". Wave takes it from the call: a call that a sandbox key placed is "sandbox", and inbound calls are "production". The voice_auth.completed verdict webhook takes it from the key of the challenge. Every event carries the environment of its call, including the Verify, callback, voicemail, conference, IVR and transfer events.

Verifying the signature

Every delivery is signed. The X-Wave-Signature header is sha256=<hex> — an HMAC-SHA256 of the raw request body using your endpoint’s signing secret (whsec_…). Verify it with a constant-time compare before trusting the payload:
Compute the HMAC over the raw body bytes, before any JSON parse/re-serialize — re-stringifying can change the bytes and break the check.

Retries & dead-letter

Each attempt has a 10-second timeout. Failed deliveries retry up to 5 attempts on a backoff ladder, then dead-letter: Exhausted deliveries are dead-lettered (retained 72h) and appear in the dashboard’s delivery logs, marked Dead-lettered.