Reactions
React to any WhatsApp message with a single emoji — or receive reactions from your contacts as inbound webhook events. Full parity with WhatsApp Web’s reaction UI.
Concepts
A reaction is a single emoji tied to a parent message (a message that already exists in the WhatsApp conversation and has a waMessageId). Meta enforces:
- One reaction per person per message. Reacting again with a different emoji replaces the previous one. Reacting with an empty string
""removes the current reaction. - Same 24-hour window as messages (aka the CSW). A reaction sent more than 24h after the last inbound from the contact will be rejected with error
131047— same behavior as free-form text outside the window. Reactions on messages inside the window work regardless of how old the parent is. - Reactions do not open a new conversation. They don’t consume a billable conversation from Meta.
Sending a reaction
{id} is the internal GoSendAPI message ID (from the id field of a previous POST /v1/messages response, or from a messages webhook). NOT the waMessageId.
curl https://cloud.gosendapi.com/v1/messages/{id}/reactions \
-X POST \
-H "X-API-Key: gsk_live_..." \
-H "Content-Type: application/json" \
-d '{ "emoji": "❤️" }'Response:
{ "ok": true }Removing a reaction
Send an empty string:
curl https://cloud.gosendapi.com/v1/messages/{id}/reactions \
-X POST \
-H "X-API-Key: gsk_live_..." \
-H "Content-Type: application/json" \
-d '{ "emoji": "" }'Response:
{ "ok": true, "deleted": true }Idempotency
Reacting twice with the same emoji is a no-op. Changing the emoji replaces the previous reaction (no duplicate row). You don’t need an Idempotency-Key header for reactions — the underlying store is upsert-by-(message, sender).
Errors
| Code | Meaning | What to do |
|---|---|---|
131047 | Reaction outside 24h window | Send a template first to reopen the CSW, then react. |
100 | Invalid parent message | The parent has no waMessageId yet (still sending) or was deleted from Meta. Wait or refetch. |
400 emoji required | Body missing emoji field | Send { "emoji": "..." }. Empty string = remove. |
404 Message not found | The {id} doesn’t belong to your project | Check the ID from your DB / previous response. |
Meta’s own error codes are documented in the WhatsApp Cloud API error reference.
Receiving reactions
Reactions from your contacts arrive as regular messages webhook events with type: "reaction":
{
"messaging_product": "whatsapp",
"entry": [{
"changes": [{
"field": "messages",
"value": {
"messages": [{
"id": "wamid.ABC...",
"from": "5491122334455",
"timestamp": "1732300000",
"type": "reaction",
"reaction": {
"message_id": "wamid.PARENT...",
"emoji": "👍"
}
}]
}
}]
}]
}Notes:
message_idis thewaMessageIdof the parent (the message they reacted to). To find your internal message, look it up bywaMessageId.- An empty
emojimeans the contact removed their reaction. - Reactions are also persisted internally — the
GET /v1/messageslist endpoints expose them under each parent message’sreactionsfield.
Coexistence
If your customer is on WhatsApp Business coexistence mode (also using the WhatsApp Business app on their phone), reactions sent from the phone arrive to you as smb_message_echoes webhook events with the same type: "reaction" shape. They’re persisted alongside API-sent reactions — the portal UI distinguishes them (mine=true when the reaction came from the business’s own WhatsApp number).
In the portal & embed
Both the main portal inbox (/app/inbox) and the embed inbox render reactions as chips under the bubble. Users can pick from a set of quick emojis or your own reaction (green chip) to remove it. Errors show an inline banner instead of a crude alert — the CSW rejection specifically offers “Send template” to reopen the window.