Not to be confused with the inbound webhooks Meta sends to Keebai. Those are configured by Keebai in the Meta dashboard when you connect a channel via Embedded Signup; you don’t touch them.
Use cases
Sync messages to your CRM
Receive every
whatsapp.message.received and store it in your system along with the conversation, contact, and content.Track delivery / read
Subscribe to
whatsapp.message.delivered / .read / .failed to report delivery rates in your dashboard.React to templates
Receive
whatsapp.template.status_updated when Meta approves or rejects a template, and notify your marketing team.Automated provisioning
Listen for
whatsapp.channel.connected to trigger your onboarding flow the moment a channel is ready.Mirror the CRM pipeline
Subscribe to
crm.ticket.stage_changed and crm.ticket.closed to keep an external CRM, a BI warehouse, or a Slack channel in step with the funnel.Sync the calendar
scheduling.appointment.created / .rescheduled / .cancelled carry the branch, service, professional, and customer inline — enough to update an external calendar without a follow-up call.Escalation alerts
conversation.escalated_to_human fires on the transition, once, when a ticket lands in a human-attended stage. Page whoever needs to pick it up.Scopes
Rotating a secret invalidates the old one immediately, so
webhooks:manage is the scope that can break your own receiver. A dashboard that only inspects delivery history needs webhooks:read alone.
How it works
1
Register an HTTPS URL
Via CLI (
keebai webhooks new) or via API (POST /v1/webhooks). Specify the events you care about and optionally extra headers.2
Keebai returns a secret
Once. You use it to verify that each delivery actually came from us (HMAC-SHA256 signature). It cannot be retrieved later — store it in your secret manager.
3
When an event happens, we deliver it
POST call to your URL with the standard JSON envelope and signature headers. If your endpoint responds 2xx, we mark the delivery as successful. If it responds 5xx / timeout / 408 / 429, we retry with exponential backoff (5 attempts, up to ~3h).4
After 50 consecutive failures, we auto-disable
To avoid hammering an endpoint that’s been down for a long time. You receive an email and the subscription is left with
is_active: false and disabled_reason: 'excessive_failures'. Reactivate via PATCH.Envelope
Every event shares the same outer shape. The difference is thedata field, discriminated by type.
Delivery headers
EveryPOST to your endpoint includes:
Guarantees and limitations
At-least-once delivery
If your endpoint times out or returns 5xx, we retry. Your endpoint must be idempotent: dedup by
event_id.No ordering guarantee
Events from the same channel can arrive out of chronological order (especially with retries). Use
occurred_at to sort.10s timeout
If your endpoint doesn’t respond within 10 seconds, we count a timeout and retry. Process fast and return 2xx; if you need heavy work, push it to your own queue.
HTTPS required
We don’t accept
http:// URLs. Use a valid certificate (Let’s Encrypt works).Next steps
Event catalog
Full list of
type values and the data shape for each one.Signature verification
How to validate
X-Keebai-Signature with HMAC-SHA256 in Node, Python, and PHP.Manage via CLI
Quickstart with
keebai webhooks new/list/test/rotate/delete.Manage via API
REST endpoints
/v1/webhooks to create, list, rotate, delete, and test.