Receiving Chat webhooks
For each message sent from the Kommo interface to the chat channel, a webhook is sent to the specified address.
After receiving a webhook, you need to process it and send a message to the messenger. Webhook is sent only once and will not be sent again if the integration couldn’t process or receive it.
The response time to the webhook is limited, so we suggest to only check the request signature when receiving the webhook, and perform the business logic in the background outside the context of the request. For example, queue a task for processing and send a response to the webhook.
If you receive a message that the integrated messenger cannot accept, you need to update the message status to “error”.
Further, already in asynchronous mode, you process the message, produce your business logic and send the message.
Currently, we wait for a response to the webhook no more than 5 seconds. In order for us to consider the webhook successfully sent, your integration should respond to the request with a 200 http code.
The Chat API has prioritization mechanisms if the integration takes a long time to respond to hooks or does not respond at all, we can move it separately from the main message stream to a slow stream where hooks can arrive with a delay.
The priority is calculated dynamically and depends on various factors, the integration can go both to a faster queue and to a slower one.
The manager “typing” events require separate webhook subscriptions for each channel via tech support.
Webhook v2
Let’s analyze the webhook that Kommo sent you, and explain its method, authentication and the body.
Method
POST Your webhook url specified when registering the channel in the filed webhook_url
Description
This webhook is sent if the v2 was set when connecting the chat channel.
Headers & Authorization type
Each webhook contains an X-Signature header, which is calculated only from the request body using the HMAC-SHA1 method. The channel secret is used as a secret key, and this is how you can verify the authenticity of incoming webhooks.
To do this, you need to calculate the hash from the body of the incoming request and compare it with the one that comes in the X-Signature header.
PHP example
$secret = 'fb50586ff7b68cd831fe0ef356345903f644c0d2';
$str = file_get_contents('php://input');
$signature = hash_hmac('sha1', $str, $secret);
if (isset($_SERVER['HTTP_X_SIGNATURE']) && $signature === $_SERVER['HTTP_X_SIGNATURE'] )
{
//The webhook is valid
}
Example of the body
In cace of sending a text message
{
"account_id": "52fd2a28-d2eb-4bd8-b862-b57934927b38",
"time": 1670571014,
"message": {
"receiver": {
"id": "9c2ccde3-a3ab-4695-832c-919dbfc598ea",
"phone": "+18305803077",
"email": "",
"client_id": "b0bc49f0-ec21-4463-965f-1fe1d4cd5a90"
},
"sender": {
"id": "b0bc49f0-ec21-4463-965f-1fe1d4cd5b89"
},
"conversation": {
"id": "14723c64-c40d-4efc-9f78-9625adac414c",
"client_id": "62ef74a4-80c5-403d-93d9-bada6302810d"
},
"timestamp": 1670571014,
"msec_timestamp": 1670571014414,
"message": {
"id": "3419eef6-2aa3-464c-b6e4-4386d0f8f3ca",
"type": "text",
"text": "Hello Adam! \nLet's arrange a call for next week. ",
"markup": null,
"tag": "",
"media": "",
"thumbnail": "",
"file_name": "",
"file_size": 0
}
}
}
The Message body entity in case of sending a file
"message": {
"id": "8fe1174e-af30-4184-95a2-6ad193c95bca",
"type": "file",
"text": "Hello Adam\nI am sending you the prices. Please take a look.",
"markup": null,
"tag": "",
"media": "https://amojo.kommo.com/attachments/52fd2a28-d2eb-4bd8-b862-a67934927b38/14723c64-c40d-4efc-9f78-9625adac414c/xjXgl_Prices-lists.odt",
"thumbnail": "",
"file_name": "Prices-lists.odt",
"file_size": 9603
}
The message entity with media in case of sending a markup
"message": {
"id": "8fe1174e-af30-4184-95a2-6ad193c95bca",
"type": "picture",
"text": "Conversation text #15926745",
"markup": {
"mode": "inline",
"buttons": [
[
{
"text": "Confirm order"
},
{
"text": "Delete order"
}
]
]
},
"tag": "",
"media": "https://amojo.kommo.com/attachments/image.jpg",
"thumbnail": "https://amojo.kommo.com/attachments/image_320x200.jpg",
"file_name": "",
"file_size": 0,
"template": {
"id": 7103,
"external_id": "my_external_id",
"content": "Conversation text {{lead.name}}",
"params": [
{
"key": "{{lead.id}}",
"value": "15926745"
}
]
}
}
Body parameters
Optional fields may not come in the hook.
It is important to note that a message can arrive simultaneously with media, text, and buttons, and when sending multiple attachments at once, the message will be split into several hooks, but they will have a common message[message][media_group_id]
Parameter | Data type | Description |
---|---|---|
account_id | string | amojo account ID |
time | int | Timestamp when generating the webhook in the format of Unix Timestamp |
message | object | An array contains the message components. Description about the elements of the object. |
Message entity
Parameter | Data type | Description |
---|---|---|
receiver | object | Message receiver. Description about the elements of the object. |
sender[id] | string | Chat participant ID on the Chat API side |
conversation | object | Conversation details. Description about the elements of the object. |
timestamp | int | Message timestamp in the format of Unix Timestamp |
msec_timestamp | int | Message timestamp in milliseconds |
message | object | The content of the message. Description about the elements of the object. |
Receiver entity
Parameter | Data type | Description |
---|---|---|
id | string | Chat participant ID on the integration side |
phone | string | Phone number. The field is not returned if the profile wasn’t passed |
string | Email address. The field is not returned if the profile wasn’t passed | |
client_id | string | Chat participant ID on the Chat API side |
Conversation entity
Parameter | Data type | Description |
---|---|---|
id | string | Chat ID in the Chat API |
client_id | string | Chat ID on the integration side |
Message body entity
Parameter | Data type | Description |
---|---|---|
id | string | amojo ID of the message |
type required |
string | Message type, one of the following: text, file, video, picture, voice, audio, sticker |
text | string | The field is mandatory for the “text” type, can be empty for other types |
markup | object | The keyboard object to display with the message. Description about the elements of the object. |
media | string | Url to the file, video, picture, voice, audio, or sticker. |
thumbnail | string | Link to the preview picture or video thumbnail url. |
file_name | string | The name of the file from the “media” field url |
file_size | int | The size for the data in the “media” field |
template | object | Template object, if the message was sent using a template. Description about the elements of the object. |
Markup entity
The markup object is an array of arrays of buttons with the specified way to arrange them.
The location method is specified in the mode field. Currently, for integrations, an object’s mode always contains the value inline.
The inline value says that the keyboard should be below the message text.
At the moment, buttons of different types cannot come in the same object.
Parameter | Data type | Description |
---|---|---|
mode | string | Keyboard layout. Possible values: inline – buttons are displayed below the message text |
button | object | Array of the button objects. Description about the elements of the object. |
Markup buttons entity
Parameter | Data type | Description |
---|---|---|
text | string | Text. When a user clicks on a text button, the messenger should send a message with the text of this button to the chat |
url | string | Link. When a user clicks on a link button, the messenger should follow that link. The property may be absent if a normal button is passed |
Template entity
Parameter | Data type | Description |
---|---|---|
id | string | The template id in Kommo |
content | string | The template text without interpreting the placeholders |
params | object | An object of the placeholders. Details of the elements of the params object. |
Template params entity
Parameter | Data type | Description |
---|---|---|
key | string | Key of the placeholder |
value | string | Value of the placeholder |
HTTP response codes
The address receiving this webhook must respond with a 200 http code, in which case we consider the hook to be successfully accepted.
Response code | Condition |
---|---|
200 | Webhook processed successfully |
Typing webhook
The webhook is sent when the manager types a message in the Kommo interface.
The webhook is sent no more than once every 5 seconds.
Example of the body
{
"account_id": "52fd2a28-d2eb-4bd8-b862-b57934927b38",
"time": 1670585310,
"action": {
"typing": {
"user": {
"id": "b0bc49f0-ec21-4463-965f-1fe1d4cd5b89"
},
"conversation": {
"id": "30477717-9f3c-4d3f-8101-60327e14dc48",
"client_id": "62ef74a4-80c5-403d-93d9-bada6302810f"
},
"expired_at": 1670585315
}
}
}
Body parameters
Parameter | Data type | Description |
---|---|---|
account_id | string | amojo account ID |
time | int | Timestamp when generating the webhook in the format of Unix Timestamp |
action[user][id] | string | User ID who performs the writing in the Chat API |
action[typing][conversation][id] | string | Chat ID in Chats API |
action[typing][conversation][client_id] | string | Chat ID on the integration side. Optional field. If the chat was created using the “Write first” function, the field will be absent in the hook |
action[typing][expired_at] | int | Timestamp when we think the user is no longer typing. We pass the typing end timestamp as the current print start time + 5 seconds |
HTTP response codes
The address receiving this webhook must respond with a 200 http code, in which case we consider the hook to be successfully accepted.
Response code | Condition |
---|---|
200 | Webhook processed successfully |
Finally, let’s see how we can disconnect a chat channel.
Webhook about a reaction
The webhook is triggered when the user reacts to a message or removes their reaction within the Kommo interface.
Body parameters
Parameter | Data type | Description |
---|---|---|
account_id | string | Chat API account ID |
time | int | Webhook create time. Unix timestamp |
action[reaction][message] | object | Object of the message. Details |
action[reaction][user] | object | An object with information about the sender of the reaction. Details |
action[reaction][conversation][id] | string | Chat ID in Chat API |
action[reaction][conversation][client_id] | string | Chat ID on the integration side. Optional field. If the chat is created via the “Write first” Salesbot action, the field will not be in the webhook |
action[reaction][type] | string | Event type: react, unreact |
action[reaction][emoji] | string | Reaction provided by the user. Optional field. If the user removes the reaction, the field will not be in the webhook |
Reaction message entity
Parameter | Data type | Description |
---|---|---|
id | string | Chat API message ID |
client_id | string | Message ID on the integration side. Optional field. If the message was created on the Kommo side, the field will not be in the webhook |
receiver | object | An object with information about the receiver of the message. Details |
sender | object | An object with information about the sender of the message. Details |
timestamp | int | Message create time, Unix timestamp |
msec_timestamp | int | Message create time, Unix timestamp with milliseconds |
Example of the request
{
"account_id": "81ede28b-8952-4785-abe2-c8d93f5fcc7d",
"time": 1637087558,
"action": {
"reaction": {
"message":{
"id": "a80fb604-9e04-4e1d-bee9-37c71924cd11",
"client_id": "64ff3a9baeb11",
"sender":{
"id": "f1e4e02c-f502-4165-9377-8575c55c5ebd",
"name": "John Smith",
"phone": "+14255551212",
"client_id": "14255551212"
},
"timestamp": 1694448283,
"msec_timestamp": 1694448283000
},
"user": {
"id": "fb0fb604-9e04-4e1d-bee9-37c71924cdc2"
},
"conversation": {
"id": "f1e4e02c-f502-4165-9377-8575c55c5ebd",
"client_id": "c7"
},
"type": "react",
"emoji": "😍"
}
}
}
HTTP response codes
The recipient address for this webhook must return a HTTP 200 status code as a response, at which point we consider the webhook to be successfully acknowledged.
Response code | Condition |
---|---|
200 | Webhook processed successfully |