Delivery events can be used to track delivery of business messages as they are transmitted through the Zendesk messaging platform to their ultimate destination. When sending a message, some channels offer a deeper level of delivery confirmation which lets you track the delivery all the way to the user's physical device. We expose a set of delivery event webhook triggers that can be used to track message delivery at each step of the way.

Event types

During the process of delivering a message to a user, three important events can happen:

Webhook TriggerDescription
conversation:message:delivery:channelThe message has been delivered to the channel (for example, WhatsApp). For social channels, this means the channel's API has accepted the message and returned a successful response, but the message may not have been received by the user yet.
conversation:message:delivery:userThe message has been successfully delivered to the user. This event is only applicable on specific channels which support confirmation of delivery to the user's device.
conversation:message:delivery:failureThe message could not be delivered. This can happen if the channel refused the message, if the channel accepted the message and then failed to deliver it to the user, or if the message failed to be processed by the messaging platform.

These three events make up the delivery flow for a message. Depending on the capabilities of the channel, the user delivery confirmation step may not be supported. The delivery to channel webhook payload includes an isFinalEvent flag which signifies whether a follow-up event can be expected or not. A value of isFinalEvent: false will be provided if the channel supports user delivery confirmation, and true otherwise. The high-level delivery flow is described in the following diagram:

Flowchart explaining the steps involved in message delivery

Channel delivery confirmation

The conversation:message:delivery:channel webhook trigger reports the successful handoff of a message from Zendesk to the destination channel. When this event is fired, it means that the message was sent to the appropriate channel API, and the response indicated that the message was accepted. Depending on the capabilities of the destination channel, this event does not guarantee that the message has reached the user, rather it means that the channel has accepted the message and will attempt delivery. See channel support below.

For the Zendesk Web Widget and SDKs, delivery to channel is automatic since the conversation history is used directly as the source of truth. A conversation:message:delivery:channel event will be triggered once for each unique SDK platform the user has connected (web, ios, android, or unity).

The isFinalEvent field is included in this webhook payload. When its value is false it means that a further user delivery confirmation from the channel is expected. A follow-up user delivery confirmation or delivery failure event will indicate whether the channel was able to deliver the message to the user or not. Note that isFinalEvent: false does not strictly guarantee that such a follow-up event will be triggered, it only means that the channel supports delivery to user confirmation. Your code should gracefully handle the case where no follow-up delivery webhook is sent.

{  "app": {    "id": "5fb29b20fee5422428712475"  },  "webhook": {    "id": "5ff5e98b0d0c6d8925594923",    "version": "v2"  },  "events": [    {      "id": "5ff7595eafcaab0a685ff889",      "createdAt": "2021-01-07T18:56:30.666Z",      "type": "conversation:message:delivery:channel",      "payload": {        "conversation": {          "id": "2d4fd3d00715d1e64611e248",          "type": "personal",          "activeSwitchboardIntegration": {            "id": "62261ff6aa72f900ef123e1d",            "name": "zd-agentWorkspace",            "integrationId": "62261ff41b74b670c3f64c2f",            "integrationType": "zd:agentWorkspace"          }        },        "user": {          "id": "71268330a47f5c4b541fce46"        },        "destination": {          "type": "twilio",          "integrationId": "5ff75853b1c3000a6ad4f7f5"        },        "externalMessages": [          {            "id": "SM98cf27c00ada4502aeba7ee784ab6c93"          }        ],        "message": {          "id": "5ff7595eb1c3000a6ad4f7fb"        },        "isFinalEvent": false      }    }  ]}

For channels that do not support delivery confirmation, isFinalEvent will be true indicating that this is the last delivery event that should be expected for a given message.id and destination.type.

{  "app": {    "id": "5fb29b20fee5422428712475"  },  "webhook": {    "id": "5ff5e98b0d0c6d8925594923",    "version": "v2"  },  "events": [    {      "id": "5ff5ea19586a5289264fe738",      "createdAt": "2021-01-06T16:49:29.986Z",      "type": "conversation:message:delivery:channel",      "payload": {        "conversation": {          "id": "6f52af604c607e7ce01e6c52",          "type": "personal",          "activeSwitchboardIntegration": {            "id": "62261ff6aa72f900ef123e1d",            "name": "zd-agentWorkspace",            "integrationId": "62261ff41b74b670c3f64c2f",            "integrationType": "zd:agentWorkspace"          }        },        "user": {          "id": "004ef0350baa219fcdcf121a"        },        "destination": {          "type": "messenger",          "integrationId": "5fb6a33ff3c83e50f3daedce"        },        "externalMessages": [          {            "id": "m_GQGPNusSIpuKm-GrPjr4mFzMF-ZIUc9omxbTJX3GSBDSI63LuOQiJ8xSIj9at9PJ4jufP8lT9spIh-I-kGNQZg"          }        ],        "message": {          "id": "5ff5ea190d0c6d8925594926"        },        "isFinalEvent": true      }    }  ]}

User delivery confirmation

The conversation:message:delivery:user trigger is useful to detect failures where the delivery flow of a channel is more complex. For example, SMS providers might accept a message (triggering a conversation:message:delivery:channel event) but then fail to deliver the message to the user because a carrier rejected the message later on.

conversation:message:delivery:user webhooks indicate that a message successfully reached the user. The webhook should always be preceded by a conversation:message:delivery:channel event with the same message.id and destination.type. No further webhook trigger will be sent as a follow-up to this webhook. This terminal message delivery state is represented by isFinalEvent: true.

Note: User delivery confirmation typically relies on acknowledgement from the user's physical device to mark the message as delivered. There might therefore be a significant time gap between the channel delivery event and the user delivery event. For example, if the user's device is out of network, turned off, or logged out, then it might take several days before the message is ulimately received by the device (if ever). There is also no guarantee that this event will be sent for 100% of messages - for example, WhatsApp will only send delivery to user confirmation within a certain number of days after the message is sent. If the message is received by the user after this time window, the user delivery confirmation is suppressed.

{  "app": {    "id": "5fb29b20fee5422428712475"  },  "webhook": {    "id": "5ff5e98b0d0c6d8925594923",    "version": "v2"  },  "events": [    {      "id": "5ff7595fafcaab0a685ff88b",      "createdAt": "2021-01-07T18:56:31.810Z",      "type": "conversation:message:delivery:user",      "payload": {        "conversation": {          "id": "2d4fd3d00715d1e64611e248",          "type": "personal",          "activeSwitchboardIntegration": {            "id": "62261ff6aa72f900ef123e1d",            "name": "zd-agentWorkspace",            "integrationId": "62261ff41b74b670c3f64c2f",            "integrationType": "zd:agentWorkspace"          }        },        "user": {          "id": "71268330a47f5c4b541fce46"        },        "destination": {          "type": "twilio",          "integrationId": "5ff75853b1c3000a6ad4f7f5"        },        "externalMessages": [          {            "id": "SM98cf27c00ada4502aeba7ee784ab6c93"          }        ],        "message": {          "id": "5ff7595eb1c3000a6ad4f7fb"        },        "isFinalEvent": true      }    }  ]}

Delivery failure

conversation:message:delivery:failure can occur if a message cannot be sent to a channel or if a message cannot reach a user. In both cases, the webhook body will include an error key giving the details of the failure. The underlyingError field of the payload describes the error returned by the third-party channel and usually contains more insights into why the message could not be delivered.

No further webhook trigger will be sent as a follow-up to this webhook. If any retries were attempted internally by the platform, the delivery failure event will only be dispatched after all retry attempts have been exhausted. In order to re-attempt delivery, a new message must be sent. This terminal message delivery state is represented by isFinalEvent: true.

{  "app": {    "id": "5ebee0975ac5304b664a12fa"  },  "webhook": {    "id": "5f4eaef81e3dcc117c7ba48a",    "version": "v2"  },  "events": [    {      "id": "5f74a0d52b5315fc007e798a",      "createdAt": "2020-09-30T15:14:29.834Z",      "type": "conversation:message:delivery:failure",      "payload": {        "conversation": {          "id": "f52b01137aa6c250bc7251fa",          "type": "personal",          "activeSwitchboardIntegration": {            "id": "62261ff6aa72f900ef123e1d",            "name": "zd-agentWorkspace",            "integrationId": "62261ff41b74b670c3f64c2f",            "integrationType": "zd:agentWorkspace"          }        },        "user": {          "id": "26508c10541a4b0ff472e5e2"        },        "destination": {          "type": "whatsapp",          "integrationId": "6dab061987d4d418775a8121"        },        "externalMessages": [          {            "id": "wamid.HBgNNTUxQTk4MDUz5Tg4MRUCABMGTkNERUIzRjREMUKEQTI4NzNBQwA="          }        ],        "message": {          "id": "5f74be6256be263abf0ffd5f"        },        "isFinalEvent": true,        "error": {          "code": "bad_request",          "message": "Message failed to send because either the recipient never messaged the sender number, or more than 24 hours have passed since the recipient last replied to the sender number.",          "underlyingError": {            "errors": [              {                "code": 131047,                "title": "Re-engagement message",                "message": "Re-engagement message",                "error_data": {                  "details": "Message failed to send because more than 24 hours have passed since the customer last replied to this number."                },                "href": "https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/"              }            ]          }        }      }    }  ]}

External message ids

For channels that return their own message ids when accepting messages, the id will be communicated in the externalMessages property of delivery events. Having a reference to the id of a message within Twilio, WhatsApp or other social channels can be useful for debugging and traceability.

The externalMessages array might contain more than one id in cases where a message was split into multiple API calls to conform to the channel's restrictions. For example, some channels such as LINE have a strict limit on the number of characters allowed per message bubble, which is more restrictive than Zendesk's definition of a message. To accommodate these restrictions, the message content may be split into multiple message bubbles during the delivery flow.

When message splitting occurs, the channel delivery and user delivery events will only be dispatched after all messages in the series are confirmed as delivered. A delivery failure event will occur if any of the messages in the series fail to deliver.

Channel support

The table below shows the level of support for delivery events on each channel:

ChannelChannel delivery confirmationUser delivery confirmationExternal message ids
Android SDKYesYesNo
Apple Messages for BusinessYesNoYes
Facebook MessengerYesNoYes
InstagramYesNoYes
iOS SDKYesYesNo
LINEYesNoNo
MessageBirdYesYesYes
TelegramYesNoYes
TwilioYesYesYes
Unity SDKYesYesNo
ViberYesNoYes
Web WidgetYesYesNo
WeChatYesNoYes
WhatsAppYesYesYes
XYesNoNo

Use cases

Tracking delivery status

The delivery status of a message is displayed to agents in the Agent Workspace. When delivery of a message is complete, a double check mark will appear next to the message:

This indicator implies that a delivery event with isFinalEvent: true was received. For channels that support delivery to user confirmation, a single "Sent" checkmark will be displayed until user delivery confirmation is received. For those that do not, the double check mark will be shown once delivery to channel is confirmed.

For messages that failed to deliver, an error indicator will be shown beneath the message bubble:

Message ordering

When calling Post Message multiple times in quick succession for a specific conversation, Zendesk messaging does not guarantee that the messages will be delivered to third-party channels in the same order they were received. Delivery of messages happens in parallel and could involve delays and retries in certain circumstances. This could cause incorrect ordering from the the end user perspective. If ordering is important for your use case, you may want to wait for the conversation:message:delivery:channel event of each message in the sequence before sending the next one. This will ensure that messages are handed off from Zendesk to the third-party channel in the intended order.

Multi-channel users

When a message is sent to a conversation with multiple channels linked, many delivery events can be sent for the same message. The destination property of the delivery event will let you know which channel the event applies to. More specifically, you can receive multiple independent delivery events for a single message if either:

  • The user has connected devices from multiple SDK platforms. In this case, delivery events will be dispatched for each channel (web, ios, android, unity) separately.
  • The preferred channel for the conversation is a third-party channel, and the user is also linked to an SDK channel.
  • The preferred channel is not push capable, and the message was dispatched to a secondary channel after 5 minutes of being unread. See automatic message delivery for details.