Skip to main content
Webhooks push events to your server as they happen, so you never have to poll. Kallabot signs every delivery with the Standard Webhooks scheme, retries failures for about 27 hours, and keeps every event for 30 days so you can replay what you missed.

Event catalogue

Every event type, with a payload example.

Set up in the dashboard

No code: add an endpoint in Settings and send a test.

Create an endpoint

The response is 201 with the endpoint and its signing secret (whsec_…). The secret is returned only now and when you rotate it; store it somewhere safe.

What a delivery looks like

Each event is one POST with a JSON body:

Verify the signature

Always verify before trusting a delivery. The signature is an HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{raw body}, keyed with the base64-decoded part of your secret after whsec_, then base64-encoded and prefixed v1,.
Verify against the raw request body, exactly as received. Parsing the JSON and re-serializing it changes the bytes and breaks the signature.

With the Kallabot SDK

The SDKs verify the signature and timestamp and return a typed event.

With the Standard Webhooks library

Standard Webhooks publishes libraries for most languages. They check the signature and the timestamp for you.

Without a library

Reject deliveries older than five minutes: it stops someone replaying a captured request later.

Respond fast, work later

  • Answer with any 2xx status within 15 seconds. Anything else, a timeout or a redirect counts as a failure. Redirects are not followed.
  • Put the event on a queue and return straight away. Don’t make the call to your CRM before responding.
  • The same event can arrive more than once (after a timeout, for example). Store webhook-id and skip ids you’ve already handled.
  • Events can arrive out of order. Use timestamp, or the revision in call events, to keep the newest state.

Retries

A failed delivery is retried on this schedule, about 27 hours in all:
  • If you answer 429 or 503 with a Retry-After header, the next attempt waits that long instead (up to an hour).
  • Answering 410 Gone switches the endpoint off straight away. Use it when an endpoint is retired for good.
  • An endpoint that has failed continuously for five days is switched off (status: auto_disabled), and the workspace owners get an email.
  • After the last attempt, the delivery is marked dead. Nothing is lost: events are kept for 30 days.

Replay and recover

Every delivery and every attempt (status code, timing, the first 2 KB of your response) is kept and readable: After an outage: fix the endpoint, call enable, then recover from when it started failing.

Test an endpoint

POST /v1/webhooks/{endpoint_id}/test sends one signed event now and returns the delivery with its attempt, so you can see exactly what your server answered. Pass {"event_type": "call.ended"} to get that event’s sample payload; leave it out for a plain webhook.test. Test deliveries have "test": true and are never retried.

Rotate the secret

POST /v1/webhooks/{endpoint_id}/rotate-secret returns a new secret. For grace_hours (default 24, up to 72) both secrets sign every delivery, so the webhook-signature header has two entries. Deploy the new secret within that window and nothing breaks. Send {"grace_hours": 0} to drop the old secret at once if it leaked.
Endpoints created before Standard Webhooks show secret_format: "legacy". Rotate their secret once so the official libraries can load it.

Content and privacy

By default, webhook payloads carry ids, statuses and masked numbers, and no conversation content. Each event lists its content fields in the catalogue, such as the message text, a call summary, or from_number and to_number. They’re only sent to endpoints with include_content: true. Turn content on only for endpoints you control, over a connection you trust. Changes to include_content are recorded in the workspace’s audit log.

Manage endpoints

Reading needs webhook:read; every change needs webhook:write.