Receiving messages
In this guide, we'll explain how to leverage webhooks and the messaging platform APIs to ingest messages and other events in your software.
Webhooks
Webhooks are an industry standard integration pattern based on HTTP. By registering a target URL and a set of desired events, your backend can receive data in real time as users exchange messages with your business. We support a large variety of webhook events that occur in reaction to various actions taken in the system.
The most important webhook event is conversation:message
. This event is dispatched whenever a message is sent in a conversation, regardless of author. Here is an example webhook payload that you can expect to receive in response to a user
message:
{
"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": "Hello world"
},
"author": {
"type": "user",
"userId": "cbec0073faeda4dfcd21d0f1",
"displayName": "Web User cbec0073faeda4dfcd21d0f1",
"user": {
"id": "cbec0073faeda4dfcd21d0f1"
}
},
"source": {
"type": "web",
"integrationId": "5d83a25d9916b64a83ed25e8"
}
}
}
}
]
}
From the example above, we can see many important elements being communicated about the message:
- Important ids such as the user id and conversation id
- The author of the message (author types are either
user
orbusiness
) - The message content
- The message's
source
(where it came from) - The
activeSwitchboardIntegration
for the conversation. This indicates which integration is expected to reply to the user.
Creating webhooks
Webhooks will always belong to an integration of some kind, which serves as the container for the webhook. The quickest way to get started with webhooks is through the Admin Center. See Creating conversations integrations in Admin Center in Zendesk help.
Depending on the type of software you are developing, you might want to manage webhooks programmatically instead:
-
To register webhooks in your own Zendesk account, you can use the Create Integration API to create an integration of type
custom
. Supply your webhook details as part of creating the integration.const apiInstance = new SunshineConversationsClient.IntegrationsApi()
const data = new SunshineConversationsClient.Integration()
data.type = "custom"
data.webhooks = [
{
target: "http://example.com/callback",
triggers: ["conversation:message"]
}
]
await apiInstance.createIntegration("{appId}", data)
-
If you are developing software that will be integrated in someone else's Zendesk account using OAuth, then an integration will be automatically provisioned as part of the OAuth flow. Use the Create Webhook API with the special
me
alias to add the webhook to the OAuth integration. Integrators may configure up to 3 such webhooks per account.const apiInstance = new SunshineConversationsClient.WebhooksApi()
const data = new SunshineConversationsClient.WebhookCreateBody()
data.target = "http://example.com/callback"
data.triggers = ["conversation:message"]
await apiInstance.createWebhook("{appId}", "me", data)
Webhook settings
When creating your webhook, there are two configuration options you might want to consider enabling that will affect the contents of the payloads you receive:
-
includeFullUser
controls whether the user's full profile information should be included in the payload or not. When set tofalse
, only the user'sid
andexternalId
will be communicated:{
"author": {
"type": "user",
"userId": "cbec0073faeda4dfcd21d0f1",
"displayName": "Web User cbec0073faeda4dfcd21d0f1",
"user": {
"id": "cbec0073faeda4dfcd21d0f1"
}
}
}
If you need information from the user's profile (such as their
givenName
or preferred language) set this totrue
instead:{
"author": {
"userId": "cbec0073faeda4dfcd21d0f1",
"displayName": "Web User cbec0073faeda4dfcd21d0f1",
"type": "user",
"user": {
"id": "cbec0073faeda4dfcd21d0f1",
"profile": {
"locale": "en-US",
"localeOrigin": "apiRequest"
},
"signedUpAt": "2020-02-25T18:06:37.547Z",
"metadata": {},
"identities": []
}
}
}
-
includeFullSource
controls whether the payload should include the client or device that generated the event. If you need access to additional information about the source of the message such as the user's IP address or their phone number on WhatsApp, set this totrue
.{
"source": {
"integrationId": "6243aacc9ac0d600f38d6628",
"type": "web",
"device": {
"id": "67c5cb567c6f14b8936dad18",
"guid": "f5779af912b144c7844a1111d687e5c8",
"clientId": "67c5cb567c6f14b8936dad13",
"integrationId": "6243aacc9ac0d600f38d6628",
"type": "web",
"status": "active",
"info": {
"vendor": "zendesk",
"sdkVersion": "0.1",
"URL": "example.com",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
"referrer": "https://example.com",
"browserLanguage": "en-US",
"currentUrl": "https://example.com/example/page",
"currentTitle": "My Web Page",
"ipAddress": "0.0.0.0",
"country": "United States",
"countryCode": "US",
"state": "California",
"stateCode": "CA",
"city": "San Francisco"
},
"lastSeen": "2020-02-25T18:06:37.547Z"
}
}
}
Event filtering criteria
Integrations which are not part of the app's switchboard receive all events for which they are subscribed. This is the expected configuration for some Zendesk systems such as Zendesk QA, which ingests all messages but is never intended to be put in control of replying to a conversation. Zendesk QA therefore will not have any corresponding switchboard integration. This is also the default behaviour for a newly created integration of type custom
- the integration must be explicitly added to the switchboard after it is created (if desired). If your integration will only be listening to events but does not need to reply, you should leave it out of the switchboard.
For integrations that are part of the switchboard, the deliverStandbyEvents
property controls whether events should be filtered out when not in control of a conversation. Most integrators prefer not to receive messages from conversations they are not expected to reply to. This is also the expected configuration for some Zendesk systems such as AI Agents. When using deliverStandbyEvents: false
, event delivery will be suppressed for any integration that does not match the conversation's activeSwitchboardIntegration
property.
However, depending on the use case, you might still want to be notified of messages in conversations that are not currently in your control. For example, if you need to keep a cache of recent messages in case control is escalated. Integrations with deliverStandbyEvents: true
will receive all events, regardless of switchboard state, similar to how integrations behave when they are not in the switchboard at all.
Note: When using deliverStandbyEvents: true
, it's still important that your system only replies to conversations for which it is in control. Otherwise, multiple integrations might be replying to the conversation at the same time, causing confusion for the user. Your software should be coded to inspect the conversation's activeSwitchboardIntegration
property to know when to reply, and when to leave replying up to other integrations.
Retrieving conversation history
To fetch the history of a conversation, use the List Messages API. This returns the most recent 100 messages of the conversation. Cursor pagination can be used to page further back in the history, if desired.
const apiInstance = new SunshineConversationsClient.MessagesApi()
const opts = {} // Can contain parameters for applying cursor pagination.
await apiInstance.listMessages("{appId}", "{conversationId}", opts)
Message author name
When you receive a message from a user, it will always have a displayName
associated with it. The display name will be populated according to the following priority list:
- If the user has a
givenName
orsurname
, use that as the message name (ex: "John Johnson"). - If the useAnimalNames setting is set to
true
, a random animal name will be generated (ex: "Optimistic Ferret"). This name will then be reused for all future messages from the same user. - If the user has an
externalId
,{channel} User {user.externalId}
is used as the message name (ex: "iOS User usr_AB23A"). - If the message is from a third-party messaging channel, use
{channel} User {client.externalId}
as the message name (ex: "WhatsApp User 1234567890"). - If the message is from an SDK, use
{channel} User {userId}
as the message name (ex: "Android User 097491b5b2d5388e43f20354"). - Otherwise,
User {userId}
will be used as the message name (ex: "User 097491b5b2d5388e43f20354").
Next steps
- Reply to messages you receive from users.
- Read the full reference on webhooks to learn more about the various events you can subscribe to.