Webhooks
Event types
Subscribe to the events you need. Each one carries what a workflow needs, without a second call.
All events
Messages
message.received- A customer sent a message
message.sent- Meta accepted an outbound message, from the inbox or the API
message.status_updated- An outbound message moved to sent, delivered, read, failed or rejected
Conversations
conversation.created- A customer's first message opened a conversation
conversation.assigned- The assigned member or team changed
conversation.status_changed- The status or snooze changed
note.created- Someone added an internal note
Contacts
contact.created- A contact was created
contact.updated- Fields changed, listed in changed
contact.deleted- A contact was deleted
contact.restored- A deleted contact came back
contact.blocked- A contact was blocked
contact.unblocked- A contact was unblocked
contact.lifecycle_changed- A contact moved to another stage
contact.tag_added- A tag was put on a contact
contact.tag_removed- A tag was taken off a contact
contact.merged- A contact was merged into another
Other
import.completed- An import finished or failed
ping- A test sent from Settings
The contact
Message, conversation, note and contact events carry the contact in data.contact, the same object Get a contact returns. Every key is present, null when empty. It is read when the event is sent, so it can be newer than the event.
{
"customer_id": "4829173650",
"first_name": "Ama",
"last_name": null,
"username": null,
"phone_e164": "+237690000001",
"email": null,
"language": "fr",
"lifecycle": { "stage_id": "new", "name": "New", "color": "#9CA3AF" },
"tags": [],
"collaborators": [],
"attributes": { "plan": "gold" },
"status": "active",
"channel_id": "0e8d3c1f-7a6b-4b52-9e34-2d1f5c8a9b70",
"created_at": "2026-10-05T14:02:11Z",
"updated_at": "2026-10-05T14:02:11Z"
}
Contact events also keep the contact fields at the top of data, as before.
Files
message.received and message.sent carry media for an image, audio, video, document or sticker, and null otherwise.
{
"id": "7d1e4a0c-3b52-4c8e-9f60-2a5b8c1d9e33",
"mime_type": "image/jpeg",
"size": 48213,
"filename": null,
"source": "omnio",
"url": "https://...",
"url_expires_at": "2026-10-05T14:17:11Z"
}
urlneeds no token and expires after 15 minutes. Download the file when the event arrives. Each retry gets a new link.- For a fresh link later, call Get a file link with the
id. - A file sent by link has
source"link", its originalurlandurl_expires_atnull. - An inbound file is copied a few seconds after it arrives and the event waits up to a minute for it. If it is not ready,
urlisnulland the link endpoint answers once it is.
Message status
A status never goes back. When a customer reads a message, each earlier unread one gets its own event with inferred set to true.
{
"message_id": "3c5e7a90-8d1b-4e26-a4f7-5b9d0c2e1a68",
"seq": 43,
"conversation_id": "b1c7e0a4-52a3-4a3c-8d0e-6c1b9e5f7a20",
"channel_id": "0e8d3c1f-7a6b-4b52-9e34-2d1f5c8a9b70",
"customer_id": "4829173650",
"message_type": "text",
"status": "read",
"previous_status": "delivered",
"inferred": false,
"read_at": "2026-10-05T14:05:39Z",
"error": null
}