Webhooks
Webhook event types
Understand the message, delivery-status, and Test Mode events your endpoint can subscribe to.
What this guide covers
- Route behavior using the event type instead of guessing from payload fields.
- Use public message and conversation IDs to correlate events with logs.
- Allow additive fields so integrations remain forward-compatible.
Normalized event envelope
Every Developer Platform event has a stable evt_ id, an exact type, an environment, an ISO 8601 creation time, and normalized data. The envelope is used directly by yanola and yanola_with_raw payload modes.
import type {
YanolaWebhookPayload,
} from "@yanola/whatsapp"
async function processEvent(event: YanolaWebhookPayload) {
switch (event.type) {
case "whatsapp.message.received":
await handleInboundMessage(event)
break
case "whatsapp.message.failed":
await handleMessageFailure(event)
break
default:
await recordObservedEvent(event)
}
}A TypeScript annotation does not validate network input. Verify the signature and perform runtime shape validation before passing the parsed body to typed application code.
Supported event types
| Event type | Meaning | Useful correlation |
|---|---|---|
yanola.webhook.test | Synthetic Test Mode endpoint verification. | event.id and delivery header IDs |
whatsapp.message.received | An inbound WhatsApp message was received. | data.message.id, data.sender.phoneNumber, conversation id |
whatsapp.message.sent | Yanola or Meta accepted an outbound message. | data.message.id |
whatsapp.conversation.started | Yanola created a new public conversation. | data.conversation.id and Sender |
whatsapp.message.delivered | Meta reported outbound delivery. | data.message.id |
whatsapp.message.read | Meta reported the outbound message as read. | data.message.id |
whatsapp.message.failed | The outbound message reached a terminal failure. | data.message.id and message.failure |
Sent is not delivered
whatsapp.message.sent means the outbound message was accepted by Yanola or Meta. It is not proof that the recipient device received or read it.
Use whatsapp.message.delivered and whatsapp.message.read for later provider confirmations. A message can instead emit whatsapp.message.failed when it reaches a terminal failure.
Event data projections
Event read endpoints and normalized webhook payloads never expose provider credentials, internal database IDs, raw-payload storage references, or raw Meta payloads.
| Projection | May contain | Do not assume |
|---|---|---|
message | Public message ID, environment, direction, type, status, from, to, content summary, timestamps, and safe failure summary. | That every non-message event has a message. |
sender | E.164 phone number, display name, status, and API eligibility. | That Sender state is permanently unchanged. |
conversation | Public conv_ ID. | That every status event starts a new conversation. |
additional fields | Compatible normalized context added by Yanola. | That unknown fields make the event invalid. |
Deduplicate and tolerate reordering
- Use the normalized event.id or yanola-event-id as the business deduplication key.
- Use yanola-delivery-id only to diagnose one automatic or replay delivery.
- Persist the event before acknowledging it.
- Make downstream side effects idempotent because automatic retries and manual replay can deliver the same event again.
- Do not require events to arrive in lifecycle order; compare message state and timestamps before applying a transition.
Inspect retained events
An API key with events:read can list and retrieve the same normalized public events for reconciliation. Reads are restricted to the key's Yanola Account, Agent Project, environment, and permitted Senders.
import { WhatsAppClient } from "@yanola/whatsapp"
const apiKey = process.env.YANOLA_API_KEY
if (!apiKey) {
throw new Error("Missing YANOLA_API_KEY")
}
const yanola = new WhatsAppClient({ apiKey })
const event = await yanola.events.retrieve("evt_...")
console.log(event.type)
console.log(event.data.message?.id)
console.log(event.data.conversation?.id)Subscription strategy
- Subscribe only to event types the endpoint actually handles.
- Use Sender filters when different applications own different numbers.
- Include yanola.webhook.test on Test Mode endpoints you want to verify from the dashboard.
- Keep a default branch that records or safely ignores newly handled cases.
- Update subscriptions before deploying logic that depends on a newly selected event type.