Webhook reference
When a dialogue in Kindly triggers a webhook, Kindly sends an HTTP POST request to the endpoint URL you have configured. You can add webhooks to any dialogues inside the Kindly Platform.
The body of this request contains a JSON payload with information about the conversation. This page is a technical reference for the data sent in that request and the data you can send back in your response.
New to Webhooks?
For a step-by-step tutorial on how to set up your first webhook, please read our guide: Getting started with webhooks.
Request payload
The POST request payload from Kindly to your webhook endpoint is a JSON serialized object containing multiple fields.
Here are the most important fields and what they represent:
- organization_id - The ID of the organization to which the chat belongs.
- bot_id - The ID of the bot to which the chat belongs.
- chat_id - The chat ID is a UUID that defines the chat the message belongs to. This ID can be found in Insights, in the URL of the page.
- user_id - The user ID is a string, provided by the chat client that defines the user who triggered the webhook.
- chat_labels - The labels associated with this chat.
- exchange - The dialogue (exchange) object that Kindly found and replied with when triggered by the webhook.
- exchange_id - The exchange id is a UUID that defines the dialogue that triggered the webhook. It can be found in the URL of the build section, when editing the desired dialogue.
- language_code - The language code indicating the dialogue language.
- message - The exact phrase that the user wrote to trigger the webhook.
- attachments - List of file attachments that user or agent has uploaded to a chat. Read more about it here
- context- The collected chat context of the conversation. Read more about context Conversation context.
- _links - Linked REST resources object (f.ex. chat transcripts).
- chat - If your webhook service requires more information about the chat or the previous messages, this can be fetched from the Chat Transcript API with a GET request to the url in _links.chat. Chat Transcript API.
- source - Source is the name of the chat client that triggered the webhook. It can be one of the following web (chat bubble in the browser), facebook (Facebook Messenger), slack (Slack), app (Application API) or test (app.kindly.ai test chat bubble).
- web_path - The current URL path for Kindly Chat web clients, which is useful if you are implementing search and want to bias it towards documents related to the current page.
- web_host - The current URL host for Kindly Chat web clients.
- web_url - The current URL for Kindly Chat web clients.
Response payload
After your service receives and processes a webhook request from Kindly, you should always respond with an HTTP 200 OK status.
Optionally, you can include a JSON body in this response to dynamically control the conversation. This allows you to generate replies, display buttons, set context, and trigger other actions in the chat. The following sections detail the fields you can use.
Reply
A string of text that will be displayed as a message from the bot.
{
"reply": "Text that the bot will answer"
}To split the message into paragraphs (seperate bubbles) use two consecutive new lines, i.e. \n\n.
{
"reply": "Text that the bot will say\n\nText on new line"
}Buttons
You can attach buttons to the reply. You can define the same types of buttons as you can do in the platform.
It's important to note that the button object needs to be wrapped in an array, even if you only send a single button.
{
"reply": "Text that the bot will say",
"buttons": [
{
"button_type": "quick_reply",
"label": "Hello",
"value": "Hi"
},
{
"button_type": "link",
"label": "example.com",
"value": "https://example.com/",
"open_in_new_tab": false,
},
{
"button_type": "email",
"label": "Email [email protected]",
"value": "[email protected]"
},
{
"button_type": "phone",
"label": "Phone 123 456 789",
"value": "123 456 789"
},
{
"button_type": "dialogue_trigger",
"label": "Read more",
"value": "<dialogue-id> or <dialogue-slug>"
}
]
}You can also automatically define additional context when a button is clicked, using the context key on any button.
{
"reply": "What kind of ice cream do you prefer",
"buttons": [
{
"button_type": "dialogue_trigger",
"label": "Chocolate",
"value": "<dialogue-id> or <dialogue-slug>",
"context": {
"favorite_ice_cream": "chocolate"
}
},
{
"button_type": "dialogue_trigger",
"label": "Vanilla",
"value": "<dialogue-id> or <dialogue-slug>",
"context": {
"favorite_ice_cream": "vanilla"
}
},
]
}Image carousel
You can send one or multiple images.
{
"image_carousel": [
{
"id": "id1",
"title": "Carousel title",
"description": "This is a nice carousel",
"imageUrl": "https://placehold.co/600x400",
"linkUrl": "example.com",
"buttons": [
{
"id": "id1",
"value": "example.com",
"label": "Open link",
"button_type": "link"
},
{
"id": "id2",
"value": "dialogue id of the dialogue to trigger",
"label": "Trigger dialogue",
"button_type": "dialogue_trigger"
}
]
}
]
}
The image_carousel field must be an array of image objects. Every object must contain metadata for a single image.
You can attach buttons to specific images in the carousel. We currently support:
- dialogue_trigger
- link
- quick_reply
Form
You can integrate a form into the bot reply. You can include up to 5 fields per form.
{
"form": {
"language_code": "en",
"submit_dialogue_id": "{{submit_dialogue_id}}",
"cancel_dialogue_id": "{{cancel_dialogue_id}}",
"texts": {
"title": "Form Title",
"submit_button_text": "Send",
"cancel_button_text": "Cancel",
"cancel_text": "Form was exited",
"error_text": "An error occurred",
"unanswered_text": "Form was not answered"
},
"fields": [
{
"slug": "name",
"input_type": "TEXT",
"required": false,
"order": 0,
"texts": {
"label": "Name",
"placeholder_text": "Name"
}
},
{
"slug": "ingredients",
"input_type": "CHECKBOX",
"required": false,
"order": 1,
"texts": {
"label": "Ingredients"
},
"attributes": {
"options": [
{
"label": "Tomato",
"value": "tomato"
},
{
"label": "Mozzarella",
"value": "mozzarella"
}
]
}
}
]
}
}- language_code: Specifies the language used in the form.
- submit_dialogue_id: Every form, when submitted, must display a success dialogue; hence, you need to provide the id or slug of the dialogue you want to trigger.
- cancel_dialogue_id: Every form, when canceled, must display a cancel dialogue; hence, you need to provide the id or slug of the dialogue you want to trigger.
- texts: Contains text elements for various parts of the form:
- title: Title of the form.
- submit_button_text: Text for the submit button.
- cancel_button_text: Text for the cancel button.
- cancel_text: Message when the form is exited.
- error_text: Message when an error occurs.
- unanswered_text: Message when the form is left unanswered.
- fields: Array of objects, each representing a field in the form:
- slug: A unique identifier for the field.
- order: Numerical order of the field in the form.
- required: Indicates if the field is mandatory (true or false).
- affix(optional): Text or value affixed to the input field.
- input_type: Defines the type of the field, options include:
- TEXT: For text input.
- TEXTAREA: For wider text inputs.
- EMAIL: For email addresses
- NUMBER: For numerical values
- RANGE: For range values
- SELECT: For selection
- CHECKBOX: For checkboxes
- RADIO: For radio buttons
- FILE: For file uploads
- texts: Contains the following attributes for field text customization:
- label: The primary label text for the field.
- help_text (optional): Additional help text for the field.
- placeholder_text (optional): Placeholder text displayed inside the field.
- required_text (optional): Text displayed for required fields.
- affix_value (optional): Affixed text or value associated with the field.
- attributes: Additional properties for the field, including:
- default_value: Default value of the field.
- step: Step size for numerical inputs.
- options: List of options:
- value: Value of the option.
- label: Display label of the option.
- validators (optional): List of fields defining validation rules for the field, which may include:
- min_length: Minimum length requirement.
- max_length: Maximum length limit.
- maximum: Upper numerical limit.
- minimum: Lower numerical limit.
- pattern: Regex pattern for validation.
- preset: Predefined validation type.
- texts: Custom messages for validation feedback.
New context
If your webhook service computes some new value that you want the chatbot to remember, you can send it as JSON in new_context.
If the key you are adding already exists in the bot's context memory, the value will be overwritten.
{
"new_context": {
"some_key": "some value"
}
}Trigger dialogue
Instead of sending a reply defined by the webhook server, you can also trigger a dialogue that you have defined in the Kindly platform.
{
"exchange_id": "Dialogue ID"
}or
{
"exchange_slug": "Dialogue slug"
}The dialogue ID is a UUID, and can be found on the page where you edit the dialogue, or in the URL of the page.
The dialogue slug is an optional value picked by you that can be used in place of the dialogue UUID. You can set the dialogue slug on dialogues with the trigger type.
Labels
You can attach some labels to the chat by passing a labels field:
{
"labels": ["label-name-1", "label-name-2"]
}You have to use label names. The labels need to exist within the Workspace to be attached, so if they can't be found they won't get triggered but they will not cause any error (i.e. they will just be omitted).
Attachments
The list consists of Attachment objects that include a temporary signed url which is available for 30 minutes after the webhook payload is sent. This means that if you want to keep these attachments you need to download them from the given url and store them somewhere. The supported file types are raw text, documents, images, and PDF.
Here is an example:
type Attachment = {
created: string;
name: string;
url: string;
size_kb: number;
status: string;
type: string;
};
const removeExpiredAttachment = (attachment: Attachment) =>
new Date(attachment.created) >
new Date(Date.now() - ATTACHMENT_LIFETIME_MINUTES * 60 * 1000);
async function downloadAndStoreAttachment(attachment: Attachment) {
const data = await downloadFile(attachment.url); // your own implementation
await storeFile(data); // your own implementation
}
async function processAttachments(attachments: Attachment[]) {
return await Promise.allSettled(
(attachments || [])
.filter(removeExpiredAttachment)
.map((attachment) => downloadAndStoreAttachment(attachment))
);
}Settings
You can also pass some Chat settings:
- chatbubble_hide_input_field to disable the Chat input field. Make sure the user has a way to continue the conversation, for example by providing a button that triggers another dialogue.
{
"chatbubble_hide_input_field": true
}Smart Webhooks
You can utilize our Smart Webhooks functionality by passing some data as aiReply.data. You can find an example below:
{
"aiReply": {
"data": {
"id": "tshirt001",
"name": "Classic Cotton T-Shirt",
"description": "High-quality, comfortable, 100% cotton t-shirt perfect for everyday wear.",
"categories": ["clothing", "tops", "casualwear"],
"sizes": ["S", "M", "L", "XL"],
"colors": ["red","blue","green"],
}
}
}In this scenario, the reply field (if passed) will be ignored because the AI will generate the reply based on the data you provide in the field.
Examples
Here is an example response showing some of the most common fields.
This response will output in the chat a reply, some buttons, a one-image carousel, and will set some new context and labels.
{
"reply": "Hello from server!",
"buttons": [
{
"button_type": "quick_reply",
"label": "Hello",
"value": "Hi server!"
}
],
"image_carousel": [
{
"id": "id1",
"title": "Carousel title",
"description": "This is a nice carousel",
"imageUrl": "https://placehold.co/600x400",
"linkUrl": "example.com",
}
]
"new_context": {
"user_email": "[email protected]"
},
"labels": ["label-name-1", "label-name-2"]
}