Handover API
The handover functionality in Kindly allows customer support agents to temporarily replace the bot as the user's conversation partner. From the user's perspective, the conversation with the support agent takes place in the same chat window as the conversation with the bot. While the support agent is in the chat, the bot will not respond to the user's messages, and when the support agent leaves the chat, the bot will return to the conversation.
Support agent handover can be requested by the user by clicking on a handover request button, which can be easily added to a reply like any other button. When a user requests a takover, customer support agents are notified in the platform, and can easily take over the conversation from the Conversations section in Kindly. However, if your organization has a customer service center using a different platform, it is possible to set up a connection between your current platform and Kindly to enable handover requests to be handled through your current platform.
As there does not exist a standarized protocol for this kind of functionality, you will need to do some development to create an intermediary service that can talk to both the Kindly API and the customer support platform's API. This document describes the protocol for communication between Kindly and the intermediate service.
The Handover API was previously named Takeover API, and for backwards compatibility the event names still have these names. The API paths api/v2/takeover/... and api/v2/handover/...are aliases for the same functions and you may use either.
Architecture suggestions
To handle the communication between Kindly and your customer support platform, Kindly can either communicate directly with the customer support platform or with a intermediary service that forwards messages between the platforms.
Compatibility application

Compatibility plugin

Configuration
You can find the handover configuration page on your workspace under Settings --> Handover.

- Select external handover mode
- Set the webhook URL
- Get API key
- Set values for messages & business hours
Protocol
The protocol is based on HTTP requests between Kindly and your service, where each type of request has a unique event name. When Kindly sends events to your service, they will all arrive at your webhook, and your service will have to decide how to handle them based on the event specified in the payload.
When you send events from your service to Kindly, you can use different API endpoints for different events. Kindly will respond with a payload that includes an event field to confirm that the request was received and that the parameters were valid.
➡️ REQUESTING TAKEOVER
When a user clicks on a request handover button in the chat, your service will receive a REQUESTING TAKEOVER event. Your service should respond with 200 OK to Kindly, then forward the request to the customer support platform.
{
"event": "REQUESTING TAKEOVER",
"bot": {
"id": 123,
"name": "Test Bot"
},
"chat": {
"_links": {
"self": "https://bot.kindly.ai/api/v1/chats/5af029421a5ca5141a1ee117"
},
"id": "5af029421a5ca5141a1ee117",
"language": "en",
"source": "web"
},
"user": {
"id": "53616c7465645f5f463b889c43950414f6e08e05442771013db5d3a3953bcedc4ede6c072f91f90f1c7dee18f232f478"
}
}⬅️ TRANSCRIPT
It is probably useful for the customer service agent to be able to read what the user wrote to the bot and what the bot replied preceding the handover request. To get this info your service can POST to api/v2/handover/transcript. The API will respond with event: TRANSCRIPT and contain the message history that you can then show to the agent.
curl --request POST \
--url https://bot.kindly.ai/api/v2/handover/transcript \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"bot_id": 123,
"chat_id": "5af029421a5ca5141a1ee117"
}'{
"event": "TRANSCRIPT",
"chat": {
"id": "5af029421a5ca5141a1ee117",
"bot_id": 123.
"messages": [...],
...
}
}⬅️ SUMMARIZE
Transcripts can be long and take some time for the agent to read and understand. It's possible to ask Kindly's summarization service to read the chat transcript ahead of the agent joining and provide a short summary of the gist of the conversation. You can POST to api/v2/handover/summarize.
To make a summary, the chat has to contain 2 or more user messages that in total contains more than 30 characters.
You can customize the summary generation by adding a "Chat Summary prompt" through the Kindly Platform at this path: Workspace -> Settings -> Handover.
The summarization is a call to a large language model that happens on the fly when you make the request. The request may take some time to process, and the result summary text may change between requests. The model is hosted in the EU.
curl --request POST \
--url https://bot.kindly.ai/api/v2/handover/summarize \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"bot_id": 123,
"chat_id": "5af029421a5ca5141a1ee117"
}'{
"event": "SUMMARIZED",
"chat_id": "5af029421a5ca5141a1ee117",
"summary": "User interacted with the bot using button clicks to request information about pricing, services, and features of Kindly. Bot provided information about Kindly's services, pricing contact process, and customization options, and acknowledged the receipt of user's details."
}⬅️ HANDOVER AVAILABILITY
To control whether Kindly should route requests to your Handover system, you can update its availability status.
- When the Handover system is closed, Kindly will prevent new requests from being sent to it and instead display the relative messages and content from rules for when Handover is closed.
- When the Handover system is open, Kindly will allow requests and show the relative messages and content from rules for when Handover is open.
This could be useful for example if you want to tell us when all your agents are offline or your business hours just started.
Endpoint:
POST https://bot.kindly.ai/api/v2/handover/availabilityExpected request body:
type requestBody = {
availability: 'OPEN' | 'CLOSED'
/** Currently we support only support 1 queue, that should be named 'DEFAULT'. */
queue: 'DEFAULT' | string,
/** You should specify the reason of the opening/closure, if possible. */
reason: 'AGENT_AVAILABILITY' | 'BUSINESS_HOURS' | 'OTHER'
};Expected response body:
type responseBody = {
event: 'HANDOVER AVAILABILITY UPDATED';
/** ID of the bot whose handover availability was updated. */
bot_id: string;
queue: string; // e.g. 'DEFAULT'
availability: 'OPEN' | 'CLOSED';
updated_at: string;
};If you choose to manually manage your handover availability through this endpoint, it's your responsibility to open/close it as we don't have any automatic timeout to, for example, re-open your handover after a certain period of closure.
⬅️ HANDOVER LIVE TRANSLATION
During handover you can activate live translation of the sent messages. To do so you need to start a handover by POST to api/v2/handover/startand pass sender.language_codes.
After doing so, the system will check if the chat(client) language matches any of the agents(sender) languages. If not, it will translate each message to the first language from the language_codes. Agent messages will be translated to the client(widget)`s language.
curl --request POST \
--url https://bot.kindly.ai/api/v2/handover/start \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"bot_id": 123,
"chat_id": "5af029421a5ca5141a1ee117",
"sender": {
"name": "Customer support",
"avatar": "https://ui-avatars.com/api?name=AGENT&size=512",
"language_codes": ["es", "no", ...]
},
"supports_attachment": true
}'⬅️ TAKEOVER STARTED
When a customer service agent is ready to enter the chat, your service should POST to api/v2/handover/start with the relevant bot_id and chat_id. If the API key and the IDs are valid, Kindly will respond with event: TAKEOVER STARTED. The bot will inform the user that an agent is entering the chat and will no longer respond to the user's messages, until handover is ended by the agent.
The "sender" field is optional and not be displayed in the legacy version of the chat bubble.
Setting the sender.language_codes will activate live translation of the sent messages.
curl --request POST \
--url https://bot.kindly.ai/api/v2/handover/start \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"bot_id": 123,
"chat_id": "5af029421a5ca5141a1ee117",
"sender": {
"name": "Customer support",
"avatar": "https://ui-avatars.com/api?name=AGENT&size=512",
"language_codes": ["es", "no", ...]
},
"supports_attachment": true
}'{
"event": "TAKEOVER STARTED",
"chat_id": "5af029421a5ca5141a1ee117",
"chatmessage_id": "5af17d2ee9ad1d7d0b3bf03b"
}⬅️ TAKEOVER ENDED
When the customer service agent is ready to let the bot take over again, your service should POST to api/v2/handover/end with the relevant bot_id and chat_id. If the API key, and the ids are valid, Kindly will respond with event: TAKEOVER ENDED. The bot will inform the user that the agent has left the chat, and will resume responding to the user's messages.
The "sender" field is optional and not be displayed in the legacy version of the chat bubble.
curl --request POST \
--url https://bot.kindly.ai/api/v2/handover/end \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"bot_id": 123,
"chat_id": "5af029421a5ca5141a1ee117",
"sender": {
"name": "Customer support",
"avatar": "https://ui-avatars.com/api?name=AGENT&size=512"
}
}'{
"event": "TAKEOVER ENDED",
"chat_id": "5af029421a5ca5141a1ee117",
"chatmessage_id": "5af04d54fba4333215e4a3c7"
}⬅️ MESSAGE SENT TO USER
Messages from the support platform to the user can be forwarded to the user by POSTing to api/v2/handover/message/. In addition to the message, you should also send a name and an avatar in the sender field, indicating to the user that the message is from an agent, not from the bot.
Optionally, you can also use buttons like in other API methods, for instance to share a link with the user.
If the POST to Kindly was correct, Kindly will respond with event: MESSAGE SENT TO USER.
curl --request POST \
--url https://bot.kindly.ai/api/v2/handover/message/ \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"bot_id": 123,
"chat_id": "5af029421a5ca5141a1ee117",
"message": "This is a message from a customer support agent.",
"sender": {
"name": "Customer support",
"avatar": "https://ui-avatars.com/api?name=AGENT&size=512"
}
}'{
"event": "MESSAGE SENT TO USER",
"chat_id": "5af029421a5ca5141a1ee117",
"chatmessage_id": "5af04d48fba4333215e4a3c6"
}➡️ MESSAGE FROM USER
When the chat is taken over, and the user sends a message, it will be forwarded to your webhook as a MESSAGE FROM USER event. Your service should respond 200 OK to Kindly, then forward it to the customer support platform.
{
"bot": {
"id": 123,
"name": "Test Bot"
},
"chat": {
"_links": {
"self": "https://bot.kindly.ai/api/v1/chats/5af029421a5ca5141a1ee117"
},
"id": "5af029421a5ca5141a1ee117",
"language": "en",
"source": "web"
},
"event": "MESSAGE FROM USER",
"message": "hi!",
"user": {
"id": "53616c7465645f5f463b889c43950414f6e08e05442771013db5d3a3953bcedc4ede6c072f91f90f1c7dee18f232f478"
},
"attachments": [{ "name": "test.jpg", "url": "https://chat.kindlycdn.com/test.jpg", "type": "image/jpeg", "size_kb": 100 }]
}Note: The attachment field will be present only if you have started the handover with the supports_attachment field set to true.
➡️ AGENT TYPING START
In case you want to signal to the widget that the agent is typing, you can do it by using this endpoint: api/v2/handover/typing_start. This will display a typing indicator in our widget or SDK.
curl --request POST \
--url https://bot.kindly.ai/api/v2/handover/typing_start \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{YOUR_API_KEY}}' \
--data '{
"bot_id": {{bot_id}},
"chat_id": "{{chat_id}}",
"timeout": {{stop_timeout_ms}}
}'To hide this indicator you'll have to use the typing_stop endpoint as shown afterwards, or pass a timeout field.
In this case Kindly will POST a request to your service as below:
{
"event": "AGENT TYPING START",
"chat_id": "{{chat_id}}" // id of the ongoing conversation
}➡️ AGENT TYPING STOP
In case you want to signal to the widget that the agent stopped typing, you can do it by using this endpoint: api/v2/handover/typing_stop. This will stop displaying a typing indicator in our widget or SDK.
curl --request POST \
--url https://bot.kindly.ai/api/v2/handover/typing_stop \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{YOUR_API_KEY}}' \
--data '{
"bot_id": {{bot_id}},
"chat_id": "{{chat_id}}"
}'In this case Kindly will POST a request to your service as below:
{
"event": "AGENT TYPING STOP",
"chat_id": "{{chat_id}}" // id of the ongoing conversation
}HMACs
The messages that are sent from Kindly are authenticated using HMACs signed with the same key you use when sending messages to Kindly. See Webhook signature (HMAC) for more info about authenticating HMACs.
System messages
It is also possible to use api/v2/handover/message/ for other messages than those being forwarded from the customer support agent. For instance, you could have the service tell the user their place in the queue when it changes.
curl --request POST \
--url https://bot.kindly.ai/api/v2/handover/message/ \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"bot_id": 123,
"chat_id": "5af029421a5ca5141a1ee117",
"message": "You are now number 3 in the queue.",
"sender": {
"name": "Customer service queue",
"avatar": "https://ui-avatars.com/api?name=QUEUE&size=512"
}
}'