Receiving events from the bot

Receive events from the bot

The bot will send events to your application through the webhooks that have been configured in the bot Custom CRM settings:

Custom CRM example
Custom CRM example

The Chat webhook will receive events related to conversations, messages or escalation, while the actions webhook executes actions that have been configured in the bot.

Chat webhook

The events that can be received are:

  1. sendMessage - A message from the bot to the visitor.
  2. escalate - An escalation request from the bot to your application.
  3. isTeamOnline - An escalation dependent on the availability of human agents.
  4. widgetMessage - A message from the customer to the human agent in the scope of an escalated conversation. For Widget Bots only.
  5. widgetEscalate - An escalation request from a widget customer to the CRM. For Widget Bots only.
  6. widgetEndSession - A request to end an escalated session. For Widget Bots only.

We have defined this webhook in our template project under the url /converse-webhook, but the implementation in your application 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 is the most common event that will be sent to your application. It is 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, you can see this type of event in the ConverseWebhookService. From here, it’s up to your application to execute logic on the message that it has received from the bot. It can directly forward it to the customer or process it beforehand, 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:

FieldTypeRequiredDescription
botIdstringtrueThe ID of the bot that is sending the event.
dataObjecttrueObject containing the payload of the event. Depending on the event type, it will contain different values
FieldTypeDescription
eventTypestring
Set to sendMessage
Event of type sendMessage.
platformConversationIdstringThe ID of the conversation
conversationIdstringULTIMATE internal ID (Can be ignored)
typestring
Set to text
Simple text message type.
replyIdstringThe ID of the reply in Ultimate system that triggered this text message.
textstringThe text of the message.
predictedIntentsPredictedIntent[]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 intent
confidence 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:

FieldTypeRequiredDescription
botIdstringtrueThe ID of the bot that is sending the event.
dataObjecttrueObject containing the payload of the event. Depending on the event type, it will contain different values
FieldTypeDescription
eventTypestring
Set to sendMessage
Event of type sendMessage.
platformConversationIdstringThe ID of the conversation
conversationIdstringULTIMATE internal ID (can be ignored)
typestring
Set to text
Simple text message type.
replyIdstringThe ID of the reply in Ultimate system that triggered this text message.
buttonsButton[]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
textstringThe text of the message with buttons. Not mandatory to exist.
predictedIntentsPredictedIntent[]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 intent
confidence 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}]
}
}

The carousel message structure:

FieldTypeRequiredDescription
botIdstringtrueThe ID of the bot that is sending the event.
dataObjecttrueObject containing the payload of the event. Depending on the event type, it will contain different values
FieldTypeDescription
eventTypestring
Set to sendMessage
Event of type sendMessage.
platformConversationIdstringThe ID of the conversation
conversationIdstringULTIMATE internal ID (can be ignored)
typestring
Set to carousel
Carousel message type.
replyIdstringThe ID of the reply in Ultimate system that triggered this text message.
textstringThe text of the message with buttons. Not mandatory to exist.
carouselCardsCarouselCard[]The carousel cards array will contain a list of cards. See table below with the fields of CarouselCards
predictedIntentsPredictedIntent[]Predicted intents for visitor message. Each object of type PredictedIntent in the array needs to contain the following fields:
value string - the intent id
name string - name of the intent
confidence number - confidence in the intent


Each object of type CarouselCard in the array needs to contain the following fields:

FieldTypeDescription
titlestringTitle of the carousel.
descriptionstringEvent of type sendMessage
imageUrlstringUrl of the card image.
buttonsButton[]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 happens when the bot triggers an escalation to a human agent. When this event is received, the bot stops sending messages to the visitor, At this point conversations have to be handled in your application.

In our template project, we process this event in the ConverseWebhookService. From there, any other action has to happen in your application whether it is about checking for agents availabilitin, adding the customer to a queue or any other logic that is relevant to your application.

/**
* 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:

FieldTypeRequiredDescription
botIdstringtrueThe ID of the bot that is sending the event.
dataObjecttrueObject containing the payload of the event. Depending on the event type, it will contain different values
FieldTypeDescription
eventTypestring
Set to escalate
Event of type escalate.
platformConversationIdstringThe ID of the conversation
conversationIdstringULTIMATE internal ID (can be ignored)
escalateTo?stringThe 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 your application 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:

FieldTypeRequiredDescription
botIdstringtrueThe ID of the bot that is sending the event.
dataObjecttrueObject containing the payload of the event. Depending on the event type, it will contain different values
FieldTypeDescription
eventTypestring
Set to isTeamOnline
Event of type isTeamOnline.
conversationIdstringULTIMATE internal ID (can be ignored)
teamId?stringThe ID of the team to check (OPTIONAL)

Example in JSON format:

{
"botId": "BOT_ID",
"data": {
"eventType": "isTeamOnline",
"teamId": "string"
}
}

widgetEscalate event

This event happens when the bot triggers an escalation to a human agent and the bot is using Ultimate Chat Widget. When this event is received, the bot stops sending messages to the visitor, At this point conversations have to be handled in your application. and send to the widget the updates on the escalation process (like queue updates). See this article for more information on Widget escalations

The ConverseWebhookService in our template project is where we process this type of event. From there, any other action has to happen in your application whether it is about checking for agents availability, adding the customer to a queue or any other logic that is relevant to your application.

/**
* 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:

FieldTypeRequiredDescription
botIdstringtrueThe ID of the bot that is sending the event.
dataObjecttrueObject containing the payload of the event. Depending on the event type, it will contain different values
FieldTypeDescription
eventTypestring
Set to widgetEscalate
Event of type escalate.
platformConversationIdstringThe ID of the conversation
conversationIdstringULTIMATE internal ID (can be ignored)
escalateTo?stringThe 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 is used when customers using an Ultimate Chat Widget wants to send messages to an agent within the scope of an escalated conversation. When this event is received, the main purpose of the bot should be to redirect the message to a human agent, along with any other required logic. The format of this request is similar to the sendMessage event. See this article for more information on Widget escalations

In our template project, the ConverseWebhookService is where we can process this type of event. From here, it’s up to your application to execute logic on the message that it has received from the bot like directly forwarding it to a human 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:

FieldTypeRequiredDescription
botIdstringtrueThe ID of the bot that is sending the event.
dataObjecttrueObject containing the payload of the event. Depending on the event type, it will contain different values
FieldTypeDescription
eventTypestring
Set to widgetMessage
Event of type sendMessage.
platformConversationIdstringThe ID of the conversation
conversationIdstringULTIMATE internal ID (Can be ignored)
typestring
Set to text
Simple text message type.
replyIdstringAlways empty in this case
buttonsButton[]Always empty in this event
textstringThe text of the message.
carouselCardsCarouselCard[]Always empty in this event
predictedIntentsPredictedIntent[]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 happens when a customer using a Ultimate Chat Widget explicitly finishes an escalated conversation. When this event is received, the ongoing connection with the agent should be stopped, and the conversation should be closed. See this article for more information on Widget escalations

In our template project, the ConverseWebhookService is where we can process this type of event. From here, it’s up to your application to execute logic on the message that it has received from the bot like disconnecting with the human 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:

FieldTypeRequiredDescription
botIdstringtrueThe ID of the bot that is sending the event.
dataObjecttrueObject containing the payload of the event. Depending on the event type, it will contain different values
FieldTypeDescription
eventTypestring
Set to widgetEndSession
Event of type escalate.
platformConversationIdstringThe ID of the conversation
conversationIdstringULTIMATE 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 your 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:

FieldTypeDescription
botIdstringThe ID of the bot
conversationIdstringULTIMATE internal ID (can be ignored)
platformConversationIdstringThe ID of the conversation
namestringThe name of the action (ie updateCustomerBalance)
dataActionData[]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 parameter
value 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:

FieldTypeDescription
resultsActionResult[]List of key/value pairs to be stored in Ultimate conversation session

Each actionResult object needs to be defined:

FieldTypeDescription
keystringName of the variable to create in the conversation session
valuestring or number or booleanValue of the variable to create in the conversation session
sanitizebooleanMarks if the value should be sanitised

An example in JSON format:

{
"results": [
{
"key": "userId",
"value": "123345"
},
{
"key": "newBalance",
"value": "210",
"sanitize": true
}
]
}