Skip to main content
Zavu sends webhook events for message lifecycle stages. There are several categories:

Event Structure

All events follow this structure:

Inbound Events

conversation.new

Triggered when a new contact sends you their first message. This is useful for tracking new leads or customers.

Data Fields

You’ll also receive a message.inbound event for the same message. Use conversation.new specifically for new lead notifications or CRM integrations.

message.inbound

Triggered when a customer sends you a message via SMS or WhatsApp. This includes text, images, videos, audio, documents, stickers, locations, and contacts.

Text Message Example

Username Contact (BSUID) Example

WhatsApp users can adopt a username and hide their phone number. Their messages arrive through the same event, but from carries a business-scoped user ID (BSUID) instead of an E.164 phone number:
Do not assume from is a phone number. Treat it as an opaque identifier: reply by passing it back as to in the send API, which accepts BSUIDs directly. See Usernames & BSUIDs for the full picture, including how to recover the contact’s phone number.

Image Message Example

For media messages (image, video, audio, document, sticker), the content.mediaId is provided initially. The media is then downloaded and stored, and subsequent reads of the message will include a content.mediaUrl with the permanent URL.

Location Message Example

When the location answers a location request you sent, the same event carries content.replyToMessageId pointing at the request. There is no separate event type — match on that field to tie the coordinates back to the order, ticket or job you were asking about.

Contact Message Example

Interactive Reply Example

When a user clicks a button or selects a list item that you sent, you’ll receive the reply with the button/item ID:
The interactiveReply.id is the ID you specified when sending the button or list message. Use this to identify which option the user selected.

Reply / Quote Context Example

When a customer replies to (quotes) an earlier message, the content object carries the reply context so you can thread the conversation. When the quoted message exists in Zavu, you get its Zavu replyToMessageId, a text snippet, and its type:
If the quoted message is not stored in Zavu (e.g. an old or unknown message), the context degrades gracefully — you still get the provider ID and sender, but replyToMessageId, replyToText, and replyToMessageType are omitted:
Use replyToMessageId to link the reply to a message in your system. When it’s absent, fall back to replyToProviderMessageId (the WhatsApp WAMID), which is always present on a reply.

Data Fields

The top-level timestamp is when Zavu dispatched the webhook, not when the contact sent the message. If a channel delays delivery, these can differ by minutes. Use data.providerTimestamp to measure the real delay and skip stale messages:

Example Handler


message.unsupported

Triggered when a customer sends a message type that cannot be fully represented on the channel. On WhatsApp Cloud API, this includes polls, deleted messages, ephemeral messages, and some third-party stickers.

Data Fields

On WhatsApp Cloud API, unsupported types typically include:
  • Polls — Cloud API does not expose poll content
  • Deleted messages — messages deleted by the sender
  • Ephemeral messages — disappearing messages that Cloud API does not expose
  • Third-party stickers — stickers not meeting WhatsApp specifications
These Cloud API limitations are from Meta, not Zavu.

Example Handler


message.reaction

Triggered when a customer reacts to a message with an emoji (WhatsApp only). This event is sent when a reaction is added or removed from a message.

Data Fields

When a user removes a reaction, action will be removed and emoji will be an empty string.

Example Handler


Outbound Events

These events help you track the delivery status of messages you send. Subscribe to these if you need delivery confirmations or failure notifications.

message.queued

Triggered when your message is accepted and queued for delivery.

Data Fields


message.sent

Triggered when your outbound message is successfully accepted by the carrier or Meta. This confirms the message has left Zavu’s systems and is being processed by the provider.

Data Fields

WhatsApp Business App Echo (Coexistence)

When using WhatsApp in coexistence mode, messages sent directly from the WhatsApp Business App also trigger message.sent events. These events include the full message content so you can sync outbound messages that were not sent through the Zavu API. You can distinguish these from regular status updates by checking the source field.

Additional Fields (Coexistence Only)

When you receive a message.sent event with source: "whatsapp_business_app", you should create a new outbound message record in your system rather than treating it as a status update. These messages were sent outside of Zavu’s API and have their own unique messageId.

message.delivered

Triggered when your message is confirmed delivered to the recipient’s device.

Data Fields

Delivery confirmation availability depends on the carrier and channel. WhatsApp provides reliable delivery receipts, while SMS delivery confirmations vary by carrier.

message.failed

Triggered when message delivery fails.

Data Fields

Common Error Codes

Example Handler


Template Events

template.status_changed

Triggered when a WhatsApp template’s approval status changes. This is useful for tracking when templates are approved, rejected, or disabled by Meta.

Data Fields

Status Values

Example Handler


Partner Invitation Events

invitation.status_changed

Triggered when a partner invitation changes status. This is useful for tracking when your clients complete the WhatsApp onboarding process.

Data Fields

Status Flow

Example Handler


Broadcast Events

broadcast.status_changed

Triggered when a broadcast changes status. This is a project-level event — configure it in your project webhook settings.

Data Fields

Status Flow

Example Handler


Best Practices

Idempotency

Webhook deliveries may be retried, so your handler should be idempotent:

Error Handling

Always wrap your handlers in try-catch to prevent unhandled exceptions:

Next Steps