AI Agents Chat API Webhook
The AI agents Chat API uses webhooks to provide immediate, asynchronous event delivery. When you send a message to the Chat API, it responds with an empty 200 OK to acknowledge the request. The actual bot response is delivered separately to your configured webhook as soon as it’s ready.
This approach enables:
- Proactive bot messaging: The bot can send messages or updates without waiting for a user prompt.
- Real-time delivery: Each event (message, escalation, and so forth) generates an immediate webhook to your application.
For example, if a conversation begins and the user hasn't sent a message within a certain time, the bot can proactively send a prompt via webhook, such as "Are you still there?"
Supported webhook events
The Chat API webhook can receive the following event types:
| Event Type | Description | Example Use |
|---|---|---|
| sendMessage | Bot sends a message to the visitor | Display a message, carousel, or quick reply |
| escalate | Bot requests escalation to a human agent | Route the conversation to a support agent |
| isTeamOnline | Bot checks if a team or agent is available | Confirm agent or team availability |
Example: Handling webhook events
In the template project, webhooks are sent as POST requests to the /converse-webhook endpoint, but your application can use any endpoint you choose. Each payload includes details about the event type and relevant message data. Your application should process each event asynchronously, handle any required business logic, and respond with a 200 OK.
Here is an example handler in TypeScript:
/*** This method processes the Converse Webhook* It receives a DTO of type ConverseWebhookDto with the event details** It processes 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
The sendMessage event is the most common event sent to your application. It represents a message from the bot to the visitor and can deliver a simple text message, a list of buttons, or carousel cards. Your webhook should process each event asynchronously and respond with 200 OK to acknowledge receipt.
In the template project, you can handle sendMessage events using ConverseWebhookService. This service receives incoming webhook events from the bot and processes them asynchronously. Your application can then choose to forward the message directly to the customer or apply any custom logic before delivering it.
Example handler in TypeScript:
/*** Handles the Converse Webhook event.* @param converseWebhookDto Event payload from the bot*/public processConverseWebhookEvent(converseWebhookDto: ConverseWebhookDto): void {switch (converseWebhookDto.data.eventType) {case ConverseWebhookEventTypes.SEND_MESSAGE:// Process messages from the bot (text, button list, carousel, etc.)logger.info(`Received ${ConverseWebhookEventTypes.SEND_MESSAGE} event: ${JSON.stringify(converseWebhookDto)}`);// Add your application's logic herebreak;default:// Handle other event types as neededbreak;}}
Text message
A simple text message from the bot.
| Field | Type | Description |
|---|---|---|
| botId | string | The ID of the bot sending the event |
| data.eventType | string | Set to sendMessage |
| data.platformConversationId | string | Conversation ID (external) |
| data.conversationId | string | Internal conversation ID (can be ignored) |
| data.type | string | Set to text for a text message |
| data.replyId | string | The reply ID that triggered this message |
| data.text | string | The text content of the message |
| data.buttons | array | Always empty for a simple text message |
| data.carouselCards | array | Always empty for a simple text message |
| data.predictedIntents | array | Array of predicted intents for visitor message. Each object must contain: - value: string (intent id) - name: string (intent name) - confidence: number (confidence score, 0–1) |
Example:
{"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 }]}}
Button list message
A message from the bot containing a list of buttons the user can select.
| Field | Type | Description |
|---|---|---|
| botId | string | The id of the bot sending the event |
| data.eventType | string | Set to sendMessage |
| data.platformConversationId | string | Conversation id (external) |
| data.conversationId | string | (Optional) Internal conversation id |
| data.type | string | Set to text for a button list message |
| data.replyId | string | The reply id that triggered this message |
| data.text | string | Optional. Main message text (can be omitted) |
| data.buttons | array | Array of button objects. See Button object |
| data.carouselCards | array | Always empty for a button list message |
| data.predictedIntents | array | Array of predicted intent objects. Each object must contain: - value: string (intent id) - name: string (intent name) - confidence: number (confidence score, 0–1) |
Button object
| Field | Type | Description |
|---|---|---|
| type | string | Must be "button" |
| text | string | The button display text |
Example:
{"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": "It's a bot text message with 2 buttons","carouselCards": [],"predictedIntents": [{ "value": "1234", "name": "intent name", "confidence": 1 }]}}
Carousel message
A message from the bot containing a carousel of cards, each with optional buttons.
| Field | Type | Description |
|---|---|---|
| botId | string | The id of the bot sending the event |
| data.eventType | string | Set to sendMessage |
| data.platformConversationId | string | Conversation id (external) |
| data.conversationId | string | (Optional) Internal conversation id |
| data.type | string | Set to carousel |
| data.replyId | string | The reply id that triggered this message |
| data.text | string | Optional. Message text (can be omitted for carousels) |
| data.buttons | array | Always empty for a carousel message |
| data.carouselCards | array | Array of CarouselCard objects. See CarouselCard |
| data.predictedIntents | array | Array of predicted intent objects. Each object must contain: - value: string (intent id) - name: string (intent name) - confidence: number (confidence score, 0–1) |
CarouselCard
Each object of type CarouselCard in the array must contain the following fields:
| Field | Type | Description |
|---|---|---|
| title | string | Title of the carousel card |
| description | string | Description of the card |
| imageUrl | string | URL to the card image |
| buttons | array | Each object of type Button must contain the following fields:- type: string (set to the value "button") - text:string (button text) |
Example:
{"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 }]}}
Response handling
A successful sendMessage will return a 200 response to the webhook request and no response body. A failed sendMessage will return a 4XX - 5XX range response to the webhook request.
escalate event
The escalate event occurs when the bot requests escalation to a human agent. Once this event is received, the bot stops sending messages to the visitor, and your application becomes responsible for managing the conversation flow—such as checking agent availability or adding the customer to a queue.
The template project processes this event using ConverseWebhookService. After the event is received, your application is responsible for handling the next steps, such as checking agent availability, adding the customer to a queue, or implementing any other relevant business logic.
Example webhook handler (TypeScript)
/*** 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;}}}
Payload structure
| Field | Type | Description |
|---|---|---|
| botId | string | The id of the bot sending the event |
| data.eventType | string | Set to escalate |
| data.platformConversationId | string | The external conversation id |
| data.conversationId | string | (Optional) Internal conversation id |
| data.escalateTo | string | (Optional) The escalation team’s CRM id |
Example:
{"botId": "BOT_ID","data": {"eventType": "escalate","platformConversationId": "13427e90-f76a-47c2-a26d-ea0b4f1836c5","escalateTo": "team_123"}}
A successful escalation should return a 200 OK with no response body. Failure scenarios should return an appropriate 4XX or 5XX error code.
isTeamOnline event
The isTeamOnline event is sent when the bot needs to check if a specific support team or agent group is available. Your webhook should handle this event synchronously and respond with a boolean value indicating whether the requested team is online.
The ConverseWebhookService in our template project handles this event. After receiving the event, your application should implement the necessary logic internally, such as checking the availability of specific agents or agent groups.
Example handler (TypeScript)
/*** Processes the Converse Webhook event.* @param converseWebhookDto The event payload from the bot*/public processConverseWebhookEvent(converseWebhookDto: ConverseWebhookDto): void {switch (converseWebhookDto.data.eventType) {case ConverseWebhookEventTypes.IS_TEAM_ONLINE:/*** Handles the event where the bot needs to check the availability of human agents.* The payload for this event is defined in the BotIsTeamOnlineEvent class.* Your application should process the request and respond with agent/team* availability using the BotIsTeamOnlineEventResponse class.*/logger.info(`Received ${ConverseWebhookEventTypes.IS_TEAM_ONLINE} event: \n${JSON.stringify(converseWebhookDto)}`);// Add your availability-check logic herebreak;default:break;}}
Payload structure
| Field | Type | Description |
|---|---|---|
| botId | string | The id of the bot sending the event |
| data.eventType | string | Set to isTeamOnline |
| data.conversationId | string | (Optional) Internal conversation id |
| data.teamId | string | (Optional) The team id to check for availability |
Example:
{"botId": "BOT_ID","data": {"eventType": "isTeamOnline","teamId": "team_abc"}}
Response structure
| Field | Type | Description |
|---|---|---|
| isOnline | boolean | Returns true if the team is available, false otherwise |
Example:
{"isOnline": true}