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 or business)
  • 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 to false, only the user's id and externalId 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 to true 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 to true.

    {  "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:

  1. If the user has a givenName or surname, use that as the message name (ex: "John Johnson").
  2. 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.
  3. If the user has an externalId, {channel} User {user.externalId} is used as the message name (ex: "iOS User usr_AB23A").
  4. If the message is from a third-party messaging channel, use {channel} User {client.externalId} as the message name (ex: "WhatsApp User 1234567890").
  5. If the message is from an SDK, use {channel} User {userId} as the message name (ex: "Android User 097491b5b2d5388e43f20354").
  6. 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.