Webhooks let you receive real‑time notifications about events happening in Wazzup — for example, when a message status changes to "Delivered," or when a channel becomes "Unauthorized" and needs to be reconnected.
Wazzup sends webhooks to your HTTP endpoint. You need to subscribe to webhooks for a specific end‑customer account using the client_access_token in the header: Authorization: Bearer <client_access_token>
Minimum requirements for receiving webhooks: Respond with HTTP 200 as quickly as possible. Logging and business logic can be handled asynchronously.
message.add — an incoming message from a customer has been received;message.status_update — the status of an outgoing message has changed (e.g., from "Delivered" to "Read");message.delete — a message has been deleted;message.edit — a message has been edited. This event is only sent for messages on channels that support editing;waba_template.status_update — the moderation status of a WABA template has changed, indicating whether the template is ready to use;channel.status_update — the status of a channel has changed;channel.create — a channel has been created;channel.delete — a channel has been deleted;channel.qr_update — the QR code or connection code has been updated — the new code must be displayed to the user. Sent for WhatsApp, Telegram Personal, and Viber;channel.waba_tier_update — the WABA tier has changed. The tier determines how many conversations can be initiated within a 24‑hour period;group_chat.memberships_update — the membership of a WhatsApp group chat has changed, or a participant has been renamed;group_chat.update — group chat information has been updated;crm_entities.contact_add — a new contact needs to be created;crm_entities.deal_add — a new deal needs to be created.Subscribe only to the events that your system actually processes.
You can subscribe to multiple events in a single request.
POST /v2/webhooks| Body parameter. Required are marked with * | Parameter type | Parameter description |
data* |
object |
List of webhooks you are subscribing to |
data.url* |
string |
The URL where you want to receive webhooks |
data.event* |
string |
The webhook event |
Webhooks for creating a contact or a deal have specific characteristics:
You can subscribe to both the crm_entities.contact_add and crm_entities.deal_add webhooks, or only to crm_entities.contact_add. The webhook for creating a deal will not work without subscribing to the webhook for creating a new contact.
Request example:
curl -L 'https://tech.wazzup24.com/v2/webhooks' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <client_access_token>' \
-d '{
"data": [
{
"url": "https://webhook.site/73796fab-2e6d-492a-b68e-061d825b7db5",
"event": "message.add"
},
{
"url": "https://webhook.site/73796fab-2e6d-492a-b68e-061d825b7db5",
"event": "message.status_update"
}
]
}'
Response example:
{
"data": [
{
"id": "d6c04-7623-43ae-a024-7b36c4004c13",
"url": "https://webhook.site/73796fab-2e6d-492a-b68e-061d825b7db5",
"event": "message.add"
},
{
"id": "b0a26-10d9-4d47-8cda-892c9b471a05",
"url": "https://webhook.site/73796fab-2e6d-492a-b68e-061d825b7db5",
"event": "message.status_update"
}
],
"meta": {
"timestamp": 1759494767
}
}
Result: A subscription has been created for the message.add and message.status_update events. Webhooks will be sent to https://webhook.site/73796fab-2e6d-492a-b68e-061d825b7db5.
The response includes a subscription id, which is required to manage webhooks using other methods.
This method allows you to subscribe to additional webhooks, cancel an existing subscription, or change the URL where events are received.
PATCH /v2/webhooks| Body parameter. Required are marked with * | Parameter type | Parameter description |
data* |
object |
List of webhooks you are subscribing to |
data.id* |
string |
Subscription ID |
data.url* |
string |
The URL where you want to receive webhooks |
data.event* |
string |
The webhook event |
Request Example:
curl -L -X PATCH 'https://tech.wazzup24.com/v2/webhooks' \
-H 'Authorization: Bearer <client_access_token>' \
-H 'Content-Type: application/json' -d '{
"data": [
{
"id": "42cdd-a0a6-40fd-b55b-040e7c605d0a",
"url": "https://webhook.site/1d2c6a79-d709-4d00-ad24-856e3d8edfd5",
"event": "message.delete"
}
]
}'
Response example:
{
"data": [
{
"id": "d6c04-7623-43ae-a024-7b36c4004c13",
"url": "https://webhook.site/new-webhook-url",
"event": "message.delete"
}
],
"meta": {
"timestamp": 1759483585
}
}
Result: The webhook URL has been updated for subscription id: 411d6c04-7623-43ae-a024-7b36c4004c13.
GET /v2/webhooksRequest Example:
curl -L 'https://tech.wazzup24.com/v2/webhooks' -H 'Authorization: Bearer <client_access_token>'
Response example:
{
"data": [
{
"id": "891cdbf4-07bd-4c24-942b-27d5c820c879",
"url": "https://webhook.site/3d76c4a6-f1ab-4090-a766-3f9a07bca714",
"event": "channel.status_update"
},
{
"id": "1e35de57-ca04-45ba-a345-67f0d8b11138",
"url": "https://webhook.site/3d76c4a6-f1ab-4090-a766-3f9a07bca714",
"event": "channel.create"
},
{
"id": "ccbe0af3-2f12-4e6e-8c35-78fe3c9d3714",
"url": "https://webhook.site/3d76c4a6-f1ab-4090-a766-3f9a07bca714",
"event": "channel.update"
}
],
"meta": {
"timestamp": 1759483435
}
}
Result: A list of all webhook subscriptions for the end‑customer account.
DELETE /v2/webhooks| Body parameter | Parameter type | Parameter description |
data* |
object |
List of webhooks you are subscribing to |
data.id* |
string |
Subscription ID |
Request Example:
curl -L -X DELETE 'https://tech.wazzup24.com/v2/webhooks' \
-H 'Authorization: Bearer <client_access_token>' \
-H 'Content-Type: application/json' \
-d '{
"data": [
{
"id": "dbf4-07bd-4c24-942b-27d5c820c879"
}
]
}'
Response example:
{
"data": null,
"meta": {
"timestamp": 1759483702
}
}
Result: Subscription id: dbf4-07bd-4c24-942b-27d5c820c879 has been deleted. You will no longer receive webhooks for this event.
{
"event": "message.add" | "message.status_update" | "message.delete" | "message.edit" | "channel.status_update" | "channel.delete" | "channel.create" | "channel.qr_update" | "channel.waba_tier_update" | "waba_template.status_update" | "group_chat.memberships_update" | "group_chat.update",
"data": [],
"meta": {
"idempotency_key": UUIDv4,
"timestamp": Unix timestamp in seconds
}
}
The data field contains the event itself. Event structures:
{
"message_id": "a14325c0-97c0-43dd-917e-f0ad7460b6a9",
"channel_id": "a14325c0-97c0-43dd-917e-f0ad7460b6a9",
"direction": "inbound",
"quoted_message_id": "90126ace-fc10-44ed-90de-c30c3802fcf5" | null,
"timestamp": 1762340622177,
"crm_user_id": "123" | null,
"status": "sent",
"recipient": {
"chat_id": "3719999999",
"username": "my_tg_user",
"phone": "37198511122",
"chat_type": "telegram",
"name": "Tg User"
},
"text": "Hello!",
"attachment": {
"url": "https://some.url/photo.jpg",
"name": "photo.jpg",
"mimetype": "image/jpeg",
"size": 14832,
"sha1": "123456abcdf"
},
"template": {
"id": "2b1c3d4e-5f67-890a-bcde-f123456789ab",
"values": [ "Hello" ],
"buttons": [
{ "text": "Yes", "payload": "yes" },
{ "text": "No", "payload": "no" }
]
}
}
{
"event": "message.add",
"data": [
{
"message_id": "a5e8ba61-bc6c-41fe-9598-db7a9cbfbcbd",
"chat_id": "221601332",
"channel_id": "5f3f029a-8e76-4203-9434-fd490f8db848",
"direction": "inbound",
"quoted_message_id": null,
"timestamp": 1776953557938,
"crm_user_id": null,
"text": "Hello",
"status": "accepted",
"sender": {
"chat_type": "telegram",
"chat_id": "221601332",
"name": "Test Testovich",
"username": "testaccount",
"phone": 79111234567
},
"recipient": {
"chat_id": "221601332",
"chat_type": "telegroup",
"avatar": null,
"username": null,
"phone": null,
"name": "Group chat",
"profile_id": null,
"advert": null
}
}
],
"meta": {
"idempotency_key": "9ef07b18-e95f-4ba1-9981-63d95d8ed468",
"timestamp": 1776953558
}
}
message.add │ ├── message_id * ├── channel_id * ├── direction * ├── quoted_message_id ├── timestamp * ├── status * ├── crm_user_id ├── sender │ ├── chat_type * │ ├── chat_id * │ ├── name │ ├── username │ └── phone ├── recipient * │ ├── chat_type * │ ├── chat_id │ ├── username │ ├── phone │ ├── profile_id * │ └── advert * ├── text ├── attachment │ ├── url * │ ├── name │ ├── mimetype │ ├── size │ └── sha1 ├── template │ ├── id * │ ├── values[] │ └── buttons[] │ ├── text * │ └── payload * └── referral ├── source_url ├── source_type ├── source_id ├── headline ├── body ├── media_type ├── image_url ├── video_url ├── thumbnail_url └── ctwa_clid
| Parameter. Required are marked with * | Type | Description |
message_id* |
string |
Message ID |
channel_id* |
string |
Wazzup channel ID |
direction* |
string |
Message direction: inbound, outbound |
quoted_message_id |
string |
ID of the quoted message |
timestamp* |
number |
Unix timestamp |
status* |
string |
Message status (accepted) |
crm_user_id |
string |
ID of the CRM user or "null" |
sender |
object sender |
Message sender in a WhatsApp, Telegram, or MAX group chat |
recipient* |
object recipient |
The chat where a new outgoing or incoming message has appeared. If the webhook is about a new message in a dialogue, this object contains information about the contact the user is communicating with. If the webhook is about a new message in a group chat, this object contains general information about the group without specifying the participants. |
text |
string |
Message text. One of text, attachment, or template must be present |
attachment |
object attachment |
Attachment object |
template |
object template |
WABA template object |
referral |
object referral |
Only for WABA. Marketing data from ads. This data is passed when a customer clicks a button in an ad and opens WhatsApp. It helps you understand where the customer learned about you |
| Parameter. Required are marked with * | Type | Description |
chat_type* |
string |
Chat type. Available values:
|
chat_id* |
string |
Message sender ID — the contact's messenger account ID |
name |
string |
Sender's name |
username |
string |
Telegram only. Telegram username, without the @ symbol at the beginning |
phone |
string |
Sender's phone number in international format, if known. Without + or any other characters |
| Parameter. Required are marked with * | Type | Description |
chat_type* |
string |
Chat type. Supported values:
|
chat_id |
string |
The ID of the chat where a new outgoing or incoming message has appeared. If the message appeared in a dialogue with a contact, this is essentially the messenger account ID of the person the user is communicating with:
|
username |
string |
Telegram only. Telegram username without the @ symbol. Can be used when sending messages if the chat_id is unknown |
phone |
string |
The contact's phone number in international format, if known. Without + or any other characters |
profile_id* |
string |
Cian only. Profile identifier. For other chat types, this parameter will be null. |
advert* |
object |
The Cian ad that the customer messaged about. For other chat types, this object will be null. |
| Parameter. Required are marked with * | Type | Description |
url* |
string |
File URL |
name |
string |
File name |
mimetype |
string |
MIME type of the file |
size |
number |
File size in bytes |
sha1 |
string |
SHA-1 hash of the file |
| Parameter. Required are marked with * | Type | Description |
id* |
string |
Template ID |
values |
array[string] |
Values for template variables |
buttons |
array[object] |
Template buttons |
buttons[].text* |
string |
Button label |
buttons[].payload* |
string |
Button payload |
| Parameter. Required are marked with * | Type | Description |
source_url |
string |
URL to the ad or post that the customer clicked on |
source_type |
string |
Specifies the type of source for the ad. Possible values: ad, post |
source_id |
string |
The Meta ID for the ad or post |
headline |
string |
The headline used in the ad or post |
body |
string |
The body text for the ad or post |
media_type |
string |
Media type in the ad or post. Possible values: image, video |
image_url |
string |
The URL of the image used in the ad, applicable when media_type is image |
video_url |
string |
The URL of the video used in the ad, applicable when media_type is video |
thumbnail_url |
string |
The URL of the thumbnail for the video, applicable when media_type is video |
ctwa_clid |
string |
The Click ID generated by Meta for ads that redirect to WhatsApp |
{
"message_id": UUIDv4 | null,
"request_id": UUIDv4 | null,
"status": "accepted" | "sent" | "delivered" | "read" | "failed",
"reason": string | null
}
Possible reason values depending on status.
When status: "accepted" | "sent" | "delivered" | "read" — reason is always null
When status: "failed" — reason indicates the cause of the error.
| Reason value | Description |
network_error |
Network error |
bad_contact |
Contact does not exist (For WhatsApp — phone number not registered) |
text_length_is_too_much |
Message exceeds character limit: 4096 for WhatsApp, Telegram, and MAX; 1000 for Instagram |
can_not_get_content |
|
is_spam |
Messenger has blocked the message as suspected spam. If using Instagram or WhatsApp, try rephrasing and sending later. For Telegram, contact @SpamBot |
to_many_requests |
Too many requests |
bad_content |
The file is too large or its format is not supported by the messenger |
canceled |
Sending was canceled |
over_24_hour_limit |
For WABA. Daily Meta dialog session limit has been exceeded. You cannot initiate new conversations. Wait for one of the active sessions to expire, then resend |
wapi_not_enough_money |
For WABA. Top up your WABA subscription balance to send first messages and WABA templates |
target_user_is_blocked |
|
no_user_permissions |
|
waba_business_account_locked |
Message not sent: your WhatsApp account has been blocked by Meta. See the guide for details |
message_limit_exceeded |
Message not sent: Meta has restricted the number of messages that can be sent from this WABA number |
bad_required_parameter |
The request contains one or more unsupported or malformed parameters |
stop_receiving_marketing_messages |
For WABA. The contact has opted out of receiving marketing messages. Send a template from another category |
voice_messages_forbidden |
For Telegram. This user has disabled receiving voice messages |
input_user_deactivated |
For Telegram. The contact has deleted their account or blocked you |
privacy_premium_required |
For Telegram. This contact only accepts messages from accounts with Telegram Premium |
allow_payment_required |
For Telegram. This contact only accepts messages in exchange for paid Telegram Stars |
message_empty |
For Telegram. Add text or an attachment — Telegram does not allow empty messages |
session_revoked |
For Telegram. Message not sent: Telegram has terminated the active Wazzup session |
file_part_missing |
For Telegram. Failed to upload the file. Please try again |
channel_private |
For Telegram. You are not a member of this group, or the group has been deleted |
unknown_error |
Unknown error occurred |
{
"message_id": UUIDv4,
"crm_user_id": string | null,
"timestamp": Unix timestamp in milliseconds
}
{
"message_id": UUIDv4,
"crm_user_id": string | null,
"timestamp": Unix timestamp in milliseconds,
"text": string,
"old_text": string,
"attachment": {},
"old_attachment": {}
}
{
"template_id": UUIDv4,
"status": "APPROVED" | "PENDING" | "REJECTED" | "PAUSED" | "DISABLED",
"timestamp": unix epoch
}
| Parameter | Type | Description |
template_id |
string |
Template GUID |
status |
string |
Template moderation status |
| Status value | Description |
APPROVED |
Corresponds to "Active" in the Wazzup UI. The template has been approved by Meta and is ready to use |
PENDING |
Corresponds to "Under Moderation" in the Wazzup UI. Meta is still reviewing the template |
REJECTED |
Corresponds to "Rejected" in the Wazzup UI. The template did not pass Meta's moderation |
PAUSED |
Corresponds to "Rejected" in the Wazzup UI. The template received recipient complaints, Meta is re-reviewing it |
DISABLED |
Corresponds to "Rejected" in the Wazzup UI. The template was disabled following complaints |
{
"channel_id": UUIDv4,
"status": "active" | "disabled" | "init",
"reason": string | null
}
Possible reason values depending on status:
status: "active" — reason is always nullstatus: "init" — reason: wait_for_password, wait_for_code, qr, sync, or nullstatus: "disabled" — reason: blocked, not_enough_money, rejected, unauthorized, foreignphone, qridle, openelsewhere, or null| Channel status | Description |
active |
Channel is active |
init |
Channel is starting up |
disabled |
Channel is disabled: removed from subscription or deleted while preserving messages |
| reason value | Description |
qridle, qr |
QR code needs to be scanned |
openelsewhere |
Channel is authorized in another Wazzup account |
not_enough_money |
Channel is unpaid |
foreignphone |
QR scanned by a different account in the messenger (different phone number) |
unauthorized |
Unauthorized |
wait_for_password |
Two-factor authentication password required |
blocked |
Meta blocked the WABA channel |
rejected |
WABA channel rejected |
{
"channel_id": UUIDv4,
"timestamp": Unix timestamp in milliseconds
}
{
"channel_id": UUIDv4,
"timestamp": Unix timestamp in milliseconds
}
{
"channel_id": UUIDv4,
"qr_code": string,
"platform": 'whatsapp' | 'telegram_api' | 'viber'
}
Meta assigns WhatsApp Business accounts a tier — this determines how many 24‑hour conversations can be initiated per day.
{
"channel_id": UUIDv4,
"tier": "TIER_0" | "TIER_1K" | "TIER_10K" | "TIER_100K" | "TIER_UNLIMITED"
}
Possible values:
{
"meta": {
"idempotency_key": "945ff8a4-bb3c-45f7-8d1a-b40f7ce2fb",
"timestamp": 1760690824
},
"data": [
{
"group_id": "3c67afca-6cbf-4517-b120-c4a83dbd41",
"members": [
{
"group_member_id": "c705786d-bba5-43f9-9b-5f6f5d4ba623",
"name": "Mary",
"avatar_url": null,
"status": "in_group" | "invited" | "unknown" | "deleted" | "not_exists"
}
]
}
],
"event": "group_chat.memberships_update"
}
We send these when a contact or a deal needs to be created in the CRM. This happens in 3 cases:
Case 1: In integration settings, item 3 is set to "Every new client is assigned to the first respondent".
A new client writes in. An employee responds. Wazzup sends a webhook to create a new contact and deal on the first outgoing message, if pipelines with stages have been loaded from the CRM.
We only send the webhook if we have received the ID of the employee who responded to the new client's message.
Case 2: In integration settings, item 3 is set to "Sales reps are assigned new clients in turn".
A new client writes in. Wazzup sends a webhook to create a new contact and deal on the first incoming message, if pipelines with stages have been loaded from the CRM.
For webhooks to be sent in cases 1 and 2, you need to add employees in the personal account and enable the "Receives new clients" toggle for at least one of them in the integration settings.
Case 3: When the "+" button is clicked in the "Deals" list to create a deal:
We check whether the contact exists in our database.
If the contact does not exist, we send a webhook to create a contact:
{
"event": "crm_entities.contact_add",
"data": [
{
"responsible_user_id": string,
"name": string,
"recipient": [
{
"chat_type": string,
"chat_id": string,
"username": "string",
"phone": "string"
}
],
"source": "auto" | "by_user"
// auto — on incoming or outgoing message, by_user — by button click
}
],
"meta": {
"idempotency_key": string,
"timestamp": number
}
}
The CRM must then create the contact and return a JSON object with the contact's data. Example:
{
"id": "string",
// contact ID in the CRM, required parameter
"responsible_user_id": "string",
"name": "string",
// contact name, required parameter
"recipient": [
{
"chat_type": "string",
"chat_id": "string",
"username": "string",
"phone": "string"
}
],
"uri": "string"
// uri is optional. Link to the contact in the CRM, which the user opens from the "Deals" list in the chats iframe
}
We will then send a webhook to create a deal.
If the contact already exists, we send a webhook to create a deal:
{
"event": "crm_entities.deal_add",
"data": [
{
"responsible_user_id": string,
"pipeline_id": string,
"stage_id": string,
"contacts": string[],
"source": "auto" | "by_user"
// auto — on incoming or outgoing message, by_user — by button click
}
],
"meta": {
"idempotency_key": string,
"timestamp": number
}
}
The CRM must then create the deal and return a JSON object with the deal's data. Example:
{
"id": "deal_123",
// deal ID in the CRM, required parameter
"responsible_user_id": "user_456",
"name": "Client",
"contacts": ["contact_789", "contact_012"],
"source": "auto",
"closed": false,
"uri": "https://crm.example.com/deals/deal_123"
// uri is optional. Link to the deal in the CRM, which the user opens from the "Deals" list in the chats iframe
}
If the contact or deal has already been created, Wazzup will not resend the webhook, even if the deal is closed: "closed": true
200 OK as fast as possible; handle any additional processing asynchronously.POST endpoint (HTTPS) that accepts application/json.message.add and message.status_update events — this gives you basic visibility into whether messages are sent and delivered.