WABA Webhooks
Automate this endpoint with an AI agent using the 2chat-whatsapp-waba skill:
npx skills add 2ChatCo/agent-skills -s 2chat-whatsapp-waba
In here you can see what a WhatsApp Business API (WABA) webhook event has as payload.
Message Sent
Triggers when a WhatsApp message is sent from your WABA number: from the live chat, a campaign, a flow or the API. If your number also uses the WhatsApp Business app (coexistence), messages sent from the app trigger it too.
| Field | Description |
|---|---|
sent_by | api when the message was sent via the API, agent for everything else (live chat, campaigns and flows) |
to_number | The phone number of the recipient |
campaign | Only when a campaign sent the message: its uuid and name. Campaign sends and live chat replies both have sent_by: "agent", so this is how you tell them apart |
template | Only when the message is a template: its name, language and category |
campaign and template also come in the receipt events below, and in Message Failed when WhatsApp accepted the message.
{
"id": "MSG42c01a92-ace3-4de3-a5e9-2fbbf8b22d25",
"uuid": "MSG42c01a92-ace3-4de3-a5e9-2fbbf8b22d25",
"session_key": "WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"message": {
"text": "Hi Carlos, your order #1042 is on its way."
},
"created_at": "2026-02-18T18:01:35",
"remote_phone_number": "+595986541230",
"_2chat_link": "https://app.2chat.io/live-chat/STEc5ca017c-6e16-4e1a-9960-c180b1f51682/WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"channel_phone_number": "+16173518454",
"sent_by": "agent",
"campaign": {
"uuid": "CPN7d2e91b4-3c6a-4f0e-9b58-2a6f1c8e5d03",
"name": "Shipping updates"
},
"template": {
"name": "order_shipped",
"language": "en",
"category": "UTILITY"
},
"event": "whatsapp.waba.message.sent",
"channel": {
"uuid": "WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7",
"friendly_name": "2Chat Gupshup Integration",
"iso_country_code": "US",
"verified_name": "APPROVED",
"phone_number": "+16173518454",
"connection_status": "C",
"created_at": "2025-11-19 23:04:18",
"updated_at": "2026-02-02 19:41:12"
},
"to_number": "+595986541230",
"contact": {
"uuid": "CONc1f24408-ad5b-4168-89d1-3a258f784fbe",
"first_name": "Carlos",
"last_name": "Gimenez",
"name": "Carlos Gimenez",
"channel_uuid": null,
"profile_pic_url": "https://2chat-user-data.s3.amazonaws.com/ACC91be87af-5a29-4034-b599-342f2aeb5d52/pp/contacts/example.jpeg",
"last_updated": "2026-01-05T13:03:43Z"
}
}
Message Received
Triggers when a new WhatsApp message is received on your WABA number.
The sent_by field will be user because the message originates from the contact, and remote_phone_number is the phone number of the person who sent you the message.
{
"id": "MSG1e265247-8c72-5020-98ac-9bbdf562ad36",
"uuid": "MSG1e265247-8c72-5020-98ac-9bbdf562ad36",
"session_key": "WA-WAN7c43ea2d-f225-45d2-bda9-60f4746f1572-14085550176",
"message": {
"text": "Hello"
},
"created_at": "2026-07-28T19:25:23",
"remote_phone_number": "+14085550176",
"_2chat_link": "https://app.2chat.io/live-chat/STEc5ca017c-6e16-4e1a-9960-c180b1f51682/WA-WAN7c43ea2d-f225-45d2-bda9-60f4746f1572-14085550176",
"channel_phone_number": "+13024855297",
"sent_by": "user",
"contact": {
"first_name": null,
"last_name": null,
"profile_pic_url": null,
"friendly_name": "Carlos",
"device": null
}
}
Messages from a Meta ad
When the person writes by tapping a Click-to-WhatsApp ad, or the WhatsApp button of a Facebook or Instagram post, message.context carries what Meta reports about it. It comes only on the first message they send from that ad or post: save it on your side if you need it later in the conversation.
{
"id": "MSG4f0b6c1e-2a7d-5e93-b1c8-7d2e94a0f3b5",
"uuid": "MSG4f0b6c1e-2a7d-5e93-b1c8-7d2e94a0f3b5",
"session_key": "WA-WAN7c43ea2d-f225-45d2-bda9-60f4746f1572-14085550176",
"message": {
"text": "Hi, how much is the queen size?",
"context": {
"source_type": "ad",
"source_id": "120211234567890123",
"source_url": "https://fb.me/3cr4Wqqkx",
"headline": "Spring Sale",
"body": "Free shipping on all mattresses this week.",
"media_type": "image",
"image_url": "https://scontent.xx.fbcdn.net/v/example.jpg",
"ctwa_clid": "ARAkLkA8rmlFeiCktEJQ-QTwRiyYHAFDLMNDBH0CD3qpjd0HR4irJ6LEkR7JwFF4XvnO2E4Nx0-eM-GABDLOPaOdRMv-_zfUQ2a",
"welcome_message": {
"text": "Hi! How can we help you?"
}
}
},
"created_at": "2026-10-28T17:29:39",
"remote_phone_number": "+14085550176",
"_2chat_link": "https://app.2chat.io/live-chat/STEc5ca017c-6e16-4e1a-9960-c180b1f51682/WA-WAN7c43ea2d-f225-45d2-bda9-60f4746f1572-14085550176",
"channel_phone_number": "+13024855297",
"sent_by": "user",
"contact": {
"first_name": null,
"last_name": null,
"profile_pic_url": null,
"friendly_name": "Carlos",
"device": null
}
}
| Field | Description |
|---|---|
message.context.source_type | ad for a Click-to-WhatsApp ad, post for a Facebook or Instagram post |
message.context.source_id | The ID of the ad (or post) in Meta |
message.context.source_url | Link to the ad or post |
message.context.headline / body | Title and text of the ad, when Meta sends them |
message.context.media_type | image or video, with image_url or video_url (and sometimes thumbnail_url) |
message.context.ctwa_clid | Click ID of the ad. It's what Meta's Conversions API asks for to attribute a sale to the ad |
message.context.welcome_message.text | The greeting set on the ad, when it has one |
Meta decides which of these fields to send, so treat all of them as optional. For a per-ad count of the conversations they started, use the Ads Report.
Order Received
Triggers when a contact places an order from your catalog on your WABA number, by checking out the cart in the WhatsApp product catalog.
This event replaces whatsapp.waba.message.received for that message: an order fires whatsapp.waba.message.order.received only, so you never receive both for the same order.
The order itself travels inside message.order, and message.text carries the note the contact typed at checkout (often an empty string). The sent_by field is user because the order originates from the contact.
{
"id": "MSG0d47c1b8-3f92-4a51-b6c7-8e2d5a91f043",
"uuid": "MSG0d47c1b8-3f92-4a51-b6c7-8e2d5a91f043",
"session_key": "WA-WAN8f21cc03-5d7a-4e19-bb62-1a3f9e0d7c48-14085550176",
"message": {
"text": "Please deliver after 6pm",
"order": {
"catalog_id": "1284930175620394",
"text": "Please deliver after 6pm",
"currency": "USD",
"total": 511.0,
"products": [
{
"product_retailer_id": "SKU-BAG-001",
"name": "ADIDAS | CLASSIC BACKPACK | LEGEND INK MULTICOLOUR",
"price": 150.5,
"quantity": 2,
"currency": "USD",
"thumbnail_url": "https://2chat-user-data.s3.amazonaws.com/order/product/SKU-BAG-001.jpeg"
},
{
"product_retailer_id": "SKU-CAP-014",
"name": "SKU-CAP-014",
"price": 210.0,
"quantity": 1,
"currency": "USD"
}
]
}
},
"created_at": "2026-07-28T19:25:23",
"remote_phone_number": "+14085550176",
"_2chat_link": "https://app.2chat.io/live-chat/STE3a9f1c47-8b2e-4d61-9f03-6c5a4e21d8b7/WA-WAN8f21cc03-5d7a-4e19-bb62-1a3f9e0d7c48-14085550176",
"channel_phone_number": "+16195550143",
"sent_by": "user",
"contact": {
"first_name": null,
"last_name": null,
"profile_pic_url": null,
"friendly_name": "Carlos",
"device": null
},
"event": "whatsapp.waba.message.order.received",
"channel_uuid": "WAN8f21cc03-5d7a-4e19-bb62-1a3f9e0d7c48",
"message_uuid": "MSG0d47c1b8-3f92-4a51-b6c7-8e2d5a91f043"
}
The message.order object
| Field | Description |
|---|---|
catalog_id | The identifier of the catalog the contact ordered from |
text | The note the contact typed at checkout. Usually an empty string |
currency | The currency of the order, taken from the first product that reports one. null when no product carries a currency |
total | The sum of price × quantity across every product, rounded to 2 decimals |
products | The list of ordered products. See the table below |
Each entry of products has these fields:
| Field | Description |
|---|---|
product_retailer_id | The SKU (retailer ID) of the product as it exists in your catalog |
name | The product name. See the note below |
price | The unit price of the product |
quantity | How many units of this product the contact ordered |
currency | The currency of the unit price |
thumbnail_url | URL of the product image. Optional — see the note below |
WhatsApp only reports the retailer ID, unit price, and quantity of each item. 2Chat resolves the rest against your Meta catalog to fill in name and thumbnail_url.
When that lookup cannot run — a coexistence number, whose catalog lives in the WhatsApp Business App, or a channel without a Meta access token — name falls back to the product_retailer_id and thumbnail_url is omitted, as shown for SKU-CAP-014 in the example above. Always treat thumbnail_url as optional.
Quick Reply
Triggers when a contact responds by tapping a quick reply button.
The message.quick_reply field is true to indicate the incoming message came from a quick reply button rather than free-form text, and message.text holds the label of the button the contact selected. The sent_by field is user because the message originates from the contact.
How to tell which button was tapped depends on the message the contact replied to:
- Interactive messages and list replies:
message.quick_reply_idis the button'sid. - Templates:
message.quick_reply_indexis the position of the tapped button in the template, starting at1for the first button. It doesn't change when you edit the button's label or send the template in another language, so route on it. For a template,message.quick_reply_idrepeats the button's label.
Avoid routing on message.text: it is the label the contact sees, so it changes with the
template's language.
{
"id": "MSG7b3e9a41-2c8d-4f6a-b1e0-9d4c5a2f83b1",
"uuid": "MSG7b3e9a41-2c8d-4f6a-b1e0-9d4c5a2f83b1",
"session_key": "WA-WAN8f21cc03-5d7a-4e19-bb62-1a3f9e0d7c48-14085550176",
"message": {
"text": "I want to learn more",
"quick_reply": true,
"quick_reply_id": "I want to learn more",
"quick_reply_index": 2
},
"created_at": "2026-07-02T13:22:03",
"remote_phone_number": "+14085550176",
"_2chat_link": "https://app.2chat.io/live-chat/STE3a9f1c47-8b2e-4d61-9f03-6c5a4e21d8b7/WA-WAN8f21cc03-5d7a-4e19-bb62-1a3f9e0d7c48-14085550176",
"channel_phone_number": "+16195550143",
"sent_by": "user",
"contact": {
"first_name": null,
"last_name": null,
"profile_pic_url": null,
"friendly_name": "Carlos",
"device": null
}
}
Message Receipt Sent
Triggers when a message you sent has been transmitted to the WhatsApp network and is on its way to the recipient.
When a campaign sent the message, or the message is a template, it also carries campaign and template, as in Message Sent.
{
"id": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb",
"uuid": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb",
"session_key": "WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"message": {
"text": "Hi Juan. We are writing you to ask you if you received our package with track-id 1. Please confirm."
},
"created_at": "2026-02-18T17:34:17",
"remote_phone_number": "+595986541230",
"_2chat_link": "https://app.2chat.io/live-chat/STEc5ca017c-6e16-4e1a-9960-c180b1f51682/WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"channel_phone_number": "+16173518454",
"sent_by": "agent",
"sent": true,
"received": false,
"read": false,
"event": "whatsapp.waba.message.receipt.sent",
"channel_uuid": "WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7",
"message_uuid": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb"
}
Message Receipt Received
Triggers when a message you sent is received on the app of its intended receiver.
{
"id": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb",
"uuid": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb",
"session_key": "WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"message": {
"text": "Hi Juan. We are writing you to ask you if you received our package with track-id 1. Please confirm."
},
"created_at": "2026-02-18T17:34:17",
"remote_phone_number": "+595986541230",
"_2chat_link": "https://app.2chat.io/live-chat/STEc5ca017c-6e16-4e1a-9960-c180b1f51682/WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"channel_phone_number": "+16173518454",
"sent_by": "agent",
"sent": true,
"received": true,
"read": false,
"event": "whatsapp.waba.message.receipt.received",
"channel_uuid": "WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7",
"message_uuid": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb"
}
Message Receipt Read
Triggers when the receiver reads a message you sent.
This one is not tied to the delivery receipt: it fires whenever the recipient actually opens the chat, which may be minutes or hours after whatsapp.waba.message.receipt.received. It only arrives if the recipient has read receipts enabled on their device.
{
"id": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb",
"uuid": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb",
"session_key": "WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"message": {
"text": "Hi Juan. We are writing you to ask you if you received our package with track-id 1. Please confirm."
},
"created_at": "2026-02-18T17:34:17",
"remote_phone_number": "+595986541230",
"_2chat_link": "https://app.2chat.io/live-chat/STEc5ca017c-6e16-4e1a-9960-c180b1f51682/WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"channel_phone_number": "+16173518454",
"sent_by": "agent",
"sent": true,
"received": true,
"read": true,
"event": "whatsapp.waba.message.receipt.read",
"channel_uuid": "WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7",
"message_uuid": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb"
}
Message Failed
Triggers when WhatsApp could not deliver a message you sent, or rejected it when we sent it.
errors is passed through from the provider untouched, so you can act on the specific code. wa_message_id is the provider's own message id (the Meta wamid), included when we know it, so you can correlate the failure with your data in WhatsApp Manager.
When WhatsApp accepts the message and fails to deliver it later, the payload looks like this:
{
"id": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb",
"uuid": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb",
"session_key": "WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"message": {
"text": "Hi Juan. We are writing you to ask you if you received our package with track-id 1. Please confirm."
},
"created_at": "2026-02-18T17:34:17",
"remote_phone_number": "+595986541230",
"_2chat_link": "https://app.2chat.io/live-chat/STEc5ca017c-6e16-4e1a-9960-c180b1f51682/WA-WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7-595986541230",
"channel_phone_number": "+16173518454",
"sent_by": "agent",
"sent": false,
"received": false,
"read": false,
"event": "whatsapp.waba.message.failed",
"channel_uuid": "WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7",
"message_uuid": "MSG68e4fc6c-6a81-43aa-967e-4a71f11234eb",
"wa_message_id": "wamid.HBgLNTk1OTg2NTQxMjMwFQIAERgSQjNBRjczNkNBQjM0NUY5MUEyAA==",
"errors": [
{
"code": 131026,
"title": "Message undeliverable",
"message": "Message undeliverable",
"error_data": {
"details": "Receiver is incapable of receiving this message"
}
}
]
}
When WhatsApp rejects the message as soon as we send it (for example 130429, the number went over its sending rate), the message never reaches WhatsApp: Send WABA Message already answered 202, and this webhook is how you find out. The payload is shorter, without id, session_key, message or wa_message_id. Match it to your send with message_uuid, the one the 202 response returned.
{
"event": "whatsapp.waba.message.failed",
"channel_uuid": "WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7",
"message_uuid": "MSGe9301e0d-ff75-4487-8bbc-7eaf14453d5c",
"channel_phone_number": "+16173518454",
"remote_phone_number": "+595986541230",
"created_at": "2026-02-18T17:34:17.512304",
"errors": [
{
"code": 130429,
"title": "Rate limit hit",
"message": "(#130429) Rate limit hit",
"error_data": {
"details": "Rate limit hit"
}
}
]
}
Template Created
Triggers when a new message template is submitted to WhatsApp through 2Chat — via Create WABA Template or from the web app. The creator already gets the result in the HTTP response; this event is for every other subscriber.
status is the initial status: usually PENDING, though some AUTHENTICATION templates are approved on the spot.
{
"event": "whatsapp.waba.template.created",
"channel_uuid": "WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7",
"timestamp": "2026-02-18T17:31:02.114000Z",
"payload": {
"template_uuid": "TMP1b44a079-c75c-4403-bc8f-a75c4ce5cd23",
"name": "order_shipped",
"language": "en",
"category": "UTILITY",
"status": "PENDING",
"previous_status": null,
"rejection_reason": null
}
}
Template Status Updated
Triggers when WhatsApp finishes reviewing a message template, or changes its status afterwards (for example pausing a template with poor feedback). Only APPROVED templates can be sent.
Use template_uuid directly as the template_uuid of Send WABA Message.
{
"event": "whatsapp.waba.template.status.updated",
"channel_uuid": "WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7",
"timestamp": "2026-02-18T17:34:17.221000Z",
"payload": {
"template_uuid": "TMP1b44a079-c75c-4403-bc8f-a75c4ce5cd23",
"name": "order_shipped",
"language": "en",
"category": "UTILITY",
"status": "APPROVED",
"previous_status": "PENDING",
"rejection_reason": null
}
}
| Field | Description |
|---|---|
payload.template_uuid | UUID of the template whose status changed |
payload.status | New status: APPROVED, REJECTED, PAUSED, DISABLED or DELETED |
payload.previous_status | Status the template had before this change |
payload.rejection_reason | Why WhatsApp rejected the template, when status is REJECTED |
Template Deleted
Triggers when one of your message templates is deleted — through 2Chat (Delete WABA Template or the web app) or directly in WhatsApp Manager. The template can no longer be sent.
In every template event, status reflects the template's state on WhatsApp, never a 2Chat-internal state. Deleting a template is not instant on WhatsApp's side: it enters PENDING_DELETION and is retained for about 30 days before the definitive DELETED, so this event usually arrives with status: "PENDING_DELETION". On some carriers the template is removed immediately instead; in that case status comes directly as DELETED.
{
"event": "whatsapp.waba.template.deleted",
"channel_uuid": "WAN3ff9fb72-6ecd-4c2a-9055-4836d8ed33d7",
"timestamp": "2026-02-19T09:12:45.310000Z",
"payload": {
"template_uuid": "TMP1b44a079-c75c-4403-bc8f-a75c4ce5cd23",
"name": "order_shipped",
"language": "en",
"category": "UTILITY",
"status": "PENDING_DELETION",
"previous_status": "APPROVED",
"rejection_reason": null
}
}
If WhatsApp later reports a further transition (for example the final DELETED after the retention window), it arrives as a regular Template Status Updated event.