The switchboard allows you to programmatically route a user's conversation through various messaging integrations (bot or agent systems), similarly to how an operator patches phone calls via a switchboard. By connecting various first- and third-party integrations in the switchboard, you can customize the escalation path for conversations in your account to suit your needs. For example, you might want conversations over WhatsApp to immediately create a ticket in Zendesk Support, but have users that open the Web Widget on your website interact with an AI agent first.

Switchboards and switchboard integrations

The switchboard is a container for a set of switchboard integrations, which each handle part of a user's journey as their conversation progresses. By default, your account will contain switchboard integrations representing AI agents and the Zendesk Agent Workspace. As you enable additional features such as AI agents advanced or third-party messaging bots, new switchboard integrations will be added.

The switchboard establishes an escalation flow that your messaging users will follow. For each conversation in your account, switchboard integrations will either be in an active, pending, or standby state with respect to the conversation. A conversation can only have one active switchboard integration at a time. Typically, all other integrations will be on standby for that conversation.

The active switchboard integration for a conversation is the system that is expected to respond to user messages and events for that conversation. Each relevant webhook event will contain information specifying which switchboard integration is currently active for the conversation.

The diagram below shows an example switchboard composed of two switchboard integrations: an AI agent, and the Agent Workspace. For the example conversation, the AI agent is currently in control of the conversation and is considered as active. The Agent Workspace integration is on standby awaiting escalation of the conversation:

Switchboard with switchboard integrations

Switchboard integrations

Each business system that interacts with the messaging platform in some way is represented as an integration within Zendesk messaging. A switchboard integration is used to model an integration's membership within the switchboard, as well as their presence and status in each ongoing conversation. The following types of integrations can participate in the switchboard:

  • Zendesk services (for example, Agent Workspace and AI agents)
  • OAuth integrations (for example, third-party bot partners)
  • Custom integrations (webhook-based integrations built by your developers)

The diagram below depicts the relationship between the switchboard, its switchboard integrations, the underlying integrations, and the business systems that are represented by each integration. The example switchboard has N switchboard integrations each representing integrations of different types:

Comparing integrations and their associated switchboard integrations

Event delivery

As discussed in receiving messages, an integration's presence in the switchboard can affect its ability to receive messages and other events. Typically, integrators prefer not to receive messages from conversations they are not expected to reply to. The switchboard makes this possible.

For a given conversation, the active and pending switchboard integrations will receive all events and activities within that conversation. However, any switchboard integrations that are on standby for the conversation will not receive events by default. If standby events are desired, this can be enabled using the deliverStandbyEvents property when creating a switchboard integration. This allows an integration to keep track of conversation events so that they have context on hand-off if and when they are switched to active status for a given conversation.

The following list of webhook triggers are affected by the status of a switchboard integration with respect to a conversation. When deliverStandbyEvents is set to false for a switchboard integration, these events will be suppressed for conversations in which the integration is on standby:

  • conversation:create
  • conversation:join
  • conversation:leave
  • conversation:message:delivery:channel
  • conversation:message:delivery:failure
  • conversation:message:delivery:user
  • conversation:message
  • conversation:postback
  • conversation:read
  • conversation:referral
  • conversation:remove
  • conversation:typing
  • notification:delivery:channel (v1.1 API only)
  • notification:delivery:failure (v1.1 API only)
  • notification:delivery:user (v1.1 API only)
  • passthrough:apple:extension
  • passthrough:apple:interactive

Events for any triggers not mentioned above will be delivered to all integrations regardless of switchboard state.

Conversational control model

As explained above, the switchboard is responsible for determining which system is in charge of each conversation in your account. The currently active switchboard integration for a conversation is stored in the activeSwitchboardIntegration property of the conversation. The switchboard state of the conversation is communicated in webhook payloads, and can be also retrieved at any time using the Get Conversation API.

Here is an example conversation object showing the activeSwitchboardIntegration field:

{  "id": "67179a3130a15fd5aec4d91f",  "type": "personal",  "isDefault": true,  "businessLastRead": "2025-03-28T13:19:01.381Z",  "lastUpdatedAt": "2025-03-28T13:19:01.381Z",  "createdAt": "2024-10-22T12:27:29.481Z",  "activeSwitchboardIntegration": {    "id": "67dc32a58d289d63bfeb6346",    "name": "zd-agentWorkspace",    "integrationId": "66bb767f61d6028b2aa89ec6",    "integrationType": "zd:agentWorkspace"  }}

This section describes how the active integration for a conversation is determined, and how it can be manipulated to perform handoff of the conversation between systems.

Default integration assignment

When a conversation is first created, or the user returns to a conversation in which control had previously been released, an active switchboard integration will need to be selected for the conversation. The decision of which switchboard integration to assign is based on two criteria:

  1. The switchboard has a defaultSwitchboardIntegrationId property referencing a specific switchboard integration that will be put in control of all conversations by default.
  2. Each of your messaging channel integrations have a defaultResponder property which may override the switchboard's global default responder if customized to do so.

Depending on how your switchboard and channels are configured, and the messaging channel of the end user, one of the above criteria will apply. For example, you might want conversations over WhatsApp to immediately create a ticket in Zendesk Support, but have users that open the Web Widget on your website interact with an AI agent first. In this scenario, the switchboard's global default responder would be set to your AI agent, and your WhatsApp channel's defaultResponder would have an override set to the Zendesk Agent Workspace.

Control transfer

In addition to controlling the default responder for your account, the switchboard also models the escalation paths between the various connected integrations. The nextSwitchboardIntegrationId property of a switchboard integration dictates where conversations should be directed in the case of an escalation. For example, your AI agent might need to escalate the conversation to Zendesk Support if the user is unable to self-solve their problem.

When a switchboard integration decides that control of a conversation needs to be transferred to another system, typically they will do so using the next keyword. This will pass control of the conversation to whatever the configured nextSwitchboardIntegrationId happens to be. In this way, an individual switchboard integration does not need to be aware of the state of the switchboard in order to perform an escalation. The proper escalation flows will have already been configured by an admin ahead of time.

On the other hand, control of a conversation can also be passed to a specific switchboard integration if desired. In addition to the next keyword, switchboard integrations may also be referenced directly by their name or by id when transferring control.

The diagram below depicts the expected flow of a conversation as it is transferred between an AI agent and the Agent Workspace using the passControl and releaseControl operations:

Switchboard control flow including passControl and releaseControl

Pass control

In the vast majority of cases, the passControl operation should be used to escalate control of a conversation from one integration to another. By invoking the Pass Control API, a switchboard integration can escalate the conversation to the next system in the hierarchy:

const apiInstance = new SunshineConversationsClient.SwitchboardActionsApi()const data = new SunshineConversationsClient.PassControlBody()
data.switchboardIntegration = "next"
await apiInstance.passControl("{app_id}", "{conversation_id}", data)

The pass control action will immediately mark the target integration as active for the conversation. The switchboard integration receiving control is expected to react to the transfer immediately by handling the resulting switchboard:passControl webhook event. For example, passing control to the Zendesk Agent Workspace will immediately make a ticket eligible for assignment to an agent.

Below is an example switchboard:passControl webhook payload that integrations can expect to receive when control of a conversation is passed. Note that all connected integrations will receive this event, not just the one that was placed in control. The payload includes details about which integration is currently active for the conversation. It may optionally include any metadata that was supplied as part of the operation:

{  "app": {    "id": "5ebee0975ac5304b664a12fa"  },  "webhook": {    "id": "5f4eaef81e3dcc117c7ba48a",    "version": "v2"  },  "events": [    {      "id": "5f74a0d52b5315fc007e798a",      "createdAt": "2020-09-30T15:14:29.834Z",      "type": "switchboard:passControl",      "payload": {        "conversation": {          "id": "f52b01137aa6c250bc7251fa",          "type": "personal",          "activeSwitchboardIntegration": {            "id": "67dc32a58d289d63bfeb6346",            "name": "zd-agentWorkspace",            "integrationId": "66bb767f61d6028b2aa89ec6",            "integrationType": "zd:agentWorkspace"          },          "metadata": {            "foo": "bar"          }        }      }    }  ]}

Release control

The releaseControl action clears any existing active or pending switchboard integrations for a conversation. Typically this is used when a system in the escalation hierarchy considers the conversation to be resolved and there is no further action required. For example, when an agent resolves the user's problem and the support ticket is closed, control of the conversation will be released from the Agent Workspace as a consequence.

If the user then returns to the same conversation after control has been released (potentially days or weeks later), the conversation will once again be assigned to the default switchboard integration, and the escalation flow restarts from the beginning.

Control of a conversation can be released by invoking the Release Control API:

const apiInstance = new SunshineConversationsClient.SwitchboardActionsApi()
await apiInstance.releaseControl("{app_id}", "{conversation_id}")

Note that the use of releaseControl differs from the case of using passControl to hand off back to the default integration. When using passControl, the assigned switchboard integration is determined based on the switchboard configuration when the interaction concludes. That means that if the switchboard is reconfigured to have a new default responder before the user returns, the conversation will remain "stuck" assigned to the previous default. When using releaseControl, the assigned switchboard integration is not recomputed until the user later returns to the conversation and starts a new interaction. Any changes to the switchboard configuration that may have happened in the meantime will be properly accounted for.

Offer and accept control

If an immediate control transfer is not desired, then the offer/accept control paradigm can be used for a more graceful transition between systems. Different systems might also benefit from being able to share control of a conversation, instead of having abrupt transfers of control as the only option. For this use case, we use two new actions: offerControl and acceptControl.

In this scenario, instead of abruptly passing control of the conversation and disconnecting itself, the integration can instead offer control of the conversation to next integration, and remain active for the conversation until the offer is accepted. When control is offered, the target integration becomes pending for the conversation. While the target integration remains in a pending state, control of the conversation is shared between the two integrations, and both integrations will receive events even if their deliverStandbyEvents setting is false. When the target integration is ready to take exclusive control of the conversation, it can issue an acceptControl action, which completes the control transfer, marking the target integration as active, while marking the original integration as standby.

The Offer Control and Accept Control APIs are used to accomplish this variation of switchboard control transfer.

Metadata

When transferring control between systems, sometimes it can be valuable to convey additional metadata about what happened in the conversation up to that point. The passControl operation accepts a metadata parameter for just this purpose. Zendesk systems support a variety of pre-defined metadata keys that can be used to customize what happens when control of a conversation is passed.

Metadata accepted by the Agent Workspace

When passing control to Zendesk's Agent Workspace, you can include metadata to populate ticket fields on the resulting Zendesk ticket. All keys are optional, and do not need to be provided in order for a ticket to be created. Here is an example passControl with included metadata:

{  "switchboardIntegration": "zd-agentWorkspace",  "metadata": {    "dataCapture.ticketField.54321": "Blue",    "dataCapture.ticketField.98112": "981235",    "dataCapture.systemField.requester.name": "Frodo",    "first_message_id": "603012d7e0a3f9000c879b67",    "origin_source_type": "twilio"  }}
Standard ticket fields

Zendesk standard ticket fields can be populated using the following key pattern in metadata:

"dataCapture.systemField.<name_of_system_field>": "value"

The following subset of fields are supported:

  • priority
  • organization_id
  • group_id
  • assignee_id
  • tags
  • brand_id
  • requester.name
  • requester.email
Custom ticket fields

Zendesk custom ticket fields can be populated using the following key pattern in metadata:

"dataCapture.ticketField.<custom_ticket_field_id>": "value"
First message id

When a conversation is escalated to an agent, the recent history of the conversation will be automatically injected into the ticket to provide context for the agent. To control where the history injection starts, the first_message_id metadata field can be used. The id of a message in the conversation history can be specified as the starting point from which history should be loaded. Typically this will be used to specify the first message in the bot flow which resulted in the escalation.

Ticket source type

When a ticket is created, the source type is usually inferred from the context of the conversation. If you need to override the default channel detection logic, you can specify an origin_source_type in the metadata object.

This is the list of allowed origin_source_type values and the resulting via.channel of the created messaging ticket:

origin source typevia.channel
android, ios, web, sdkNATIVE MESSAGING
appleAPPLE BUSINESS CHAT
googlercsGOOGLE RCS
instagramINSTAGRAM DM
kakaoKAKAOTALK
lineLINE
mailgunMAILGUN
messagebirdMESSAGEBIRD SMS
messengerSUNSHINE CONVERSATIONS FACEBOOK MESSENGER
slackconnectBUSINESS MESSAGING SLACK CONNECT
telegramTELEGRAM
twilioTWILIO SMS
twitterSUNSHINE CONVERSATIONS TWITTER DM
viberVIBER
wechatWECHAT
whatsappWHATSAPP
default (no value provided)SUNSHINE CONVERSATIONS API

Metadata accepted by AI agents

Some use cases require an AI agent to be part of a conversation, but not as the default responder. In this scenario, the AI agent is part of your switchboard configuration, but may only be involved based on specific business logic. For example, suppose you have a custom integration that determines the identity of the user. Based on who the user is, you may want to direct them to various bots, including the Zendesk AI agent. The execute_flow metadata allows you to pass control to your AI agent and ensure the proper greeting or answer gets executed as a result.

The following key pattern can be used to control the flow execution of your AI agent:

"zen:answerbot:execute_flow": "channel=<integration_id>"

The integration id supplied should be taken from the messaging channel the user is reaching out from. For example, in the conversation:create webhook event, the integration id of the user's channel can be retrieved from events.payload.source.integrationId.

Here is an example passControl body with included metadata:

{  "switchboardIntegration": "zd-answerBot",  "metadata": {    "zen:answerbot:execute_flow": "channel=6086368afhfb5541d229n898"  }}

Configuring the switchboard

Accounts with messaging enabled will have their switchboard automatically created along with a few relevant switchboard integrations. You can find the switchboard id for your account using the List Switchboards API:

const apiInstance = new SunshineConversationsClient.SwitchboardsApi()
await apiInstance.listSwitchboards("{app_id}")

Using this id, you can list the switchboard integrations using List Switchboard Integrations:

const apiInstance = new SunshineConversationsClient.SwitchboardIntegrationsApi()
await apiInstance.listSwitchboardIntegrations("{app_id}", "{switchboard_id}")

Basic switchboard configuration

For a newly created account, or an account that has just set up messaging for the first time, the configuration should look something like this:

Switchboard

{  "switchboards": [    {      "id": "62261ff651249100f09e85aa",      "enabled": true,      "defaultSwitchboardIntegrationId": "6243aaba5d474e00f3c6b10f" // zd:answerBot    }  ]}

Switchboard Integrations

{  "switchboardIntegrations": [    {      "id": "67dc32a58d289d63bfeb6346",      "name": "zd-agentWorkspace",      "integrationId": "66bb767f61d6028b2aa89ec6",      "integrationType": "zd:agentWorkspace",      "deliverStandbyEvents": false,      "nextSwitchboardIntegrationId": "6243aaba5d474e00f3c6b10f" // zd:answerBot    },    {      "id": "6243aaba5d474e00f3c6b10f",      "name": "zd-answerBot",      "integrationId": "62261ff51b74b670c3f6beee",      "integrationType": "zd:answerBot",      "deliverStandbyEvents": false,      "nextSwitchboardIntegrationId": "67dc32a58d289d63bfeb6346" // zd:agentWorkspace    }  ]}

The switchboard should have two switchboard integrations. The global default responder is zd:answerBot, and it escalates control to zd:agentWorkspace as next.

The table below summarizes the integrationTypes you can expect to find representing Zendesk systems in the switchboard:

integrationTypeProduct
zd:agentWorkspaceZendesk Support / Agent Workspace
zd:answerBotAI agents - Essential
ultimateAI agents - Advanced

Changing the default responder

Typically, the default responder for your switchboard will be automatically set while configuring your channels and integrations in Admin Center. However, they can also be managed using the API if programmatic customization is required. To configure the global default for your switchboard, you can use the Update Switchboard API to set the defaultSwitchboardIntegrationId parameter:

const apiInstance = new SunshineConversationsClient.SwitchboardsApi()const data = new SunshineConversationsClient.SwitchboardUpdateBody()
data.defaultSwitchboardIntegrationId = "{switchboard_integration_id}"
await apiInstance.updateSwitchboard("{app_id}", "{switchboard_id}", data)

To change the default responder on a per-channel basis, use the Update Integration API and supply a defaultResponderId property. You can also pass null to revert the channel to using the global default configured for your switchboard:

const apiInstance = new SunshineConversationsClient.IntegrationsApi()const data = new SunshineConversationsClient.IntegrationUpdate()
data.defaultResponderId = "{switchboard_integration_id}"
// or: data.defaultResponderId = null
await apiInstance.updateIntegration("{app_id}", "{integration_id}", data)

Setting nextSwitchboardIntegrationId

Similar to default responders, the next(s) of your switchboard integrations are typically configured for you automatically. If you need more control over the escalation flow between your switchboard integrations, you can use the Update Switchboard Integration API to configure the nextSwitchboardIntegrationId property for each of your switchboard integrations:

const apiInstance = new SunshineConversationsClient.SwitchboardIntegrationsApi()const data = new SunshineConversationsClient.SwitchboardIntegrationUpdateBody()
data.nextSwitchboardIntegrationId = "{switchboard_integration_id}"
await apiInstance.updateSwitchboardIntegration(  "{app_id}",  "{switchboard_id}",  "{switchboard_integration_id}",  data)

Keep in mind that the value of this parameter only affects integrations that pass control using the next keyword. If an integration passes control directly using a switchboard integration's name or id, then this parameter does not apply.

Adding a switchboard integration

When installing a third-party bot from the Zendesk Marketplace, a switchboard integration for the bot should be automatically created as a result. However, if you are building a custom bot using conversations integrations, then you might need to add it to the switchboard manually. To add your custom integration to the switchboard, use the Create Switchboard Integration API and reference the integration by its id:

const apiInstance = new SunshineConversationsClient.SwitchboardIntegrationsApi()const data = new SunshineConversationsClient.SwitchboardIntegrationCreateBody()
data.name = "my-custom-bot"data.integrationId = "{custom_integration_id}"data.deliverStandbyEvents = falsedata.nextSwitchboardIntegrationId = "{switchboard_integration_id}"
await apiInstance.createSwitchboardIntegration(  "{app_id}",  "{switchboard_id}",  data)