Message overrides (also referred to as passthrough) are a way to leverage channel-specific features that are not natively supported by the messaging platform API. For example, the Apple Messages for Business channel supports a variety of specific message types such as list picker and time picker which are not supported in any other channels. Message overrides allow the integrator to craft a raw payload to send to the third-party channel's API, and the Zendesk messaging platform will "pass it through", automatically including any required authentication.

Specifying overrides

Post message API

To send a message override using the Post Message API, you must first craft a valid message of any type, and then specify an additional override parameter for the channels you would like to use passthrough. Under each channel name key, the payload field should contain the exact structure expected by the third-party channel's API. If the message is dispatched to a channel for which an override has been supplied, then the override will be used instead of the message's content. For any channel that does not have a specified override, the message's content will be used as usual.

For example, to send an override for whatsapp you would specify override.whatsapp.payload as follows:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "whatsapp": {      "payload": {        "type": "text",        "text": {          "body": "Goodbye"        }      }    }  }}

The above example depicts a simple override example, where the text message will render as "Hello there" on every channel except WhatsApp, where it would instead render the text "Goodbye". Note that all fields under payload in the above example (type, text, body) are WhatsApp-specific fields, exactly as the WhatsApp API would accept them.

Notification API

Overrides can also be specified when using the notification API. Reusing the same whatsapp example from above, the call to the notification API would look like this (note that the notification API is using v1 API naming conventions):

curl https://{subdomain}.zendesk.com/sc/v1.1/apps/{app_id}/notifications \     -X POST \     --user '{key_id}:{secret}' \     -H 'content-type: application/json' \     -d '{        "destination": {          "integrationId": "5e1f438bf99fb467810c0ab9",          "destinationId": "+15145555333"        },        "author": {          "role": "appMaker"        },        "message": {          "type": "text",          "text": "Hello there"        },        "override": {            "whatsapp": {                "payload": {                    "type": "text",                    "text": {                        "body": "Goodbye"                    }                }            }        }      }'

Reserved fields

In order to ensure the message is correctly delivered, Zendesk will automatically set some fields in the payload for you. For example, many messaging channels require the destination user's id to be specified in the request body. To avoid the possibility of an incorrect recipient being supplied, Zendesk will reserve that field for its own usage, and inject the proper value when delivering the message. If you supply any of the reserved fields in your override payload, they will be ignored and replaced according to the table below:

Channel typeReserved keyReserved behaviour
appledestinationIdThe unique identifier of the user. Zendesk will populate this value based on the target user
appleidA unique identifier (in UUID format) for the message. Zendesk will automatically generate and populate this value
applesourceIdThe unique identifier of the calling business. Zendesk will populate this value based on the configured integration
applevSpecifies the version of the message schema to use. Zendesk will automatically set this to 1
instagramrecipientThe identity of the user on Instagram. Zendesk will populate this value based on the target user
linetoThe user's id on LINE. Zendesk will populate this value based on the target user
messengerrecipientThe identity of the user on Facebook. Zendesk will populate this value based on the target user
whatsappmessaging_productZendesk will automatically set this to whatsapp
whatsapptemplate.namespaceThis field is no longer supported in WhatsApp's cloud API. Zendesk will remove this field from the payload
whatsapptoThe username of the user on WhatsApp. Zendesk will populate this value based on the target user

Capabilities check

When sending message overrides to the apple channel, the capabilities of the end-user's device and OS version can affect their ability to receive certain message types. Certain devices or versions offer unique features such as time pickers or list pickers, while others may not have support for rendering these types of messages.

The withCapabilities optional parameter can be used to specify when your override should apply, based on the capabilities of the end-user's device. If the user does not have the desired capabilities, the message's override payload will be ignored, and the content field will be sent to the user instead.

Here is an example of a time picker message with a fallback for devices that do not have proper support for the message type:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Time Picker fallback"  },  "override": {    "apple": {      "withCapabilities": ["TIME"],      "payload": {        "interactiveData": {          "bid": "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.icloud.apps.messages.business.extension",          "data": {            "event": {              "identifier": "reservation-id",              "timeslots": [                {                  "duration": 3600,                  "identifier": "7-am",                  "startTime": "2018-10-24T07:00+0000"                },                {                  "duration": 3600,                  "identifier": "8-am",                  "startTime": "2018-10-24T08:00+0000"                }              ],              "timezoneOffset": 400,              "title": "Available Reservations"            },            "mspVersion": "1.0",            "requestIdentifier": "appointment-selector-1"          },          "receivedMessage": {            "style": "icon",            "title": "Make a reservation"          },          "replyMessage": {            "style": "icon",            "title": "Your reservation"          }        },        "type": "interactive"      }    }  }}

In this example:

  • If the user’s device supports time pickers, they will receive a specific reservation message with selectable time slots.
  • If it doesn't, they will see the fallback message: "Time Picker fallback".

Examples

We've crafted some example override payloads to help you get started. You can refer to the JSON samples below for guidance on how to send various third-party-specific message types.

Apple Messages for Business

A rich link is automatically built for text messages containing a single URL inside. However, you can manually define rich links using overrides. Rich links can contain an image or video preview. For the image, you must provide the image in base64 encoding. You can obtain this through a library or 3rd party website.

Example of a rich link with an image preview:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "apple": {      "payload": {        "body": "https://zendesk.com/",        "type": "richLink",        "richLinkData": {          "url": "https://zendesk.com/",          "title": "Title",          "assets": {            "image": {              "data": "<put base64 encoded image here>",              "mimeType": "image/jpg"            }          }        }      }    }  }}

Example of a rich link with a video preview:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "apple": {      "payload": {        "body": "https://zendesk.com/",        "type": "richLink",        "richLinkData": {          "url": "https://zendesk.com/",          "title": "Title",          "assets": {            "video": {              "url": "https://images.apple.com/media/us/homepod/2018/98e6cc1a_37ec_4e69_b717_9e58c71e1937/films/expand/homepod-expand-tpl-cc-us-20180306_1280x720h.mp4",              "mimeType": "video/mp4"            }          }        }      }    }  }}

Attachments

For some message types, it might be necessary to send attachments. In such cases, you should refer to the Apple documentation for instructions on how to upload those resources to Apple, and pass the object reference to Zendesk using an override.

Example:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "apple": {      "payload": {        "attachments": [          {            "decryption-key": "00260450bb05cd4597a8ae706199f685c0f6fafee4b6c3e1375771c472f4149e29",            "file-size": "10159",            "mime-type": "image/png",            "mmcs-owner": "M39303332653438322d396338342d313165372d613330332d633735336231626666366661.C01USN00",            "mmcs-signature-base64": "AXG58GIo7xWZz7gRXZH2liWuzVah",            "mmcs-url": "https://p97-content.icloud.com",            "name": "icon.png"          }        ],        "body": "goodbye",        "type": "text"      }    }  }}

List picker

A sample list picker payload:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "apple": {      "payload": {        "interactiveData": {          "bid": "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.icloud.apps.messages.business.extension",          "data": {            "images": [],            "listPicker": {              "multipleSelection": true,              "sections": [                {                  "items": [                    {                      "identifier": "taco-appetizer",                      "order": 0,                      "style": "default",                      "subtitle": "Great tacos",                      "title": "Tacos"                    },                    {                      "identifier": "burrito-appetizer",                      "order": 1,                      "style": "default",                      "subtitle": "Good burritos",                      "title": "Burritos"                    }                  ],                  "order": 0,                  "title": "Appetizers"                },                {                  "items": [                    {                      "identifier": "taco-meal",                      "order": 0,                      "style": "default",                      "subtitle": "Great tacos",                      "title": "Tacos"                    },                    {                      "identifier": "burrito-meal",                      "order": 1,                      "style": "default",                      "subtitle": "Good burritos",                      "title": "Burritos"                    }                  ],                  "order": 1,                  "title": "Meals"                }              ]            },            "mspVersion": "1.0",            "requestIdentifier": "food-picker-1"          },          "receivedMessage": {            "style": "small",            "subtitle": "Let's eat!",            "title": "FoodPicker"          },          "replyMessage": {            "style": "large",            "subtitle": "Nutrition",            "title": "Selected food"          }        },        "type": "interactive"      }    }  }}

Time picker

A sample time picker payload:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "apple": {      "payload": {        "interactiveData": {          "bid": "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.icloud.apps.messages.business.extension",          "data": {            "event": {              "identifier": "reservation-id",              "timeslots": [                {                  "duration": 3600,                  "identifier": "7-am",                  "startTime": "2018-10-24T07:00+0000"                },                {                  "duration": 3600,                  "identifier": "8-am",                  "startTime": "2018-10-24T08:00+0000"                }              ],              "timezoneOffset": 400,              "title": "Available Reservations"            },            "mspVersion": "1.0",            "requestIdentifier": "appointment-selector-1"          },          "receivedMessage": {            "style": "icon",            "title": "Make a reservation"          },          "replyMessage": {            "style": "icon",            "title": "Your reservation"          }        },        "type": "interactive"      }    }  }}

Authentication message

A sample authentication message payload:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "apple": {      "payload": {        "type": "interactive",        "v": 1,        "locale": "en_us",        "interactiveData": {          "bid": "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.icloud.apps.messages.business.extension",          "data": {            "version": "2.0",            "requestIdentifier": "1a50ecd2-a0bb-467c-a77c-1932033e8309",            "authenticate": {              "oauth2": {                "responseType": "code",                "scope": ["r_liteprofile"],                "redirectURI": "https://example.com/auth/linkedin/callback"              }            }          },          "receivedMessage": {            "title": "Lets Sign In"          },          "replyMessage": {            "title": "Sign In Completed"          }        }      }    }  }}
Business flow
  • Businesses must supply authentication details about the OAuth provider, including authentication endpoint URLs, client identifier, and business information to their AMB account.
  • Create an integration with an authenticationMessageSecret value. This value will be used by Zendesk to sign the state. The state is a value required by Apple to perform the authentication flow. Securely store this value as it cannot be retrieved by the API.
  • In order to perform the authentication flow, the business needs to expose an endpoint that will be the same route as the redirectURI.
  • After the end-user authenticates, the endpoint created by the business will be called and they will be responsible for validating the state value. This can be done by decoding the state value using the authenticationMessageSecret. The state value is a JWT containing the conversationId. Using the List Participants API, you can query which user is participating in the conversation. You can then merge the user on Apple with an existing authenticated user in Zendesk using the v1 merge users api. This will merge a user with an existing one in your Zendesk Agent Workspace.
  • Redirect the end-user to the following URL scheme after the auth flow is complete in order to close the webview. See Finishing the New Authentication Flow for more details.
// URL Schemamessage-auth://?
Examples:messages-auth://?status=successmessages-auth://?status=failure&error_code=400
  • The authentication webhook event is sent when closing the window with the status as success or failure. Zendesk messaging will publish the webhook via passthrough:apple:interactive containing the status of the authentication.

Custom extension

A sample custom extension (e.g. iMessage App) payload:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "apple": {      "payload": {        "attachments": [          {            "decryption-key": "00260450bb05cd4597a8ae706199f685c0f6fafee4b6c3e1375771c472f4149e29",            "file-size": "10159",            "mime-type": "image/png",            "mmcs-owner": "M39303332653438322d396338342d313165372d613330332d633735336231626666366661.C01USN00",            "mmcs-signature-base64": "AXG58GIo7xWZz7gRXZH2liWuzVah",            "mmcs-url": "https://p97-content.icloud.com",            "name": "icon.png"          }        ],        "interactiveData": {          "URL": "?options=tacos,burritos",          "appId": 34554,          "appName": "Your App Name",          "bid": "com.apple.messages.MSMessageExtensionBalloonPlugin:ABCD5678:com.yourDomain.MessagesExtension",          "receivedMessage": {            "imageSubtitle": "Image Subtitle",            "imageTitle": "Image Title",            "secondarySubtitle": "Trailing Caption",            "subtitle": "Subcaption",            "tertiarySubtitle": "Trailing Subcaption",            "title": "Caption"          },          "useLiveLayout": false        },        "type": "interactive"      }    }  }}

Apple Pay payment requests

Prerequisites for sending ApplePay payment requests include:

  • Apple Pay Merchant ID including:
    • signed certificate (developer.apple.com)
    • a verified Merchant Domain
  • Apple Pay Merchant ID configured on the Messages for Business account (register.apple.com)
  • Valid MerchantSession object, obtained from Apple's API

Override should be constructed according to the Apple specification here.

Responses are sent to the function-specific URL(s) specified in the request (in the interactiveData.data.payment.endpoints object).

App Clips

An App Clip is a small, lightweight version of a full application. It allows users to quickly access and use specific functionalities of an app without needing to download and install the entire application.

Prerequisites for sending App Clips include:

  • A valid URL has App Clips elements on its web page. See details here.

Ensure the version property is a string with at least one decimal precision. Otherwise, the Apple Messages for Business API will return an error.

If the App Clip is not available in the US App Store, add an optional storeRegion link property. See the construct payload API for more details.

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "apple": {      "payload": {        "type": "link",        "link": {          "url": "https://zendesk.com/",          "storeRegion": "US" // optional        },        "version": "1.0"      }    }  }}

LINE

Flex message

A sample flex message payload:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "line": {      "payload": {        "messages": [          {            "type": "flex",            "altText": "This is a Flex Message",            "contents": {              "type": "bubble",              "body": {                "type": "box",                "layout": "horizontal",                "contents": [                  {                    "type": "text",                    "text": "Left"                  },                  {                    "type": "text",                    "text": "Right"                  }                ]              }            }          }        ]      }    }  }}

Facebook Messenger

Receipt

The example below shows how a receipt message can be sent using an override:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "messenger": {      "payload": {        "message": {          "attachment": {            "type": "template",            "payload": {              "template_type": "receipt",              "recipient_name": "John",              "order_number": "111111111111",              "currency": "USD",              "payment_method": "Visa 2345",              "order_url": "http://petersapparel.parseapp.com/order?order_id=123456",              "timestamp": "1428444852",              "address": {                "street_1": "1 Apple Highway",                "street_2": "",                "city": "Mangle city",                "postal_code": "94025",                "state": "CA",                "country": "US"              },              "summary": {                "subtotal": 75.0,                "shipping_cost": 4.95,                "total_tax": 6.19,                "total_cost": 56.14              },              "adjustments": [                {                  "name": "New Customer Discount",                  "amount": 20                },                {                  "name": "$10 Off Coupon",                  "amount": 10                }              ],              "elements": [                {                  "title": "Fall Coat",                  "subtitle": "Soft and Luxurious",                  "quantity": 2,                  "price": 50,                  "currency": "USD",                  "image_url": "https://smooch.io/static_assets/images/shoplifter/double-breasted-coat.jpg"                }              ]            }          }        }      }    }  }}

WhatsApp

Template messages

Here is an example of how to send an approved template message on WhatsApp:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "whatsapp": {      "payload": {        "type": "template",        "template": {          "name": "goodbye_template",          "language": {            "policy": "deterministic",            "code": "en_US"          }        }      }    }  }}
Message template reconstruction

Message template reconstruction enables the conversation history stored by Zendesk to reflect the message as seen by the user, so that all the software connected to the conversation (e.g. Agent Workspace or a bot platform) have the full context of what was sent.

When sending a message template on WhatsApp, you can optionally use message template reconstruction to avoid having to specify your own fallback content field when sending the message. Instead, Zendesk will parse the specified override payload and leverage WhatsApp's Business Management API to connect to your WhatsApp Business Manager and read the contents of the template. The message's content field would then be "reconstructed" from the template details, and will be automatically populated for you.

To leverage message template reconstruction, rather than specifying an override property, you would instead use the content field in conjunction with the schema property. Specify a schema of whatsapp, and replace the message content with your WhatsApp template payload, exactly as it would have appeared under override.whatsapp.payload. Here is an example:

{  "author": {    "type": "business"  },  "schema": "whatsapp",  "content": {    "type": "template",    "template": {      "name": "goodbye_template",      "language": {        "policy": "deterministic",        "code": "en_US"      }    }  }}

Zendesk will then attempt to reconstruct a valid message according to the following sequence, replacing any template variables with the values provided in the API request body:

  1. If the template contains header text, it will be inserted into the text property of the reconstructed message
  2. If the template contains a header image, the type of the message will be set to image, and the image URL will be set as the message's mediaUrl
  3. If the template contains a file in the header, the type of the message will be set to file, and the document URL will be set as the message's mediaUrl
  4. If the template contains body text, it will be inserted into the text property of the reconstructed message, separated from the header text (if it exists) by two newline characters
  5. If the template contains footer text, it will be inserted into the text property of the reconstructed message, separated from preceding text (if it exists) by two newline characters
  6. For each button in the template:
    1. Reply buttons will append an action of type reply to the message's actions array
    2. Phone number buttons will append an action of type link to the message's actions array
    3. URL buttons will append an action of type link to the message's actions array

The reconstructed text of the message will use one of the available translations of the message template; the selected language will be determined according to the following order of precedence:

  1. The language.code specified in the message override payload
  2. The fallback language (hsmFallbackLanguage) configured via the Integration API
  3. The first variation of en_* found

Full reconstruction example:

Given the following template configuration:

Component typeContent
Header image{{some_image}}
BodyYour order {{1}} for a total of {{2}} is confirmed.
FooterThank you for shopping with us!
ButtonThanks!
ButtonNew order

and the following override payload:

{  "author": {    "type": "business"  },  "schema": "whatsapp",  "content": {    "type": "template",    "template": {      "name": "template_example",      "language": {        "policy": "deterministic",        "code": "en_US"      },      "components": [        {          "type": "header",          "parameters": [            {              "type": "image",              "image": {                "link": "https://example.com/image.png"              }            }          ]        },        {          "type": "body",          "parameters": [            {              "type": "text",              "text": "#1234"            },            {              "type": "text",              "text": "$22.47"            }          ]        },        {          "type": "button",          "sub_type": "quick_reply",          "index": "0",          "parameters": [            {              "type": "payload",              "payload": "THANK_YOU"            }          ]        },        {          "type": "button",          "sub_type": "quick_reply",          "index": "1",          "parameters": [            {              "type": "payload",              "payload": "PLACE_NEW_ORDER"            }          ]        }      ]    }  }}

Zendesk would reconstruct the following message content:

{  "author": {    "type": "business"  },  "content": {    "type": "image",    "mediaUrl": "https://example.com/image.png",    "text": "Your order #1234 for a total of $22.47 is confirmed.\n\nThank you for shopping with us!",    "actions": [      {        "type": "reply",        "text": "Thanks!",        "payload": "THANK_YOU"      },      {        "type": "reply",        "text": "New order",        "payload": "PLACE_NEW_ORDER"      }    ]  }}

List Message

List Messages are messages that include a menu of up to 10 options for users to choose from. For example, you can use List Messages for:

  • A restaurant online menu
  • Appointment reservation available times
  • Available online courses

To create a list message, use the interactive object of type list. Options are listed inside an action object. The action object must contain at least one section field. You can have a maximum of ten section fields. Each section field must have at least one rows object that describes the option.

Example:

{  "author": {    "type": "business"  },  "content": {    "type": "text",    "text": "Hello there"  },  "override": {    "whatsapp": {      "payload": {        "type": "interactive",        "interactive": {          "type": "list",          "body": {            "text": "What would you like for dinner?"          },          "action": {            "button": "Make your selection",            "sections": [              {                "title": "Main course",                "rows": [                  {                    "id": "tacos",                    "title": "Tacos",                    "description": "Pork"                  },                  {                    "id": "guacamole",                    "title": "Guacamole",                    "description": "Vegetarian"                  }                ]              },              {                "title": "Drink",                "rows": [                  {                    "id": "tea",                    "title": "Tea",                    "description": "Oolong"                  },                  {                    "id": "soda",                    "title": "Soda",                    "description": "Stewart's Key Lime"                  }                ]              }            ]          }        }      }    }  }}

The user's selection is returned as text, including a quotedMessage reference to the original message sent. Since the override payload is not persisted alongside the message, the WhatsApp syntax used in the initial request is not available.

When the user makes a selection, the resulting conversation:message webhook should look similar to this:

{  "app": {    "id": "5698edbf2a43bd081be982f1"  },  "webhook": {    "id": "5e554d2cac66fb73a3c01869",    "version": "v2"  },  "events": [    {      "id": "0ca7d56ba7b2e081e479fe9e",      "type": "conversation:message",      "createdAt": "2020-02-25T18:06:37.547Z",      "payload": {        "conversation": {          "id": "13f32c6cf7d0d38e6e0eba93",          "type": "personal",          "brandId": "360004166971",          "activeSwitchboardIntegration": {            "id": "62261ff6aa72f900ef123e1d",            "name": "zd-agentWorkspace",            "integrationId": "62261ff41b74b670c3f64c2f",            "integrationType": "zd:agentWorkspace"          }        },        "message": {          "id": "5e55622dac66fb73a3c01877",          "received": "2020-02-25T18:06:37.547Z",          "content": {            "type": "text",            "text": "Tacos - Pork",            "payload": "tacos"          },          "author": {            "type": "user",            "userId": "cbec0073faeda4dfcd21d0f1",            "displayName": "WhatsApp User",            "user": {              "id": "cbec0073faeda4dfcd21d0f1"            }          },          "source": {            "type": "whatsapp",            "integrationId": "5d83a25d9916b64a83ed25e8",            "originalMessageId": "ABGGFDhgAzJ_AhDcs60XVOVFceznj0Re54wL",            "originalMessageTimestamp": "2020-02-25T18:06:37.000Z"          },          "quotedMessage": {            "type": "message",            "message": {              "id": "6143599e72ad5800cb150832",              "received": "2020-02-25T18:05:00.531Z",              "author": {                "avatarUrl": "https://www.gravatar.com/avatar/00000000000000000000000000000000.png?s=200&d=mm",                "type": "business"              },              "content": {                "type": "text",                "text": "Hello there"              },              "source": {                "type": "api:conversations"              }            }          }        }      }    }  ]}