Conversation API callbacks

Registering webhooks and listening to callbacks from the Sinch Conversation API.

Webhook Management

The Conversation API delivers contact messages, delivery receipts for app messages and various notifications through callbacks.

API clients can create fine-grained subscriptions for up-to 5 endpoints (webhooks) per conversation API app through the Sinch Portal or by using the /webhooks management endpoint.

Each webhook represents a subscription for events defined by a list of triggers. The events are delivered by the Conversation API to the webhook target URL. The callbacks are signed with the webhook secret if such is provided. The signature can be used to verify the authenticity and integrity of the callbacks.

Webhook Triggers

Each webhook can subscribe to one or more of the following triggers:

Smart Conversations Trigger

Note:

Please note that this functionality is currently available for open beta testing.

In addition to the standard webhooks, you may also configure your solution to subscribe to the SMART_CONVERSATION webhook. This trigger allows you to subscribe to notifications that provide machine learning analyses of inbound messages from end users on the underlying channels.

For information on the structure of the callback, see Smart Conversations callbacks.

Creating webhooks using the API

The snippet below demonstrates how to create a webhook using the management API. The webhook registers a POST capable endpoint with URL {{WEBHOOK_URL}} to receive inbound messages and delivery receipts for app with ID {{APP_ID}} and project with ID {{PROJECT_ID}}.

Copy
Copied
curl -X POST \
'https://eu.conversation.api.sinch.com/v1/projects/{{PROJECT_ID}}/webhooks' \
-H 'Content-Type: application/json' --header 'Authorization: Bearer {{ACCESS_TOKEN}}' \
-d '{
 "app_id": "{{APP_ID}}",
 "target": "{{WEBHOOK_URL}}",
 "target_type": "HTTP",
 "triggers": ["MESSAGE_DELIVERY", "MESSAGE_INBOUND"]
}'

Validating Callbacks

Conversation API callbacks triggered by a registered webhook, with a secret set, will contain the following headers:

Field Description
x-sinch-webhook-signature-timestamp Timestamp, in UTC, of when the signature was computed
x-sinch-webhook-signature-nonce A unique nonce that can be used to protect against reply attacks
x-sinch-webhook-signature-algorithm The HMAC signature algorithm that was used to compute the signature. For now it's set to HmacSHA256.
x-sinch-webhook-signature The signature of the raw HTTP body, the timestamp, and the nonce as computed by the Conversation API.

The receiver of signed callbacks should execute the code found in the following example, after replacing the commented values in the example with their values:

JavaScriptPython
Copy
Copied
var crypto = require('crypto')

var secret = 'foo_secret1234' // secret used when creating a webhook; replace with your own value

//actual raw message; replace with your own value
var rawBody = '{"app_id":"","accepted_time":"2021-10-18T17:49:13.813615Z","project_id":"e2df3a34-a71b-4448-9db5-a8d2baad28e4","contact_create_notification":{"contact":{"id":"01FJA8B466Y0R2GNXD78MD9SM1","channel_identities":[{"channel":"SMS","identity":"48123456789","app_id":""}],"display_name":"New Test Contact","email":"new.contact@email.com","external_id":"","metadata":"","language":"EN_US"}},"message_metadata":""}'

var nonce = '01FJA8B4A7BM43YGWSG9GBV067' //x-sinch-webhook-signature-nonce; replace with your own value
var timestamp= 1634579353 //x-sinch-webhook-signature-timestamp; replace with your own value

var signedData = rawBody + '.' + nonce + '.' + timestamp
var signature = crypto.createHmac('sha256', secret).update(signedData).digest('base64')

console.log("calculated-signature     : " + signature)
console.log("x-sinch-webhook-signature: 6bpJoRmFoXVjfJIVglMoJzYXxnoxRujzR4k2GOXewOE=")
Copy
Copied
import base64
import hashlib, hmac

secret = 'foo_secret1234' #secret used when creating a webhook; replace with your own value

#actual raw message; replace with your own value
body = '{"app_id":"","accepted_time":"2021-10-18T17:49:13.813615Z","project_id":"e2df3a34-a71b-4448-9db5-a8d2baad28e4","contact_create_notification":{"contact":{"id":"01FJA8B466Y0R2GNXD78MD9SM1","channel_identities":[{"channel":"SMS","identity":"48123456789","app_id":""}],"display_name":"New Test Contact","email":"new.contact@email.com","external_id":"","metadata":"","language":"EN_US"}},"message_metadata":""}'

nonce = '01FJA8B4A7BM43YGWSG9GBV067' #x-sinch-webhook-signature-nonce; replace with your own value
timestamp= 1634579353 #x-sinch-webhook-signature-timestamp; replace with your own value

signed_data = body + '.' + nonce + '.' + str(timestamp)

digest = hmac.new(secret.encode('utf-8'), signed_data.encode('utf-8'), hashlib.sha256).digest()

print('calculated signature     : ' + base64.b64encode(digest).decode())
print('x-sinch-webhook-signature: 6bpJoRmFoXVjfJIVglMoJzYXxnoxRujzR4k2GOXewOE=')
Note:

HMAC signature validation is sensitive to white spaces, so any white space characters included in the message will impact the final digest.

Callback Format

Each callback dispatched by Conversation API has a JSON payload with the following top-level properties:

Field Type Description
project_id string The project ID of the app which has subscribed for the callback.
app_id string Id of the subscribed app.
accepted_time ISO 8601 timestamp Timestamp marking when the channel callback was accepted/received by the Conversation API.
event_time ISO 8601 timestamp Timestamp of the event as provided by the underlying channels.
message_metadata string Context-dependent metadata. Refer to specific callback's documentation for exact information provided.

Each specific callback type adds additional properties to the payload which are described in detail in the section below.

Inbound Message

This callback delivers contact (end-user) messages to the API clients. The message details are given in a top level message field. It's a JSON object with the following properties:

Field Type Description
id string The message ID.
direction string The direction of the message, it's always TO_APP for contact messages.
contact_message object The content of the message. See Contact Message for details.
channel_identity object The identity of the contact in the underlying channel. See Channel Identity for details.
conversation_id string The ID of the conversation this message is part of. Will be empty if processing_mode is DISPATCH.
contact_id string The ID of the contact. Will be empty if processing_mode is DISPATCH.
metadata string Usually, metadata specific to the underlying channel is provided in this field. Refer to the individual channels' documentation for more information (for example, SMS delivery receipts). Note that, for Choice message responses, this field is populated with the value of the message_metadata field of the corresponding Send message request.
accept_time ISO 8601 timestamp Timestamp marking when the channel callback was received by the Conversation API.
sender_id string The sender ID to which the contact sent the message, if applicable. For example, originator msisdn/short code for SMS and MMS.
processing_mode string The Processing Mode of the message.

Metadata assigned to the conversation, if any, is provided in the top level message_metadata string field.

For example, a string representation of the metadata_json field value of a Create conversation request, or the value assigned to the conversation_metadata field in a Send message request. The last value provided in any of those fields is returned, replacing any previous value, if present.

Example of Inbound Message Callback

Copy
Copied
{
  "app_id": "01EB37HMH1M6SV18ABNS3G135H",
  "accepted_time": "2020-11-16T08:17:44.993024Z",
  "event_time": "2020-11-16T08:17:42.814Z",
  "project_id": "c36f3d3d-1523-4edd-ae42-11995557ff61",
  "message": {
    "id": "01EQ8235TD19N21XQTH12B145D",
    "direction": "TO_APP",
    "contact_message": {
      "text_message": {
        "text": "Hi!"
      }
    },
    "channel_identity": {
      "channel": "MESSENGER",
      "identity": "2742085512340733",
      "app_id": "01EB37HMH1M6SV18ABNS3G135H"
    },
    "conversation_id": "01EQ8172WMDB8008EFT4M30481",
    "contact_id": "01EQ4174TGGY5B1VPTPGHW19R0",
    "metadata": "",
    "accept_time": "2020-11-16T08:17:43.915829Z",
    "sender_id": "12039414555",
    "processing_mode": "CONVERSATION",
    "injected": false
  },
  "message_metadata": "{\"arbitrary\": \"json object stringify as metadata\" }"
}

Contact Message

The table below shows the properties of the contact_message field in inbound message callbacks:

Field Type Description
reply_to object Optional. Included if the contact message is a response to a previous app message. See ReplyTo for details.

It also contains one of the following properties depending on the type of message: text_message, media_message, location_message, choice_response_message, media_card_message, fallback_message.

All of these properties are JSON objects described in the sections below.

Text Message

Field Type Description
text string The text included in the contact message.

Media Message

Field Type Description
url string The URL of the media.

Location Message

Field Type Description
title string The title is shown above the location. The title is sometimes clickable.
coordinates object Geo coordinates of the location specified in the message. See Coordinates for details.
label string Label or name for the position.
Coordinates
Field Type Description
latitude float Latitude of the geographic coordinate.
longitude float Longitude of the geographic coordinate.

Choice Response Message

The choice response message represents a contact response to a choice message.

Field Type Description
message_id string The message id containing the choice.
postback_data string The postback data if defined in the selected choice. Otherwise the default is message_id_{text, title}

Media Card Message

Contact Message containing media and caption.

Field Type Description
url string The URL of the media.
caption string Caption for the media, if supported by channel.

Fallback Message

Fallback message, appears when original contact message can't be handled.

Field Type Description
reason object Fallback reason. See Reason for details.
raw_message string The raw fallback message if provided by the channel.

ReplyTo

Field Type Description
message_id object The id of the message that this contact message is a response to.

Channel Identity

The table below shows the properties of the channel_identity field in Conversation API callbacks:

Field Type Description
channel string Conversation API identifier of the underlying channel example, SMS, RCS, MESSENGER.
identity string The channel identity example, a phone number for SMS, WhatsApp and Viber Business.
app_id string The app ID if this is an app-scoped channel identity. Empty string otherwise. See App-scoped Channel Identities for details.

App-scoped Channel Identities

Currently, Facebook Messenger, Viber Bot, Instagram, Apple Messages for Business, LINE and WeChat channels are using app-scoped channel identities which means contacts will have different channel identities for different apps. For example, Facebook Messenger uses PSIDs (Page-Scoped IDs) as channel identities. The app_id is pointing to the app linked to the Facebook page for which this PSID is issued.

Inbound Event

This callback delivers channel events such as composing to the API clients. The message details are given in a top level event field. It's a JSON object with the following properties:

Field Type Description
id string The event ID.
direction string The direction of the event. It's always TO_APP for contact events.
contact_event object The content of the event. See Contact Event for details.
channel_identity object The identity of the contact in the underlying channel. See Channel Identity for details.
contact_id string The ID of the contact. Will be empty if processing_mode is DISPATCH.
conversation_id string The ID of the conversation this event is part of. Will be empty if processing_mode is DISPATCH.
accept_time ISO 8601 timestamp Timestamp marking when the channel callback was received by the Conversation API.
processing_mode string The Processing Mode of the event.

Example of Inbound Event Callback

Copy
Copied
{
  "app_id": "01EB37HMH1M6SV18ABNS3G135H",
  "accepted_time": "2020-11-16T08:17:44.993024Z",
  "event_time": "2020-11-16T08:17:42.814Z",
  "project_id": "c36f3d3d-1523-4edd-ae42-11995557ff61",
  "event": {
    "id": "01GJMQ28NDF6FP0REWQ70N2W3E",
    "direction": "TO_APP",
    "contact_event": {
      "composing_event": {}
    },
    "channel_identity": {
      "channel": "RCS",
      "identity": "123456789",
      "app_id": ""
    },
    "contact_id": "01EQ4174TGGY5B1VPTPGHW19R0",
    "conversation_id": "01GJMQ3782FWM7TKAZKQZAEF56",
    "accept_time": "2020-11-16T08:17:43.915829Z",
    "processing_mode": "CONVERSATION"
  }
}

Contact Event

The table below shows the properties of the contact_event field in inbound event callbacks:

Field Type Description
composing_event object Empty object denoting the contact is composing a message.
comment_event object Object which contains information of a comment made by an user outside of the main conversation context. Currently only supported on Instagram channel, see Instagram Private Replies for more details

Message Delivery Receipt

This callback notifies the API clients about status changes of already sent app message. The delivery receipt details are given in a top level message_delivery_report field. It's a JSON object with the following properties:

Field Type Description
message_id string The ID of the app message.
conversation_id string The ID of the conversation the app message is part of. Will be empty if processing_mode is DISPATCH.
status string The delivery status. See Delivery Status for details.
channel_identity object The identity of the contact in the underlying channel. See Channel Identity for details.
contact_id string The ID of the contact. Will be empty if processing_mode is DISPATCH.
reason object Error reason if status is FAILED or SWITCHING_CHANNEL. See Reason for details.
metadata string Metadata specified in the message_metadata field of a Send Message request, if any.
processing_mode string The Processing Mode of the message.

Additional metadata, if any, is provided in the top level message_metadata string field. This is specific to the underlying channel used. Refer to the individual channels' documentation for more information. For example, SMS delivery receipts.

Note:

Delivery receipts depend on the existence of message mapping, which is metadata that enables matching messages by channelMessageId. Dispatching is limited to the lesser value between 30 days or the retention policy specified by App.

Delivery receipts will not be generated after this time. The 30 day restriction is due to Entity Retention Job, which permanently removes message mappings from the datastore.

Note that a retention cleanup job runs once every twenty-four hours, which can lead to delays between the minute in which message mappings become eligible for deletion and the moment in which the message mappings are actually deleted.

Example of Message Delivery Receipt

The example below shows a receipt for successfully enqueued message with ID 01EQBC1A3BEK731GY4YXEN0C2R on MESSENGER channel:

Copy
Copied
{
  "app_id": "01EB37HMH1M6SV18BSNS3G135H",
  "accepted_time": "2020-11-17T15:09:11.659Z",
  "event_time": "2020-11-17T15:09:13.267185Z",
  "project_id": "c36f3d3d-1513-2edd-ae42-11995557ff61",
  "message_delivery_report": {
    "message_id": "01EQBC1A3BEK731GY4YXEN0C2R",
    "conversation_id": "01EPYATA64TMNZ1FV02JKF12JF",
    "status": "QUEUED_ON_CHANNEL",
    "channel_identity": {
      "channel": "MESSENGER",
      "identity": "2734085512340733",
      "app_id": "01EB27HMH1M6SV18ASNS3G135H"
    },
    "contact_id": "01EXA07N79THJ20WSN6AS30TMW",
    "metadata": "",
    "processing_mode": "CONVERSATION"
  },
  "message_metadata": ""
}

When the sending of the message failed the receipt includes a reason object describing the error:

Copy
Copied
{
  "app_id": "01EB37HMH1M6SV18BSNS3G135H",
  "accepted_time": "2020-11-17T16:01:06.374Z",
  "event_time": "2020-11-17T16:01:07Z",
  "project_id": "c36f3d3d-1513-4edd-ae42-11995557ff61",
  "message_delivery_report": {
    "message_id": "01EQBF0BT63J7S1FEKJZ0Z08VD",
    "conversation_id": "01EQBCFQR3EGE60P42H6H1117J",
    "status": "FAILED",
    "channel_identity": {
      "channel": "WHATSAPP",
      "identity": "12345678910",
      "app_id": ""
    },
    "contact_id": "01EXA07N79THJ20WSN6AS30TMW",
    "reason": {
      "code": "OUTSIDE_ALLOWED_SENDING_WINDOW",
      "description": "The underlying channel reported: Message failed to send because more than 24 hours have passed since the customer last replied to this number",
      "sub_code": "UNSPECIFIED_SUB_CODE"
    },
    "metadata": ""
  },
  "message_metadata": ""
}

Delivery Status

The field status is included in delivery receipt callbacks and shows the status of the message or event delivery. The status field can have the following values:

  • QUEUED
  • QUEUED_ON_CHANNEL
  • DELIVERED
  • READ
  • FAILED
  • SWITCHING_CHANNEL

Each message and event sent by the API clients to contacts go through the following states:

  1. The message is successfully queued in Conversation API. It has status QUEUED .
  2. The message is successfully dispatched to an underlying channel. It has status QUEUED_ON_CHANNEL .
  3. A delivery receipt is sent from the underlying channel detailing the delivery status on the channel. Depending on the channel response and the processing state of the message, the message is transitioned to one of following states:

    3.1 DELIVERED - the channel delivery receipt indicated the message has reached the end user. Some channels can later send new delivery receipts with a READ status.

    3.2 READ - the channel delivery receipt indicated the message was seen or read by the end user. This is a terminal state. There can't be more state changes after the message is in READ state. Some channel will omit sending DELIVERED when the message is seen immediately by the user. In such cases the DELIVERED status is implicit.

    3.3 FAILED - the channel delivery receipt indicated the message delivery failed and there are no more channels to try according to the channel priority defined in the send request. This is a terminal state. There can't be more state changes after the message is FAILED state.

    3.4 SWITCHING_CHANNEL - the channel delivery receipt indicated the message delivery failed. However, there are more channels which Conversation API can try to send the message according to the channel priority defined in the send request.

Note: There are no callbacks sent for status QUEUED since this state is already known by the API clients when they receive successful response from the /messages:send endpoint.

Reason

The reason field in FAILED or SWITCHING_CHANNEL delivery receipt callbacks provides information for the reason of the failure.

The table below shows the properties of the reason field:

Field Type Description
code string High-level classification of the error. See Error Codes for details.
description string A description of the reason.
sub_code string The sub code is a more detailed classification of the main error. See Error Sub-Codes for details.

Error Codes

Conversation API provides a set of common reason codes which can be used to automate the error handling by the API clients. The codes are as follow:

  • RATE_LIMITED - the message or event wasn't sent due to rate limiting.
  • RECIPIENT_INVALID_CHANNEL_IDENTITY - the channel recipient identity was malformed.
  • RECIPIENT_NOT_REACHABLE - it wasn't possible to reach the contact, or channel recipient identity, on the channel.
  • RECIPIENT_NOT_OPTED_IN - the contact, or channel recipient identity, hasn't opted in on the channel.
  • OUTSIDE_ALLOWED_SENDING_WINDOW - the allowed sending window has expired. See the channel support documentation for more information about how the sending window works for the different channels.
  • CHANNEL_FAILURE - the channel failed to accept the message. The Conversation API performs multiple retries in case of transient errors.
  • CHANNEL_BAD_CONFIGURATION - the channel configuration of the app is wrong. The bad configuration caused the channel to reject the message.
  • CHANNEL_CONFIGURATION_MISSING - the referenced app has no configuration for the channel.
  • MEDIA_TYPE_UNSUPPORTED - indicates that the sent message had an unsupported media type.
  • MEDIA_TOO_LARGE - some of the referenced media files are too large. See the channel support documentation to find out the limitations on file size that the different channels impose.
  • MEDIA_NOT_REACHABLE - the provided media link wasn't accessible from the Conversation API or from the underlying channels. Please make sure that the media file is accessible.
  • NO_CHANNELS_LEFT - no channels to try to send the message to. This error will occur if all applicable channels have been attempted.
  • TEMPLATE_NOT_FOUND - the referenced template wasn't found.
  • TEMPLATE_INSUFFICIENT_PARAMETERS - not all parameters defined in the template were provided when sending a template message.
  • TEMPLATE_NON_EXISTING_LANGUAGE_OR_VERSION - the selected language, or version, of the referenced template didn't exist. Please check the available versions and languages of the template.
  • DELIVERY_TIMED_OUT - the message or event delivery failed due to a channel-imposed timeout.
  • DELIVERY_REJECTED_DUE_TO_POLICY - the message or event was rejected by the channel due to a policy. Some channels have specific policies that must be met to send a message. See the channel support documentation for more information about when this error will be triggered.
  • CONTACT_NOT_FOUND - the provided Contact ID didn't exist.
  • BAD_REQUEST - Conversation API validates send requests in two different stages. The first stage is right before the message is enqueued. If this first validation fails the API responds with 400 Bad Request and the request is discarded immediately. The second validation kicks in during message processing and it normally contains channel specific validation rules. Failures during second request validation are delivered as callbacks to MESSAGE_DELIVERY (EVENT_DELIVERY) webhooks with ReasonCode BAD_REQUEST .
  • UNKNOWN_APP - missing app. This error may occur when the app is removed during message processing.
  • NO_CHANNEL_IDENTITY_FOR_CONTACT - the contact has no channel identities for the resolved channel priorities.
  • CHANNEL_REJECT - generic error for channel permanently rejecting a message.
  • UNKNOWN - returned if no other code can be used to describe the encountered error.
  • INTERNAL_ERROR - an internal error occurred. Please save the entire callback if you want to report an error.

Error Sub-Codes

  • UNSPECIFIED_SUB_CODE - used if no other sub code can be used to describe the encountered error.
  • ATTACHMENT_REJECTED - occurs when the message attachment has been rejected by the channel due to a policy. Some channels have specific policies that must be met to receive an attachment.

Message Submit Notification

This callback provides a notification to the API clients that the corresponding app message was submited to a channel. This notification is created before any confirmation from Delivery Receipts. The message submission details are given in a top level message_submit_notification field. It's a JSON object with the following properties:

Field Type Description
message_id string The ID of the app message.
conversation_id string The ID of the conversation the app message is part of. Will be empty if processing_mode is DISPATCH.
channel_identity object The identity of the contact in the underlying channel. See Channel Identity for details.
contact_id string The ID of the contact. Will be empty if processing_mode is DISPATCH.
submitted_message object The app message submitted to the channel.
metadata string Metadata specified in the message_metadata field of a Send Message request, if any.
processing_mode string The Processing Mode of the message.

Additional metadata, if any, is provided in the top level message_metadata string field. This is specific to the underlying channel used. Refer to the individual channels' documentation for more information. For example, SMS delivery receipts.

Example of Message Submit Notification

The example below shows a notification for a submitted message with ID 01EQBC1A3BEK731GY4YXEN0C2R on the MESSENGER channel:

Copy
Copied
{
   "app_id":"01EB37HMH1M6SV18BSNS3G135H",
   "accepted_time": "2020-11-17T15:09:11.659Z",
   "event_time": "2020-11-17T15:09:13.267185Z",
   "project_id":"c36f3d3d-1513-2edd-ae42-11995557ff61",
   "message_submit_notification":{
      "message_id":"01EQBC1A3BEK731GY4YXEN0C2R",
      "conversation_id":"01EPYATA64TMNZ1FV02JKF12JF",
      "channel_identity":{
         "channel":"MESSENGER",
         "identity":"2734085512340733",
         "app_id":"01EB27HMH1M6SV18ASNS3G135H"
      },
      "contact_id":"01EXA07N79THJ20WSN6AS30TMW",
      "submitted_message":{
         "text_message":{
            "text":"Hello from Conversation API!"
         }
      },
      "metadata":"",
      "processing_mode":"CONVERSATION"
   },
   "message_metadata":""
}

Event Delivery Receipt

This callback notifies the API clients about status changes of already sent app events. The delivery receipt details are given in a top level event_delivery_report field. It's a JSON object with the following properties:

Field Type Description
event_id string The ID of the app event.
status string The delivery status. See Delivery Status for details.
channel_identity object The identity of the contact in the underlying channel. See Channel Identity for details.
contact_id string The ID of the contact. Will be empty if processing_mode is DISPATCH.
reason object Error reason if status is FAILED or SWITCHING_CHANNEL. See Reason for details.
metadata string Metadata specified when sending the event if any.
processing_mode string The Processing Mode of the event.

Example of Event Delivery Callback

Copy
Copied
{
  "app_id": "01EB37HMH1M6SV18BSNS3G135H",
  "accepted_time": "2020-11-17T15:09:11.659Z",
  "event_time": "2020-11-17T15:09:13.267185Z",
  "project_id": "c36f3d3d-1513-2edd-ae42-11995557ff61",
  "event_delivery_report": {
    "event_id": "01EQBC1A3BEK731GY4YXEN0C2R",
    "status": "QUEUED_ON_CHANNEL",
    "channel_identity": {
      "channel": "MESSENGER",
      "identity": "2734085512340733",
      "app_id": "01EB27HMH1M6SV18ASNS3G135H"
    },
    "contact_id": "01EXA07N79THJ20WSN6AS30TMW",
    "metadata": "",
    "processing_mode": "CONVERSATION"
  },
  "message_metadata": ""
}

Conversation Start

This callback is sent when a new conversation between the subscribed app and a contact is started. The conversation details are given in a top level conversation_start_notification field. It's a JSON object with the following properties:

Field Type Description
conversation object The properties of the started conversation

Example of Conversation Start Callback

Copy
Copied
{
  "app_id": "01EB37HMH1M6SV18ASNS3G135H",
  "project_id": "c36f3d3d-1523-4edd-ae42-11995557ff61",
  "conversation_start_notification": {
    "conversation": {
      "id": "01EQ4174WMDB8008EFT4M30481",
      "app_id": "01EB37HMH1M6SF18ASNS3G135H",
      "contact_id": "01BQ8174TGGY5B1VPTPGHW19R0",
      "active_channel": "MESSENGER",
      "active": true,
      "metadata": ""
    }
  }
}

Conversation Stop

This callback is sent when a conversation between the subscribed app and a contact is stopped. The conversation details are given in a top level conversation_stop_notification field. It's a JSON object with the following properties:

Field Type Description
conversation object The properties of the stopped conversation.

Example of Conversation Stop Callback

Copy
Copied
{
  "app_id": "01EB37HMH1M6SV17ASNS3G135H",
  "project_id": "c36f3d3d-1523-4edd-ae42-11995557ff61",
  "conversation_stop_notification": {
    "conversation": {
      "id": "01EPYATZ64TMNZ1FV02JKD12JF",
      "app_id": "01EB37HMH1M6SV17ASNS3G135H",
      "contact_id": "01EKA07N79THJ20WAN6AS30TMW",
      "last_received": "2020-11-17T15:09:12Z",
      "active_channel": "MESSENGER",
      "active": false,
      "metadata": ""
    }
  }
}

Contact Create

This callback is sent when a new contact is created. The contact details are given in a top level contact_create_notification field. It's a JSON object with the following properties:

Field Type Description
contact object The properties of the created contact.

Example of Contact Create Callback

Copy
Copied
{
  "app_id": "",
  "accepted_time": "2020-11-17T15:36:28.155494Z",
  "project_id": "c36f3a3d-1513-4edd-ae42-11995557ff61",
  "contact_create_notification": {
    "contact": {
      "id": "01EQBDK8771J6A1FV8MQPE1XAR",
      "channel_identities": [
        {
          "channel": "VIBER",
          "identity": "9KC0p+pi4zPGFO99ACDxdQ==",
          "app_id": "01EB37KMH1M6SV18ASNS3G135H"
        }
      ],
      "channel_priority": ["VIBER"],
      "display_name": "Unknown",
      "email": "",
      "external_id": "",
      "metadata": "",
      "language": "UNSPECIFIED"
    }
  }
}

Contact Delete

This callback is sent when a contact is deleted. The contact details are given in a top level contact_delete_notification field. It's a JSON object with the following properties:

Field Type Description
contact object The properties of the deleted contact.

Example of Contact Delete Callback

Copy
Copied
{
  "app_id": "",
  "accepted_time": "2020-11-17T15:44:33.517073Z",
  "project_id": "c36f3a3d-1513-4edd-ae42-11995557ff61",
  "contact_delete_notification": {
    "contact": {
      "id": "01EQBDK8771J6A1FV8MQPE1XAR",
      "channel_identities": [
        {
          "channel": "VIBER",
          "identity": "9KC0p+pi4zPGFO99ACDxdQ==",
          "app_id": "01EB37HMH1M6SV13ASNS3G135H"
        }
      ],
      "channel_priority": ["VIBER"],
      "display_name": "Unknown",
      "email": "",
      "external_id": "",
      "metadata": "",
      "language": "UNSPECIFIED"
    }
  }
}

Contact Update

This callback is sent when a contact is updated. The full updated contact details are given in a top level contact_update_notification field. It's a JSON object with the following properties:

Field Type Description
contact object The properties of the updated contact.

Example of Contact Update Callback

Copy
Copied
{
  "app_id": "",
  "accepted_time": "2020-11-17T15:44:33.517073Z",
  "project_id": "c36f3a3d-1513-4edd-ae42-11995557ff61",
  "contact_update_notification": {
    "contact": {
      "id": "01EQBDK8771J6A1FV8MQPE1XAR",
      "channel_identities": [
        {
          "channel": "VIBER",
          "identity": "9KC0p+pi4zPGFO99ACDxdQ==",
          "app_id": "01EB37HMH1M6SV13ASNS3G135H"
        }
      ],
      "channel_priority": ["VIBER"],
      "display_name": "Unknown",
      "email": "",
      "external_id": "",
      "metadata": "",
      "language": "UNSPECIFIED"
    }
  }
}

Contact Merge

This callback is sent when two contacts are merged. The details of the resulting merged and deleted contacts are given in a top level contact_merge_notification field.

It's a JSON object with the following properties:

Field Type Description
preserved_contact object The properties of the resulting merged contact.
deleted_contact object The properties of the deleted contact.

Example of Contact Merge Callback

Copy
Copied
{
  "app_id": "",
  "accepted_time": "2020-11-17T15:53:03.457706Z",
  "project_id": "c36f3a3d-1513-4edd-ae42-11995557ff61",
  "contact_merge_notification": {
    "preserved_contact": {
      "id": "01EQBECE7Z4XP21359SBKS1526",
      "channel_identities": [
        {
          "channel": "VIBER",
          "identity": "9KC0p+pi4zPGFO99ACDxdQ==",
          "app_id": "01EB37KMH1M6SV18ASNS3G135H"
        }
      ],
      "channel_priority": ["VIBER"],
      "display_name": "Unknown",
      "email": "",
      "external_id": "",
      "metadata": "",
      "language": "UNSPECIFIED"
    },
    "deleted_contact": {
      "id": "01EQBEH7MNEZQC0881A4WS17K3",
      "channel_identities": [
        {
          "channel": "VIBER",
          "identity": "9KC0p+pi4zaGFO99ACDxdQ==",
          "app_id": "01EB37KMH1M6SV18ASNS3G135H"
        }
      ],
      "channel_priority": ["VIBER"],
      "display_name": "Unknown",
      "email": "",
      "external_id": "",
      "metadata": "",
      "language": "UNSPECIFIED"
    }
  }
}

Contact Identities Duplication Notification

This callback is sent when duplicates of channel identities are found between multiple contacts in the contact database during message and event processing.

Note:

Project scoped channel identities are considered duplicates when they have the same channel and identity pair within the same project. App scoped channel identities are considered duplicates when they have the same app ID, channel, and identity combination within the same project.

When a duplicate is identified, you must use the contact endpoint to resolve the issue. This notification points to the contacts which should be deleted, updated, or merged to resolve the duplication issue.

It's a JSON object with the following properties:

Field Type Description
duplicated_identities list List which contains information regarding the duplicated identities. Each list entry contains information about the channel on which the duplicate identities were found and the set of contact IDs containing those duplicated channel identities.

For more information on contact duplication, see our documentation on Conversation API contact management.

Example of Contact Identities Duplication Notification

Copy
Copied
{
  "app_id": "01EB37KMH2M6SV18ASNS3G135H",
  "accepted_time": "2022-09-29T09:16:22.544813845Z",
  "event_time": "2022-09-29T09:16:22.544813845Z",
  "project_id": "c36f3a3d-1513-4edd-ae42-11995557ff61",
  "duplicated_contact_identities_notification": {
    "duplicated_identities": [
      {
        "channel": "channel",
        "contact_ids": [
          "01EKA07N79THJ20ZSN6AS30TMW",
          "01EKA07N79THJ20ZSN6AS30TTT"
        ]
      }
    ]
  },
  "message_metadata": ""
}

Capability Check

This callback is used to deliver the results of the asynchronous capability checks. The outcome of the capability check is given in a top level capability_notification field.

It's a JSON object with the following properties:

Field Type Description
request_id string ID generated when submitting the capability request. Can be used to detect duplicates.
contact_id string The ID of the contact.
channel string The channel for which the capability lookup was performed.
identity string The channel identity. For example, a phone number for SMS, WhatsApp, and Viber Business.
capability_status string Status indicating the recipient's capability on the channel. One of CAPABILITY_FULL, CAPABILITY_PARTIAL, NO_CAPABILITY, or CAPABILITY_UNKNOWN.
channel_capabilities string array When capability_status is set to CAPABILITY_PARTIAL, this field includes a list of the supported channel-specific capabilities reported by the channel.
reason object If the capability check failed, this field contains the reason for the error. See Reason for details.

The possible values for capability_status are explained below:

  • CAPABILITY_UNKNOWN : the channel capability for the contact is unknown because the underlying channel has not made this information available.
  • CAPABILITY_FULL : the specified contact supports all the features of the channel.
  • CAPABILITY_PARTIAL : the specified contact supports a subset of the channel features.
  • NO_CAPABILITY : the specified contact supports none of the channel features.

Example of Capability Check Callback

Copy
Copied
{
  "app_id": "01EB37KMH2M6SV18ASNS3G135H",
  "accepted_time": "2020-11-17T16:05:51.724083Z",
  "project_id": "",
  "capability_notification": {
    "contact_id": "01EKA07N79THJ20ZSN6AS30TMW",
    "identity": "12345678910",
    "channel": "WHATSAPP",
    "capability_status": "CAPABILITY_FULL",
    "request_id": "01EQBF91XWP9PW1J8EWRYZ1GK2"
  }
}

Opt-in

This callback is used to deliver opt-in notifications from the channels.

Important:

Opt-in and opt-out callbacks are only supported on Conversation API channels that support opt-in and opt-out notification types (for example, the Viber Business Messages channel). These callbacks are not triggered on unsupported channels. For example, a recipient sending a reply on the SMS channel with the text STOP, UNSUBSCRIBE, etc., will not trigger an opt-out callback.

The opt-in details are given in a top level opt_in_notification field with the following properties:

Field Type Description
request_id string ID generated when making an opt-in registration request. Can be used to detect duplicates.
contact_id string The ID of the contact which is the subject of the opt-in. Will be empty if processing_mode is DISPATCH.
channel string The channel of the opt-in.
identity string The channel identity. For example, a phone number for SMS, WhatsApp and Viber Business.
status string Status of the opt-in registration. One of OPT_IN_SUCCEEDED, OPT_IN_FAILED, or OPT_IN_STATUS_UNSPECIFIED.
error_details object This field is populated if the opt-in failed. It contains a single string property, description, containing a human-readable error description.
processing_mode string The Processing Mode of the opt-in.

The possible values for status are explained below:

  • OPT_IN_STATUS_UNSPECIFIED : the underlying channel doesn't support Opt-in.
  • OPT_IN_SUCCEEDED : the Opt-in registration succeeded.
  • OPT_IN_FAILED : the Opt-in registration failed, see reason in error_details field.

Example of Opt-in Callback

Copy
Copied
{
  "app_id": "01EB37HMH1M6SV18ASNS3G135H",
  "accepted_time": "2021-06-08T07:54:03.165316Z",
  "event_time": "2021-06-08T07:54:02.112Z",
  "project_id": "",
  "opt_in_notification": {
    "contact_id": "01EKA07N79THJ20WSN6AS30TMW",
    "channel": "VIBERBM",
    "identity": "123456789",
    "status": "OPT_IN_SUCCEEDED",
    "request_id": "01F7N9TEH11X7B15XQ6VBR04G7",
    "processing_mode": "CONVERSATION"
  }
}

Opt-out

This callback is used to deliver opt-out notifications from the channels.

Important:

Opt-in and opt-out callbacks are only supported on Conversation API channels that support opt-in and opt-out notification types (for example, the Viber Business Messages channel). These callbacks are not triggered on unsupported channels. For example, a recipient sending a reply on the SMS channel with the text STOP, UNSUBSCRIBE, etc., will not trigger an opt-out callback.

The opt-out details are given in a top level opt_out_notification field with the following properties:

Field Type Description
request_id string ID generated when making an opt-out registration request. Can be used to detect duplicates.
contact_id string The ID of the contact which is the subject of the opt-out. Will be empty if processing_mode is DISPATCH.
channel string The channel of the opt-out.
identity string The channel identity. For example, a phone number for SMS, WhatsApp and Viber Business.
status string Status of the opt-out registration. One of OPT_OUT_SUCCEEDED, OPT_OUT_FAILED, or OPT_OUT_STATUS_UNSPECIFIED.
error_details object This field is populated if the opt-out failed. It contains a single string property, description, containing a human-readable error description.
processing_mode string The Processing Mode of the opt-out.

The possible values for status are explained below:

  • OPT_OUT_STATUS_UNSPECIFIED : the underlying channel doesn't support Opt-out.
  • OPT_OUT_SUCCEEDED : the Opt-out registration succeeded.
  • OPT_OUT_FAILED : the Opt-out registration failed, see reason in error_details

Example of Opt-out Callback

Copy
Copied
{
  "app_id": "01EB37HMH1M6SV18ASNS3G135H",
  "accepted_time": "2021-06-08T07:54:03.165316Z",
  "event_time": "2021-06-08T07:54:02.112Z",
  "project_id": "",
  "opt_out_notification": {
    "contact_id": "01EKA07N79THJ20WSN6AS30TMW",
    "channel": "VIBERBM",
    "identity": "123456789",
    "status": "OPT_OUT_SUCCEEDED",
    "request_id": "01F7N9TEH11X7B15XQ6VBR04G7",
    "processing_mode": "CONVERSATION"
  }
}

Unsupported Callback

Some of the callbacks received from the underlying channels might be specific to a single channel or may not have a proper mapping in Conversation API yet. In such cases the callbacks are forwarded as is all the way to the API clients subscribed to the UNSUPPORTED webhook trigger.

The source of the unsupported callback is given in a top level unsupported_callback field. It's a JSON object with the following properties:

Field Type Description
channel string The channel which is the source of this callback.
payload string Normally a JSON payload as sent by the channel.
processing_mode string The Processing Mode of the callback.
id string The message ID.
contact_id string The ID of the contact. This field is blank if not supported.
conversation_id string The ID of the conversation this message is part of. This field is blank if not supported.
channel_identity object The identity of the contact in the underlying channel. This field is omitted if not supported. See Channel Identity for details.
Note

The inclusion of the contact_id, conversation_id, and channel_identity fields is dependent on channel integration support. These fields may be omitted if the callback is not associated with a specific channel identity, or if the integration doesn't support them.

Example of Unsupported Callback

Example of an unsupported callback without the contact_id, conversation_id, or channel_identity fields:

Copy
Copied
{
  "app_id": "01EB37HMF1M6SV18ASNS3G135H",
  "accepted_time": "2020-11-17T15:17:05.723864Z",
  "event_time": "2020-11-17T15:17:05.683253Z",
  "project_id": "c36f3a3d-1513-4edd-ae42-11995557ff61",
  "unsupported_callback": {
    "channel": "MESSENGER",
    "payload": "{\"object\":\"page\",\"entry\":[{\"id\":\"107710160841844\",\"time\":1605626225304,\"messaging\":[{\"sender\":{\"id\":\"107710160841844\"},\"recipient\":{\"id\":\"2744085512340733\"},\"timestamp\":1605626225228,\"message\":{\"mid\":\"m_CE0r2yTXOPe1DG_cepCqA9eapH28NipZLg3HuKNf-MA_Edr55tBwvLiTzhrvjZJWQioE4J4gpETQZBTREc7Hdg\",\"is_echo\":true,\"text\":\"Text message from Sinch Conversation API.\",\"app_id\":477442439539985}}]}]}",
    "id": "01FMAVK07YN3SP1B43FP9D1C0S",
    "contact_id": "",
    "conversation_id": "",
    "processing_mode": "CONVERSATION"
  }
}

Example of an unsupported callback with the contact_id, conversation_id, and channel_identity fields:

Copy
Copied
{
  "app_id": "01EB37HMF1M6SV18ASNS3G135H",
  "accepted_time": "2021-11-12T19:53:54.728511Z",
  "event_time": "2021-11-12T19:53:54.542308Z",
  "project_id": "c36f3a3d-1513-4edd-ae42-11995557ff61",
  "unsupported_callback": {
    "channel": "APPLEBC",
    "payload": "{\"interactiveData\": ... }",
    "id": "01FMAVDCKE8TNN021VN7XQ1VG2",
    "contact_id": "01FMAVAPAQTEGDJSFJJWANRX38",
    "conversation_id": "01FMAVAQBTR4C1HJZS05PVTXZ8",
    "channel_identity": {
      "channel": "APPLEBC",
      "identity": "urn:mbid:AQAAX12RO5I+XVVAhq2b0S22ohAOSfSB+aZkybPFk6iOaMdgrXXstADziEHz/f/x8cA=",
      "app_id": "01EB37HMF1M6SV18ASNS3G135H"
    },
    "processing_mode": "CONVERSATION"
  },
  "message_metadata": ""
}
Was this page helpful?
Still have a question? Ask the community.