How to receive events from the bot
Receive events from the bot
The bot will send events to the custom CRM through the webhooks that have been configured in the bot Custom CRM settings:
The Chat webhook will receive events related to conversations, like messages or escalation related, while the actions webhook will execute actions that have been configured in the bot.
Chat webhook
The chat webhook will receive events related to conversations, like messages or escalation related. The events that will be received are:
- sendMessage - A message from the bot to the customer. It could be a simple text message, a carousel of cards or a list of buttons.
- escalate - An escalation request from the bot to the CRM.
- isTeamOnline - When the bot needs to make decisions that are dependent on the availability of human agents.
- widgetMessage - For Widget Bots only. Represents a message from the customer to the Agent in an escalated conversation.
- widgetEscalate - For Widget Bots only. An escalation request from a widget customer to the CRM.
- widgetEndSession - For Widget Bots only. Request to end an escalated session.
In our template project, we have defined this webhook in the url /converse-webhook
,
but the implementation in a custom CRM can be different. Here is an example implementation using Typescript:
/** * This method processes the Converse Webhook. Receives a DTO of type ConverseWebhookDto with the event details * * It will process the request differently depending on the eventType field of the payload. * * @param req * @param res * @param next */ public processEvent = async (req: Request, res: Response, next: NextFunction): Promise<void> => { const requestBody: ConverseWebhookDto = req.body;
try { this.converseWebhookService.processConverseWebhookEvent(requestBody); res.status(200).send(); } catch (error: any) { next(error); } };}
sendMessage event
This will be the most common event that will be sent to the custom CRM. It represents a message from the bot to the customer. It could be a simple text message, a carousel of cards or a list of buttons. The event should be acknowledged and processed ASYNCHRONOUSLY.
In our template project, in the ConverseWebhookService
is where we can process this type of event.
From here, its up to the Custom CRM to execute logic on the message that it has received from the bot.
It can directly forward it to the customer or process it before if needed.
/** * This method processes the Converse Webhook event. * @param converseWebhookDto */ public processConverseWebhookEvent(converseWebhookDto: ConverseWebhookDto): void { switch (converseWebhookDto.data.eventType) { case ConverseWebhookEventTypes.SEND_MESSAGE: /** * This event represents a message sent from the bot. * It can represent a text message, a list of buttons or a carousel. * * The payload of this event is represented in the BotMessageEvent class. * * The request needs to be acknowledged and processed ASYNCHRONOUSLY. */ logger.info( `Received ${ConverseWebhookEventTypes.SEND_MESSAGE} event: \n ${JSON.stringify(converseWebhookDto)}` ); break; default: break; } }}
Text message
The text message structure:
Field | Type | Required | Description |
---|---|---|---|
botId | string | true | The ID of the bot that is sending the event. |
data | Object | true | Object containing the payload of the event. Depending on the event type, it will contain different values |
Field | Type | Description |
---|---|---|
eventType | string Set to sendMessage | Event of type sendMessage. |
platformConversationId | string | The ID of the conversation |
conversationId | string | ULTIMATE internal ID (Can be ignored) |
type | string Set to text | Simple text message type. |
replyId | string | The ID of the reply in Ultimate system that triggered this text message. |
text | string | The text of the message. |
predictedIntents | PredictedIntent[] | Predicted intents for visitor message. Each object of type PredictedIntent in the array needs to contain the following fields:value string - the ID of the intent in Ultimate system name string - name of the intentconfidence number - confidence in the intent |
Example in JSON format:
{ "botId": "BOT_ID", "data": { "eventType": "sendMessage", "platformConversationId": "13427e90-f76a-47c2-a26d-ea0b4f1836c5", "conversationId": "CONVERSATION_ID", "type": "text", "replyId": "REPLY_ID", "buttons": [], "text": "Hello, this is a bot text message", "carouselCards": [], "predictedIntents": [{"value": "1234", "name": "intent name", "confidence": 1}] }}
List of buttons message
The list of buttons message structure:
Field | Type | Required | Description |
---|---|---|---|
botId | string | true | The ID of the bot that is sending the event. |
data | Object | true | Object containing the payload of the event. Depending on the event type, it will contain different values |
Field | Type | Description |
---|---|---|
eventType | string Set to sendMessage | Event of type sendMessage. |
platformConversationId | string | The ID of the conversation |
conversationId | string | ULTIMATE internal ID (can be ignored) |
type | string Set to text | Simple text message type. |
replyId | string | The ID of the reply in Ultimate system that triggered this text message. |
buttons | Button[] | The buttons array will be empty for a simple text message. Each object of type Button in the array needs to contain the following fields:type string - set to the value button text string - text of the button |
text | string | The text of the message with buttons. Not mandatory to exist. |
predictedIntents | PredictedIntent[] | Predicted intents for visitor message. Each object of type PredictedIntent in the array needs to contain the following fields:value string - the ID of the intent in Ultimate system name string - name of the intentconfidence number - confidence in the intent |
Example in JSON format:
{ "botId": "BOT_ID", "data": { "eventType": "sendMessage", "platformConversationId": "13427e90-f76a-47c2-a26d-ea0b4f1836c5", "conversationId": "CONVERSATION_ID", "type": "text", "replyId": "REPLY_ID", "buttons": [ { "type": "button", "text": "YES" }, { "type": "button", "text": "NO" } ], "text": "its a bot text message with 2 buttons", "carouselCards": [], "predictedIntents": [{"value": "1234", "name": "intent name", "confidence": 1}] }}
Carousel message
The carousel message structure:
Field | Type | Required | Description |
---|---|---|---|
botId | string | true | The ID of the bot that is sending the event. |
data | Object | true | Object containing the payload of the event. Depending on the event type, it will contain different values |
Field | Type | Description |
---|---|---|
eventType | string Set to sendMessage | Event of type sendMessage. |
platformConversationId | string | The ID of the conversation |
conversationId | string | ULTIMATE internal ID (can be ignored) |
type | string Set to carousel | Carousel message type. |
replyId | string | The ID of the reply in Ultimate system that triggered this text message. |
text | string | The text of the message with buttons. Not mandatory to exist. |
carouselCards | CarouselCard[] | The carousel cards array will contain a list of cards. See table below with the fields of CarouselCards |
predictedIntents | PredictedIntent[] | Predicted intents for visitor message. Each object of type PredictedIntent in the array needs to contain the following fields:value string - the intent idname string - name of the intentconfidence number - confidence in the intent |
Each object of type CarouselCard
in the array needs to contain the following fields:
Field | Type | Description |
---|---|---|
title | string | Title of the carousel. |
description | string | Event of type sendMessage |
imageUrl | string | Url of the card image. |
buttons | Button[] | Each object of type Button in the array needs to contain the following fields:type string - set to the value button text string - text of the button |
Example in JSON format:
{ "botId": "BOT_ID", "data": { "eventType": "sendMessage", "platformConversationId": "13427e90-f76a-47c2-a26d-ea0b4f1836c5", "conversationId": "CONVERSATION_ID", "type": "carousel", "replyId": "REPLY_ID", "buttons": [], "text": "", "carouselCards": [ { "title": "card 1", "description": "card 1 description", "imageUrl": "URL", "buttons": [ { "text": "button 1", "type": "button" }, { "text": "button 2", "type": "button" } ] }, { "title": "card 2", "description": "card 2 description", "imageUrl": "URL", "buttons": [ { "text": "button 1", "type": "button" }, { "text": "button 2", "type": "button" } ] } ], "predictedIntents": [{"value": "1234", "name": "intent name", "confidence": 1}] }}
escalate event
This event will happen when the bot triggers an escalation to agent. When this event is received, the bot will stop sending messages to the customer, and it will be the custom CRMs responsibility to manage the escalated conversation between the agent and the customer.
The ConverseWebhookService
in our template project is where we process this type of event.
From here, it’s up to the custom CRM to implement its logic internally,
like checking agent availability, adding the customer to a queue or any other logic that needs to be implemented.
/** * This method processes the Converse Webhook event. * @param converseWebhookDto */ public processConverseWebhookEvent(converseWebhookDto: ConverseWebhookDto): void { switch (converseWebhookDto.data.eventType) { case ConverseWebhookEventTypes.ESCALATE: /** * This event represents an escalation request from the bot. * * The payload of this event is represented in the BotEscalationEvent class. * * The request will be processed SYNCHRONOUSLY and respond if the escalation was successful (200) or not (4xx-5xx). */ logger.info( `Received ${ConverseWebhookEventTypes.ESCALATE} event: \n ${JSON.stringify(converseWebhookDto)}` ); break; default: break; } }}
The escalate message structure:
Field | Type | Required | Description |
---|---|---|---|
botId | string | true | The ID of the bot that is sending the event. |
data | Object | true | Object containing the payload of the event. Depending on the event type, it will contain different values |
Field | Type | Description |
---|---|---|
eventType | string Set to escalate | Event of type escalate. |
platformConversationId | string | The ID of the conversation |
conversationId | string | ULTIMATE internal ID (can be ignored) |
escalateTo? | string | The ID of the escalation team within the CRM system (OPTIONAL) |
Example in JSON format:
{ "botId": "BOT_ID", "data": { "eventType": "escalate", "platformConversationId": "13427e90-f76a-47c2-a26d-ea0b4f1836c5", "escalateTo": "string" }}
isTeamOnline event
This event will happen when the bot needs to know if there is an agent team available.
When this event is received,
the request needs to be handled SYNCHRONOUSLY
and respond if the team is available with boolean field isOnline
set to true
or false
.
The ConverseWebhookService
in our template project is where this event is processed.
From here, it’s up to the custom CRM to implement its logic internally,
like checking specific agent or group of agents availability
/** * This method processes the Converse Webhook event. * @param converseWebhookDto */ public processConverseWebhookEvent(converseWebhookDto: ConverseWebhookDto): void { switch (converseWebhookDto.data.eventType) { case ConverseWebhookEventTypes.IS_TEAM_ONLINE: /** * This event happens when the bot needs to make decisions that are dependent on the availability of human agents * * The payload of this event is represented in the BotIsTeamOnlineEvent class. * * The user will process the request and respond if there is availability or not using the class BotIsTeamOnlineEventResponse. */ logger.info( `Received ${ConverseWebhookEventTypes.IS_TEAM_ONLINE} event: \n ${JSON.stringify( converseWebhookDto )}` ); break; default: break; } }}
The escalate message structure:
Field | Type | Required | Description |
---|---|---|---|
botId | string | true | The ID of the bot that is sending the event. |
data | Object | true | Object containing the payload of the event. Depending on the event type, it will contain different values |
Field | Type | Description |
---|---|---|
eventType | string Set to isTeamOnline | Event of type isTeamOnline. |
conversationId | string | ULTIMATE internal ID (can be ignored) |
teamId? | string | The ID of the team to check (OPTIONAL) |
Example in JSON format:
{ "botId": "BOT_ID", "data": { "eventType": "isTeamOnline", "teamId": "string" }}
widgetEscalate event
This event will happen when the bot triggers an escalation to agent, and the bot is using Ultimate Chat Widget. When this event is received, the bot will stop sending messages to the customer, and it will be the custom CRM systems responsibility to manage the escalation process with the customer, and send to the widget the updates on the escalation process (like queue updates). See this article for more information of Widget escalations
The ConverseWebhookService
in our template project is where this event is processed.
From here, it’s up to the custom CRM to implement its logic internally,
like checking availability, managing a waiting queue or wait times, connect with the agent directly…
/** * This method processes the Converse Webhook event. * @param converseWebhookDto */ public processConverseWebhookEvent(converseWebhookDto: ConverseWebhookDto): void { switch (converseWebhookDto.data.eventType) { case ConverseWebhookEventTypes.WIDGET_ESCALATE: /** * This event represents an escalation request from the bot for customers that are using Ultimate Chat Widget * * The payload of this event is represented in the BotWidgetMessageEvent class. * * The request will be acknowledged and then processed ASYNCHRONOUSLY. */ logger.info( `Received ${ConverseWebhookEventTypes.WIDGET_ESCALATE} event: \n ${JSON.stringify( converseWebhookDto )}` ); break; default: break; } }}
The escalate message structure:
Field | Type | Required | Description |
---|---|---|---|
botId | string | true | The ID of the bot that is sending the event. |
data | Object | true | Object containing the payload of the event. Depending on the event type, it will contain different values |
Field | Type | Description |
---|---|---|
eventType | string Set to widgetEscalate | Event of type escalate. |
platformConversationId | string | The ID of the conversation |
conversationId | string | ULTIMATE internal ID (can be ignored) |
escalateTo? | string | The ID of the escalation team within the CRM system (OPTIONAL) |
Example in JSON format:
{ "botId": "BOT_ID", "data": { "eventType": "widgetEscalate", "platformConversationId": "13427e90-f76a-47c2-a26d-ea0b4f1836c5", "escalateTo": "string" }}
widgetMessage event
This event will be used by customers using Ultimate Chat Widget to send messages to an agent in an escalated conversation.
When this event is received,
the main purpose of the bot should be to redirect the message to the agent,
along with any other required logic.
The format of this request is similar to the sendMessage
event.
See this article for more information of Widget escalations
The ConverseWebhookService
in our template project is where this event is processed.
From here, it’s up to the custom CRM to implement its logic internally,
like directly forward it to the agent.
/** * This method processes the Converse Webhook event. * @param converseWebhookDto */ public processConverseWebhookEvent(converseWebhookDto: ConverseWebhookDto): void { switch (converseWebhookDto.data.eventType) { case ConverseWebhookEventTypes.WIDGET_MESSAGE: /** * This event represents a message request from the user to an agent in an escalated conversation for customers that are using Ultimate Chat Widget * * The payload of this event is represented in the BotWidgetEscalateEvent class. * * The request will be acknowledged and then processed ASYNCHRONOUSLY. */ logger.info( `Received ${ConverseWebhookEventTypes.WIDGET_MESSAGE} event: \n ${JSON.stringify( converseWebhookDto )}` ); break; default: break; } }}
The escalate message structure:
Field | Type | Required | Description |
---|---|---|---|
botId | string | true | The ID of the bot that is sending the event. |
data | Object | true | Object containing the payload of the event. Depending on the event type, it will contain different values |
Field | Type | Description |
---|---|---|
eventType | string Set to widgetMessage | Event of type sendMessage. |
platformConversationId | string | The ID of the conversation |
conversationId | string | ULTIMATE internal ID (Can be ignored) |
type | string Set to text | Simple text message type. |
replyId | string | Always empty in this case |
buttons | Button[] | Always empty in this event |
text | string | The text of the message. |
carouselCards | CarouselCard[] | Always empty in this event |
predictedIntents | PredictedIntent[] | Always empty in this event |
Example in JSON format:
{ "botId": "BOT_ID", "data": { "eventType": "widgetMessage", "platformConversationId": "13427e90-f76a-47c2-a26d-ea0b4f1836c5", "conversationId": "CONVERSATION_ID", "type": "text", "buttons": [], "text": "Hello, this is a customer message in an escalated conversation", "carouselCards": [], "predictedIntents": [] }}
widgetEndSession event
This event will happen when a customer using Ultimate Chat Widget explicitly finished an escalated conversation. When this event is received, the ongoing connection with the agent should be stopped, and the converastion should be closed. See this article for more information of Widget escalations
The ConverseWebhookService
in our template project is where this event is processed.
From here, it’s up to the custom CRM to implement its logic internally,
like disconnecting with the agent.
/** * This method processes the Converse Webhook event. * @param converseWebhookDto */ public processConverseWebhookEvent(converseWebhookDto: ConverseWebhookDto): void { switch (converseWebhookDto.data.eventType) { case ConverseWebhookEventTypes.WIDGET_END_SESSION: /** * This event represents an end escalated session request from the user to an agent in an escalated conversation * for customers that are using Ultimate Chat Widget * * The payload of this event is represented in the BotWidgetEndSessionEvent class. * * The request will be acknowledged and then processed ASYNCHRONOUSLY. */ logger.info( `Received ${ConverseWebhookEventTypes.WIDGET_END_SESSION} event: \n ${JSON.stringify( converseWebhookDto )}` ); break; default: break; } }}
The escalate message structure:
Field | Type | Required | Description |
---|---|---|---|
botId | string | true | The ID of the bot that is sending the event. |
data | Object | true | Object containing the payload of the event. Depending on the event type, it will contain different values |
Field | Type | Description |
---|---|---|
eventType | string Set to widgetEndSession | Event of type escalate. |
platformConversationId | string | The ID of the conversation |
conversationId | string | ULTIMATE internal ID (can be ignored) |
Example in JSON format:
{ "botId": "BOT_ID", "data": { "eventType": "widgetEndSession", "platformConversationId": "13427e90-f76a-47c2-a26d-ea0b4f1836c5" }}
Actions webhook
The actions’ webhook will receive action events only, so no eventType
parameter is defined.
This webhook is used to execute custom routines in the custom CRM application,
like updating the system with the information that the bot has collected from the customer.
The action should be executed SYNCHRONOUSLY, and optionally, it can return a response to the bot with a list of parameters to be stored in the conversation session. These parameters can later be used to drive the dialog or in other actions.
In our template project, we have defined this webhook in the url /converse-webhook
,
but it can be defined under any url.
Request payload
The payload received in the custom CRM actions webhook will look like:
Field | Type | Description |
---|---|---|
botId | string | The ID of the bot |
conversationId | string | ULTIMATE internal ID (can be ignored) |
platformConversationId | string | The ID of the conversation |
name | string | The name of the action (ie updateCustomerBalance ) |
data | ActionData[] | The parameters of the Action request. Each object of type ActionData in the array needs to contain the following fields:key string - key of the parametervalue string - value of the parameter saveAs string - name for this parameter when saved in conversation |
An example in JSON format:
{ "botId" : "BOT_ID", "conversationId": "CONVERSATION_ID", "platformConversationId": "13427e90-f76a-47c2-a26d-ea0b4f1836c5" "name": "updateCustomerBalance", "data": [ { "key": "userId", "value": [ "123345" ], "saveAs?": "customerId" }, { "key": "balance", "value": [ "100" ] } ]}
Response payload
As mentioned above, the action webhook can optionally return a response to the bot with a list of parameters to be stored in the conversation session.
The structure of the response is:
Field | Type | Description |
---|---|---|
results | ActionResult[] | List of key/value pairs to be stored in Ultimate conversation session |
Each actionResult object needs to be defined:
Field | Type | Description |
---|---|---|
key | string | Name of the variable to create in the conversation session |
value | string or number or boolean | Value of the variable to create in the conversation session |
sanitize | boolean | Marks if the value should be sanitised |
An example in JSON format:
{ "results": [ { "key": "userId", "value": "123345" }, { "key": "newBalance", "value": "210", "sanitize": true } ]}