WhatsApp channel message support
The WhatsApp channel of the Conversation API supports a wide variety of message types, including the the rich template, media, and location message types supported by the WhatsApp API.
Sending Messages
Prior to sending messages on the WhatsApp channel using the Conversation API generic message format, note the following:
- Sending a generic message format requires a started customer care session . Sending messages outside of a customer care session requires a template .
- All marketing, utility or authentication conversations on the WhatsApp channel should start with an “Opt-In” by the user. This can be collected through any third party channel. For example in an SMS message, a web form, email etc. Businesses must also provide a method by which customers may opt-out of receiving future messages from your organization.
-
When using the WhatsApp channel, you may receive a
RECIPIENT_NOT_REACHABLE
error code if you send a marketing template message to a recipient, and the recipient is part of the current WhatsApp marketing message experiment .
The following table details the mapping between the Conversation API generic message format and how WhatsApp renders the messages on mobile devices:
Message Type | Natively Supported? | Special Instructions |
---|---|---|
Text Message | Yes, this type of message is natively supported. You can include a maximum of 4096 characters in a single text message. For example: |
The code to send a text message for this channel doesn't differ from the generic message and can be viewed here. |
Media Message | Yes, this type of message is natively supported for the following media types (the WhatsApp channel will automatically detect what type of WhatsApp media message to use):
|
The code to send a media message for this channel doesn't differ from the generic message and can be viewed here. |
Choice Message | This type of message is natively supported (through the use of quick reply buttons) if:
If more than three choices are included, but all other conditions are met,the native interactive list message type will be used (see Choice List Message below). This type is also natively supported through the use of call to action buttons if:
If any of these conditions are not met, the message is converted into plain text. |
The code to send a choice message for this channel doesn't differ from the generic message and can be viewed here. |
Card Message | This type of message is natively supported if you only include text choices (that adhere to the Choice Message conditions detailed in the previous row) in your card message. Note that:
. If:
. |
The code to send a card message for this channel doesn't differ from the generic message and can be viewed here. |
Carousel Message | No, this type of message will be converted into plaintext. For example: |
The code to send a carousel message for this channel doesn't differ from the generic message and can be viewed here. |
Location Message | Yes, this type of message is natively supported. For example: |
The code to send a location message for this channel doesn't differ from the generic message and can be viewed here. |
Choice List Message | Yes, this type of message is natively supported. For example: The detailed view of the message is displayed below: |
The code to send a list message for this channel doesn't differ from the generic message and can be viewed here. |
Product List Message (Single Product) | Yes, this type of message is natively supported. For example: The detailed view of the message is displayed below: |
The code to send a list message for this channel doesn't differ from the generic message and can be viewed here. |
Product List Message (Multi-Product) | Yes, this type of message is natively supported. For example: The detailed view of the message is displayed below: |
The code to send a list message for this channel doesn't differ from the generic message and can be viewed here. |
Explicit Channel Messages
Conversation API provides a way to use channel specific message formats. If you know the underlying channel's API (in this case, the WhatsApp Cloud API), and you want to use a feature that's not supported by Conversation API message types, you can pass the JSON format of the WhatsApp Cloud API to Conversation API too. When you want to use a channel specific format, you need to pass this JSON as an escaped string to Conversation API.
For example, consider the Interactive List message. While we can send this message as a choice list message, it can also be sent using the WhatsApp Cloud API. This example message is sent using a Conversation API POST
to the messages:send
endpoint:
{
"message": {
"explicit_channel_message": {
"WHATSAPP": "{\"messaging_product\":\"whatsapp\",\"to\":\"{{to}}\",\"type\":\"interactive\",\"recipient_type\":\"INDIVIDUAL\",\"interactive\":{\"type\":\"list\",\"body\":{\"text\":\"What do you want to do?\"},\"action\":{\"button\":\"Menu\",\"sections\":[{\"rows\":[{\"id\":\"firstreply\",\"title\":\"First Reply\"},{\"id\":\"secondreply\",\"title\":\"Second Reply\"},{\"id\":\"thirdreply\",\"title\":\"Third Reply\"}]}]}}}"
}
}
}
The rendered message:
WhatsApp Payments: Brazil (Beta)
Note:
This WhatsApp functionality is not yet generally available to all customers. Additionally, the functionality provided by Sinch to enable this WhatsApp feature is only available to select customers for closed beta testing.
If you are a business based in Brazil, and you have access to WhatsApp's Payments API, you can use an explicit channel message to access that functionality. This functionality will allow you (the business) to send product information, respond to customer interest, facilitate payments, and provide order status updates, all within WhatsApp.
In order to gain access to WhatsApp Payments in Brazil, reach out to your account manager. They will be able to enable this feature on your account. Additionally, Sinch has created supplemental WhatsApp Payments documentation to aid customers that are included in the closed beta.
Note:
Meta's documentation for the WhatsApp Payments API in Brazil may be unavailable to you if you do not have access to the unreleased feature. Please note that the supplemental documentation that Sinch provides for this functionality is only for customers that have access to this API.
WhatsApp Location Request
WhatsApp provides a way to send a message with custom text and a "Send location" button. Clicking this button allows a user to share their location. It's possible to send a location request an explicit channel message to recreate an Interactive message. For example:
{
"message": {
"explicit_channel_message": {
"WHATSAPP": "{\"messaging_product\":\"whatsapp\",\"to\":\"{{to}}\",\"type\":\"interactive\",\"recipient_type\":\"INDIVIDUAL\",\"interactive\":{\"type\":\"location_request_message\",\"body\":{\"text\":\"Please provide your location\"},\"action\":{\"name\":\"send_location\"}}}"
}
}
}
The rendered message:
WhatsApp Flows
This functionality is WhatsApp-specific, Conversation API supports it in the form of a channel specific message. WhatsApp Flows allows you to construct well-defined business messaging interactions. With Flows, a business can create and configure customized messages with interactive features that provide customers with a structured communication path. Meta details that "you can use Flows to book appointments, browse products, collect customer feedback, get new sales leads, or anything else where structured communication is more natural or comfortable for your customers."
In order to have WhatsApp Flows provisioned, you must work with Sinch Professional Services. For any questions regarding the Sinch Professional Services team, please contact your Sinch account manager. Additionally, Sinch has created supplemental WhatsApp Flows documentation for reference.
Receiving Delivery Receipts
Messages sent on WhatsApp channel can have three statuses: DELIVERED
, READ
, or FAILED
.
If the status is FAILED
, a reason will be included that provides more information about the failure.
Note the following:
-
Not all messages that are successfully delivered have both
DELIVERED
andREAD
statuses. Only aREAD
receipt is sent if the contact's WhatsApp app and conversation are active when the message is received. -
In some cases, the recipient of your message may have their WhatsApp account associated with multiple devices. This can result in multiple delivery receipts for the same message. If those devices support different messaging features, you may receive
contradictory delivery receipts
for the same message. Also note that any
DELIVERED
messages are subject to charges at the normal rates, even if you initially received aFAILED
delivery receipt for the same message.
Below is an example of a Conversation API POST
to the MESSAGE_DELIVERY
webhook with a READ
receipt; a FAILED
or DELIVERED
receipt would have a different status
, and a FAILED
status would have a reason
.
{
"app_id": "01E8RCZPK7HFV70FFDWFFK0EXK",
"accepted_time": "2020-06-22T11:05:53.910Z",
"event_time": "2020-06-22T11:20:08.120Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"message_delivery_report": {
"message_id": "01EBDV9EFP66ZA0GQJ9MCX1V9H",
"conversation_id": "01EB199XQ2CBY50K6WZD9S1A22",
"status": "READ",
"channel_identity": {
"channel": "WHATSAPP",
"identity": "+46702471483",
"app_id": ""
},
"contact_id": "01EB197NDA4W7V15NPRCVV0S79",
"metadata": "",
"processing_mode": "CONVERSATION"
},
"message_metadata": "{\"pricing_category\":\"service\",\"whatsapp_conversation_id\":\"a49709b572981c281648d7d23e95412c\"}"
}
Receiving Pricing Model Information
The WhatsApp pricing model is conversation-based. This means that customers are charged per conversation. A conversation starts with the first delivered message and includes all messages delivered in the conversation category during a 24-hour session (excluding Free Entry Point conversations, which occur in 72-hour sessions). The price for the conversation depends on the pricing category of the conversation:
-
Marketing conversation
, which defines conversations that can cover a wide range of topics. For example, marketing conversations can include promotional content, greeting messages, general updates, and requests to participate in transactions. This is the least restricted conversation category. A
marketing template
message must be used to start this type of conversation.
Note:
When using the WhatsApp channel, you may receive a
RECIPIENT_NOT_REACHABLE
error code if you send a marketing template message to a recipient, and the recipient is part of the current WhatsApp marketing message experiment. - Utility conversation , which defines conversations that are limited to specific actions and notifications. For example, utility conversations can include messages confirming a transaction, or a message reminding the recipient that a payment is due. A utility template message must be used to start this type of conversation.
-
Authentication conversation
, which defines conversations in which a business sends users a one-time passcode. This is the most restricted conversation category. An
authentication template
message must be used to start this type of conversation.
Note:
Starting June 1, 2024, you will be billed at a different authentication-international rate if the authentication template was sent to an end-user that is in a different country than the one in which your business is registered, the end-user's country has an authentication-international rate on WhatsApp's rate cards, your business is eligible for authentication-international rates, and the conversation was opened on or after your start time for that country. See Meta's documentation on authentication-international rates for more information.
- Service conversation , which defines conversations initiated in response to a user message.
- Free Entry Point conversation , which defines conversations that do not incur a charge. These conversations are typically initiated when an end-user messages the business by clicking a call-to-action button on an ad. For example, a user clicking on a Facebook ad may trigger a referral conversion conversation.
Note
For more information regarding WhatsApp conversation pricing, see their article on Conversation-Based Pricing.
To inform the Conversation API user about the pricing of their WhatsApp conversation, delivery receipt callbacks with the DELIVERED
status will contain additional message_metadata
with info about:
-
pricing_category
, which is the pricing category for the conversation. -
whatsapp_conversation_id
, which is the WhatsApp conversation ID. Messages with the same ID belong to the same conversation, and this ID is included in every Delivery Report generated during the conversation.
For example:
{
"app_id": "01E8RCZPK7HFV70FFDWFFK0EXK",
"accepted_time": "2020-06-22T11:05:53.910Z",
"event_time": "2020-06-22T11:20:08.120Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"message_delivery_report": {
"message_id": "01EBDV9EFP66ZA0GQJ9MCX1V9H",
"conversation_id": "01EB199XQ2CBY50K6WZD9S1A22",
"status": "READ",
"channel_identity": {
"channel": "WHATSAPP",
"identity": "+46702471483",
"app_id": ""
},
"contact_id": "01EB197NDA4W7V15NPRCVV0S79",
"metadata": "",
"processing_mode": "CONVERSATION"
},
"message_metadata": "{\"pricing_category\":\"service\",\"whatsapp_conversation_id\":\"a36709b572981c281648d7d23d91588z\"}"
}
When the first delivery receipt with a DELIVERED
status and a new whatsapp_conversation_id
is received, the customer is charged for a new conversation in the conversation category. All messages sent to the recipient that are part of the same conversation within a 24-hour window (or, in the case of Free Entry Point conversations, 72-hour window) don't incur additional charges.
Receiving Messages
WhatsApp channel supports various kinds of contact messages - text, media, media card, location, and choice response.
Note:
Please note that the media URLs included in the contact messages are valid for 7 days. After that the media is deleted from Conversation API storage.
All of these are delivered by Conversation API with a POST
to the MESSAGE_INBOUND
webhook:
Text message response webhook example
Below is an example of a Conversation API POST
to the MESSAGE_INBOUND
webhook for a text message response:
{
"app_id": "01E8RCZPK7HFV70FFDWFFK0EXK",
"accepted_time": "2020-06-22T10:55:39.534687Z",
"event_time": "2020-06-22T10:55:39.200Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"message": {
"id": "01EBDTPPG3Q3EH14H7DY8X09MG",
"direction": "TO_APP",
"contact_message": {
"text_message": {
"text": "Hi from contact"
}
},
"channel_identity": {
"channel": "WHATSAPP",
"identity": "46712312312",
"app_id": ""
},
"conversation_id": "01EB199XQ2CBY50K6WZD9S1A22",
"contact_id": "01EB197NDA4W7V15NPRCVV0S79",
"metadata": "",
"accept_time": "2020-06-22T10:55:39.521500Z"
}
}
Media message response webhook example
Below is an example of a Conversation API POST
to the MESSAGE_INBOUND
webhook for a media message response:
{
"app_id": "01EB37HMH1M6SV18ASNS3G135H",
"accepted_time": "2020-10-01T12:10:55.073703Z",
"event_time": "2020-10-01T12:10:53.991Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"message": {
"id": "01EKJ1534NWK5R02TGWEJN13HA",
"direction": "TO_APP",
"contact_message": {
"media_message": {
"url": "https://1vxc0v12qhrm1e72gq1mmxkf-wpengine.netdna-ssl.com/wp-content/uploads/2019/05/Sinch-logo-Events.png"
}
},
"channel_identity": {
"channel": "WHATSAPP",
"identity": "46712312312",
"app_id": ""
},
"conversation_id": "01EKJ0KSWXMVDF05MG9TQ20S06",
"contact_id": "01EKA07N79THJ20WSN6AS30TMW",
"metadata": "",
"accept_time": "2020-10-01T12:10:55.060170Z"
}
}
Media card message response webhook example
Below is an example of a Conversation API POST
to the MESSAGE_INBOUND
webhook for a media card message response:
{
"app_id": "01EB37HMH1M6SV18ASNS3G135H",
"accepted_time": "2020-10-01T12:10:55.073703Z",
"event_time": "2020-10-01T12:10:53.991Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"message": {
"id": "01EKJ1534NWK5R02TGWEJN13HA",
"direction": "TO_APP",
"contact_message": {
"media_card_message": {
"url": "https://1vxc0v12qhrm1e72gq1mmxkf-wpengine.netdna-ssl.com/wp-content/uploads/2019/05/Sinch-logo-Events.png",
"caption": "caption text"
}
},
"channel_identity": {
"channel": "WHATSAPP",
"identity": "46712312312",
"app_id": ""
},
"conversation_id": "01EKJ0KSWXMVDF05MG9TQ20S06",
"contact_id": "01EKA07N79THJ20WSN6AS30TMW",
"metadata": "",
"accept_time": "2020-10-01T12:10:55.060170Z"
}
}
Location message response webhook example
Below is an example of a Conversation API POST
to the MESSAGE_INBOUND
webhook for a location message response:
{
"app_id": "01E8RCZPK7HFV70FFDWFFK0EXK",
"accepted_time": "2020-06-22T10:57:36.074692Z",
"event_time": "2020-06-22T10:57:34.012Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"message": {
"id": "01EBDTT89ZGTGM0P70W0RK0YR2",
"direction": "TO_APP",
"contact_message": {
"location_message": {
"title": "ICA Jägaren",
"coordinates": {
"latitude": 55.727802,
"longitude": 13.175061
},
"label": ""
}
},
"channel_identity": {
"channel": "WHATSAPP",
"identity": "46712312312",
"app_id": ""
},
"conversation_id": "01EB199XQ2CBY50K6WZD9S1A22",
"contact_id": "01EB197NDA4W7V15NPRCVV0S79",
"metadata": "",
"accept_time": "2020-06-22T10:57:36.060961Z"
}
}
Choice message response webhook example
Below is an example of a Conversation API POST
to the MESSAGE_INBOUND
webhook for a choice message response:
{
"app_id": "01E8RCZPK7HFV70FFDWFFK0EXK",
"accepted_time": "2020-06-22T11:00:32.866988Z",
"event_time": "2020-06-22T11:00:30.456Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"message": {
"id": "01EBDTZMYPHM0G1D0AJFEZ0A4P",
"direction": "TO_APP",
"contact_message": {
"choice_response_message": {
"message_id": "01EBDTZ9SN8HTW092K56PH1GDS",
"postback_data": "email_postback"
}
},
"channel_identity": {
"channel": "WHATSAPP",
"identity": "46712312312",
"app_id": ""
},
"conversation_id": "01EB199XQ2CBY50K6WZD9S1A22",
"contact_id": "01EB197NDA4W7V15NPRCVV0S79",
"metadata": "",
"accept_time": "2020-06-22T11:00:32.852315Z"
}
}
Reaction to ads
Below is an example of a Conversation API POST
to the MESSAGE_INBOUND
webhook for a message initiated by a user clicking an ad:
{
"app_id": "01EB37HMH1M6SV18ASNS3G135H",
"accepted_time": "2020-10-01T12:10:55.073703Z",
"event_time": "2020-10-01T12:10:53.991Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"message": {
"id": "01EKJ1534NWK5R02TGWEJN13HA",
"direction": "TO_APP",
"contact_message": {
"media_card_message": {
"url": "https://1vxc0v12qhrm1e72gq1mmxkf-wpengine.netdna-ssl.com/wp-content/uploads/2019/05/Sinch-logo-Events.png",
"caption": "Check out my product!"
}
},
"channel_identity": {
"channel": "WHATSAPP",
"identity": "46712312312",
"app_id": ""
},
"conversation_id": "01EKJ0KSWXMVDF05MG9TQ20S06",
"contact_id": "01EKA07N79THJ20WSN6AS30TMW",
"metadata": "{\"referral\":{\"source_type\":\"<SOURCE_TYPE>\",\"source_id\":\"<SOURCE_ID>\",\"source_url\":\"<SOURCE_URL>\",\"ctwa_clid\":\"<CLICK_ID>\",\"headline\":\"Our new product\",\"body\":\"This is a great product\"}}",
"accept_time": "2020-10-01T12:10:55.060170Z"
}
}
This Conversation API callback will contain additional metadata
with info about the ad which initiated the user message, including the following fields:
-
headline
- The headline used in the ad that generated the user message -
body
- The body of the ad that generated the user message -
source_type
- The source of the ad; eitherad
orpost
-
source_id
- The Facebook ID for the corresponding ad or post -
source_url
- The url that leads to the corresponding ad or post -
ctwa_clid
- The click ID generated by Meta for Click-To-WhatsApp ads
Channel Specific Message response webhook example
Below is an example of a Conversation API POST
to the MESSAGE_INBOUND
webhook for a Flow channel specific message response:
{
"app_id": "01E8RCZPK7HFV70FFDWFFK0EXK",
"accepted_time": "2020-06-22T11:00:32.866988Z",
"event_time": "2020-06-22T11:00:30.456Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"message": {
"id": "01EBDTZMYPHM0G1D0AJFEZ0A4P",
"direction": "TO_APP",
"contact_message": {
"channel_specific_message": {
"message_type": "nfm_reply",
"message": {
"type": "nfm_reply",
"nfm_reply": {
"response_json": "{\"flow_token\": \"<FLOW_TOKEN>\", \"optional_param1\": \"<value1>\", \"optional_param2\": \"<value2>\"}",
"body": "Sent",
"name": "flow"
}
}
}
},
"channel_identity": {
"channel": "WHATSAPP",
"identity": "46712312312",
"app_id": ""
},
"conversation_id": "01EB199XQ2CBY50K6WZD9S1A22",
"contact_id": "01EB197NDA4W7V15NPRCVV0S79",
"metadata": "",
"accept_time": "2020-06-22T11:00:32.852315Z"
}
}
Receiving WABA events
In addition to messages, the WhatsApp channel allows you to receive event information about Quality Rating, Daily Limit, or Template Status changes.
All of these are delivered by Conversation API with a POST
to the CHANNEL_EVENT
webhook:
Quality Rating changed webhook example
Below is an example of a Conversation API POST
to the CHANNEL_EVENT
webhook for a Quality Rating change event:
{
"app_id": "01E8RCZPK7HFV70FFDWFFK0EXK",
"event_time": "2022-07-25T06:23:46Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"channel_event_notification": {
"channel_event": {
"channel": "WHATSAPP",
"event_type": "WHATS_APP_QUALITY_RATING_CHANGED",
"additional_data": {
"quality_rating": "GREEN"
}
}
},
"message_metadata": ""
}
Daily Limit changed webhook example
Below is an example of a Conversation API POST
to the CHANNEL_EVENT
webhook for a Daily Limit change event:
{
"app_id": "01E8RCZPK7HFV70FFDWFFK0EXK",
"event_time": "2022-07-26T08:15:00Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"channel_event_notification": {
"channel_event": {
"channel": "WHATSAPP",
"event_type": "WHATS_APP_DAILY_LIMIT_CHANGED",
"additional_data": {
"daily_limit": "TIER_100K"
}
}
},
"message_metadata": ""
}
Template Status changed webhook example
Below is an example of a Conversation API POST
to the CHANNEL_EVENT
webhook for a Template Status change event:
{
"app_id": "01E8RCZPK7HFV70FFDWFFK0EXK",
"event_time": "2022-10-21T10:20:00Z",
"project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
"channel_event_notification": {
"channel_event": {
"channel": "WHATSAPP",
"event_type": "WHATS_APP_TEMPLATE_STATUS_UPDATED",
"additional_data": {
"status": "PAUSED",
"status_details": "FIRST_PAUSE Your WhatsApp message template has been paused for 3 hours until Oct 21 at 12:20 AM UTC because it had issues."
}
}
},
"message_metadata": ""
}
Webhooks will only be sent when the Template status is updated to PAUSED
, REINSTATED
, FLAGGED
or DISABLED
.
Receiving other WhatsApp callbacks
When using the Conversation API, you can subscribe to the UNSUPPORTED
webhook trigger. This trigger is activated when a callback received from an underlying channel does not fall into the categories covered by the other Conversation API webhook triggers. When this occurs, the raw content of the callback is forwarded to the Conversation API app (assuming it is subscribed to the UNSUPPORTED
webhook trigger). For the WhatsApp channel, the following WhatsApp callback payloads will be forwarded using the Conversation API UNSUPPORTED
trigger:
-
Any WhatsApp callback with a
type
that is set toUNKNOWN
. -
Any WhatsApp callback with a
type
that is set toUNSUPPORTED
. - Any other WhatsApp callback that has not yet been mapped to an existing Conversation API callback.
For more information on WhatsApp-specific payloads that may be delivered using the UNSUPPORTED
webhook trigger, see WhatsApp's Webhooks Notification Payload Reference. For more information regarding the UNSUPPORTED
webhook trigger, see our documentation on Conversation API webhooks and callbacks.