Skip to main content

Webhooks

Webhooks are configurable via the Turn UI.

Webhook Subscriptions

Each Webhook must specify at least 1 subscription. A subscription is an identifier for what type of events a webhook endpoint should be receiving.

Currently the following two subscription types are supported: whatsapp and turn.

note

engage was a supported type but is deprecated and will soon be removed.

The subscription type is submitted along with the HTTP request as an HTTP Header.

X-Turn-Hook-Subscription: whatsapp

WhatsApp Subscriptions

This is the default subscription type. All events generated by the WhatsApp Enterprise Client are dispatched to any webhook subscribed to this subscription type. If you are interested in receiving inbound messages or message delivery notifications from your target audience, this is the subscription you should be using. The details of these events are documented below in Inbound Message Webhooks and Outbound Status Notifications.

warning

We recommend that anyone who receives messages via the Webhook, enforce a uniqueness check on the message id to prevent acting on double deliveries.

Turn Subscriptions

X-WhatsApp-Id: <whatsapp's message id>

This is a subscription type that is generated for messages created through the messaging API that Turn exposes. If you are interested in receiving webhook events for whenever an API client dispatches an outbound message to someone in your target audience on WhatsApp, this is the subscription you should be using.

The webhooks receive the exact same payload as was submitted to the HTTP API endpoint.

An extra HTTP Header X-WhatsApp-Id is provided along with the original payload. The value of the header is theId that WhatsApp has assigned to this message and which any message delivery status updates will refer to.

note

Note that these messages are only dispatched after the WhatsApp Enterprise Client has successfully accepted the message for delivery.

Inbound Message Webhooks

{
"contacts": [{
"profile": {
"name": "Kerry Fisher"
},
"wa_id": "16315551234"
}],
"messages": [{
"context": {
"from": "sender_wa_id_of_context_message",
"id": "message_id_of_context_message"
},

"from": "sender_wa_id",
"id": "message_id",
"timestamp": "message_timestamp",
"type": "audio | document | image | location | system | text | video | voice | contacts",

# Only in case of error, errors field (array) will be present
"errors": [ { ... } ],

"audio": {
"file": "absolute_filepath_on_coreapp",
"id": "media id",
"link": "link to audio file",
"mime_type": "media mime type",
"sha256": "checksum"
},

"document": {
"file": "absolute_filepath_on_coreapp",
"id": "media id",
"link": "link to document file",
"mime_type": "media mime type",
"sha256": "checksum",
"caption": "document caption"
},

"image": {
"file": "absolute_filepath_on_coreapp",
"id": "media id",
"link": "link to image file",
"mime_type": "media mime type",
"sha256": "checksum",
"caption": "image caption"
},

"location": {
"address": "1 hacker way, menlo park, ca, 94025",
"latitude": latitude,
"longitude": longitude,
"name": "location name"
},

"system": {
"body": "system message content"
},

"text": {
"body": "text message content"
},

"video": {
"file": "absolute_filepath_on_coreapp",
"id": "media id",
"link": "link to video file",
"mime_type": "media mime type",
"sha256": "checksum"
},

"voice": {
"file": "absolute_filepath_on_coreapp",
"id": "media id",
"link": "link to audio file",
"mime_type": "media mime type",
"sha256": "checksum"
}

"contacts": [{
"addresses": [{
"city": "Menlo Park",
"country": "United States",
"country_code": "us",
"state": "CA",
"street": "1 Hacker Way",
"type": "WORK",
"zip": "94025"
}],
"birthday": "2012-08-18",
"contact_image": "/9j/4AAQSkZJRgABAQEAZABkAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABgAGADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1NLloxyc0j3bNUHDGgoCMVNkBbhutvVqc9yGHNZ3kOW4Wn/ZnQZzSsgLLXAA61Xn1O2t4zLcyJHGvV3OAKMADmvOviLq9m11a2bO/l2xLzoqnliF2j9f1NTLRXHGHM7Hb2vivSL+8e0s7yKaVeyHg/Q9D+FXWuHPOzivFodT0WZkeF44bheVdE2EH+Rr2+zuVuNPt7gqh86JX+TkcjPFTCdy6lNQ2dyr5+G5WpRe4HTFWWSOQfwioZbCIn5XNaXRmQPegjmqrKLh+...",
"emails": [{
"email": "kfish@fb.com",
"type": "WORK"
}],
"ims": [{
"service": "AIM",
"user_id": "kfish"
}],
"name": {
"first_name": "Kerry",
"formatted_name": "Kerry Fisher",
"last_name": "Fisher"
},
"org": {
"company": "Facebook"
},
"phones": [{
"phone": "+1 (940) 555-1234",
"type": "CELL"
}, {
"phone": "+1 (650) 555-1234",
"type": "WORK",
"wa_id": "16505551234"
}],
"urls": [{
"url": "https://www.facebook.com",
"type": "WORK"
}]
}]
}]
}

The general format of the notifications Webhook is shown. You will need create an endpoint handler that is triggered by the sending or receiving of a message. The following sections provide more detail for each type of notification.

Marking Inbound messages as read

You can use the /v1/messages/<message-id> endpoint to change the status of incoming messages to read.

$ curl -X PUT "https://whatsapp.turn.io/v1/messages/<message-id>" \
-H "Authorization: Bearer token" \
-d '
{
"status": "read"
}'
> {}

Make sure to replace token with your access token.

Outbound Status Notifications

Message was sent

{
"statuses": [
{
"id": "ABGGFlA5FpafAgo6tHcNmNjXmuSf",
"status": "sent",
"timestamp": "1518694700",
"message": {
"recipient_id":"16315555555"
}
}
]
}

Message was read

{
"statuses": [
{
"id": "ABGGFlA5FpafAgo6tHcNmNjXmuSf",
"status": "read",
"timestamp": "1518694700",
"message": {
"recipient_id":"16315555555"
}
}
]
}

The WhatsApp Business API client will send notifications to inform you of the status of messages you send to users. When the message is sent successfully, you will receive a notification when the message is sent, delivered, and read. The order of these notifications in your app may not reflect the actual timing of the message status. View the timestamp to determine the timing, if necessary. The notifications you may receive are:

  1. sent - Message was received by the server.
  2. delivered - Message was delivered to user's device.
  3. read - Message was read by the user. Read notifications will only be available for those users that have read receipts enabled. For users that do not have it enabled, you will only receive the delivered notification.
  4. failed - Message failed to send.
note

For a status to be read, it must have been delivered. In some scenarios, such as when a user is in the chat screen and a message arrives, the message is delivered and read almost simultaneously. In this or other similar scenarios, the delivered notification will be discarded, as it is implied with that a message has been delivered if it has been read. The reason for this behavior is internal optimization.

Security

See an example below of how the signature can be calculated using the Python programming language.

>>> import hmac
>>> import base64
>>> from hashlib import sha256
>>> h = hmac.new("secret", '{"foo":"bar"}', sha256)
>>> base64.b64encode(h.digest())
'PzqzmGtlarsXrz6xRD7WwI74//n+qDkVkJ0bQhrsib4='

The signature is sent as an HTTP header to the webhook endpoints you have configured.

X-Turn-Hook-Subscription: whatsapp
X-Turn-Hook-Signature: PzqzmGtlarsXrz6xRD7WwI74//n+qDkVkJ0bQhrsib4=

Each webhook has an hmac_digest and hmac_secret set. These are used to calculate a signature for the webhook payload. Using this signature you can verify that the webhook was indeed received from Turn.

note

Currently only SHA256 is supported as an hmac digest

The signature is sent as an HTTP header in the webhook posted to the endpoints you have configured.

Notification Errors

When there is an error in the sending or receiving of a notification, the errors array will provide a description of the error. This type of error can be caused by transient network connectivity errors, invalid credentials, management controllers in unavailable status, etc.

{
"errors": [{
"code": <error-code>,
"title": "<error-title>",
"details": "<error-description>",
"href": "location for error detail"
},
{
...
}
]
}