Every outbound webhook event Xobito emits, with full JSON payloads.
Xobito sends outbound webhooks across these groups: contacts / statuses / sources CRUD (9 events), message delivery status (4 events: sent / delivered / read / failed), and inbound messages (message.received). CRUD events use the contact-style payload envelope. Message delivery and inbound events use a simpler payload — see below.
Live as of 2026-05-28. Fires every time Meta reports a status change for a message you sent via the Send Message endpoints.
Event
model
event
Fires when
Message sent
WhatsAppMessage
message.sent
WhatsApp accepted the message from us
Message delivered
WhatsAppMessage
message.delivered
Recipient’s device received the message
Message read
WhatsAppMessage
message.read
Recipient opened the message (only if read receipts enabled on their side)
Message failed
WhatsAppMessage
message.failed
Delivery failed — error_message populated
Mapping back to your record: the data.message_id is the exact same wamid.* returned in the data.whatsapp_response.messages[0].id field of every successful send response. Keep a (message_id → your_record_id) table and match on it.Headers for message delivery webhooks:
The first (sent) event also includes the outbound message content (text + type) when
available, so you can mirror messages sent from the dashboard — not just ones you sent via the
API. (delivered / read / failed events omit content; you already have it from sent.)
{ "event": "message.sent", "model": "WhatsAppMessage", "data": { "message_id": "wamid.HBgMOTE3OTg0OTM5ODcxFQIAERgSOTkxOTdCMjQ1N0JENjc2RjM5AA==", "status": "sent", "error_message": null, "text": "Hi Rahul, your order has shipped.", "type": "text", "tenant_id": 6 }, "timestamp": "2026-05-28T14:50:56+00:00"}
{ "event": "message.failed", "model": "WhatsAppMessage", "data": { "message_id": "wamid.HBgM...", "status": "failed", "error_message": "Recipient phone number not on WhatsApp", "tenant_id": 6 }, "timestamp": "2026-05-28T14:52:10+00:00"}
Idempotency: Meta occasionally retries status webhooks to us, which can result in duplicate POSTs to your URL. Dedupe on your end by the (message_id, status) pair — ignore the second if you’ve already processed it.
Ordering is best-effort. Network latency means delivered may occasionally arrive before sent, or read before delivered. Compare timestamps if order matters to you.
Message text, media caption, button-tap title, or reaction emoji. null for media with no caption. For location/contacts, holds a JSON string.
media
string|null
Direct, downloadable URL for media messages; null otherwise.
media_filename
string|null
Stored filename (reference).
reply_to_message_id
string|null
If the contact replied to a specific message, the wamid it replies to.
tenant_id
integer
Your workspace id.
Enable inbound + delivery webhooks the same way (see Webhooks Overview) — set Webhook URL and turn webhook access on. Inbound events fire automatically; no per-event toggle.
The following events still do not fire outbound webhooks:
Campaigns — campaign.started, campaign.completed, etc.
Templates — template.approved, template.rejected, etc.
Tickets and conversations — no outbound webhooks.
If you need any of these, poll the relevant API endpoint on an interval you control.