. Create an API key under API keys.API reference · Customers
Labels & leads
Labels on people and chats (several per chat, shared with the CRM contact), automatic labelling rules (keywords, new chats, store orders, inactivity, AI) and the leads board with your own stages. See the labels & leads guide.
List labels
/v1/labelsEvery label of the business (used on contacts or chats, or created here) with its colour, description and how many contacts and group chats carry it. A chat with a person shares its labels with that person's CRM contact, so the same labels drive segments, broadcasts and the leads board.
Responses
- 200Labels
Response fields
labelsarray of objectrequiredlabels[].namestringrequiredNormalised name: lowercase, spaces become dasheslabels[].colorstringrequired#RRGGBBlabels[].descriptionstring | nullrequiredlabels[].countintegerrequiredContacts and group chats that carry itcolorsarray of stringrequiredSuggested colours
- 401Missing, invalid or expired credentials
curl "https://api.chatkomodo.com/v1/labels" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/labels', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.get(
"https://api.chatkomodo.com/v1/labels",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('GET', 'https://api.chatkomodo.com/v1/labels', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"labels": [
{
"name": "Example",
"color": "#0a7350",
"description": "Short description",
"count": 12
}
],
"colors": [
"#0a7350"
]
}Create a label
/v1/labelsAdds a label to the catalogue so it can be picked in the inbox and in rules. Names are normalised (lowercase, spaces become dashes); an existing label is updated instead.
Request body
namestringrequiredcolorstring#RRGGBB (default: picked from the name)descriptionstring | null
Responses
- 201Created
Response fields
labelobjectrequiredlabel.namestringrequiredNormalised name: lowercase, spaces become dasheslabel.colorstringrequired#RRGGBBlabel.descriptionstring | nullrequiredlabel.countintegerrequiredContacts and group chats that carry it
- 400Body is not valid JSON (
INVALID_JSON) or fails validation (VALIDATION_FAILED) - 401Missing, invalid or expired credentials
- 403Forbidden for a customer-service agent login (
Agent access is not allowed for this operation)
curl -X POST "https://api.chatkomodo.com/v1/labels" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Example",
"color": "#0a7350",
"description": "Short description"
}'const res = await fetch('https://api.chatkomodo.com/v1/labels', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Example",
"color": "#0a7350",
"description": "Short description"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.post(
"https://api.chatkomodo.com/v1/labels",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "Example",
"color": "#0a7350",
"description": "Short description",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('POST', 'https://api.chatkomodo.com/v1/labels', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'Example',
'color' => '#0a7350',
'description' => 'Short description',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"label": {
"name": "Example",
"color": "#0a7350",
"description": "Short description",
"count": 12
}
}Rename or recolour a label
/v1/labels/{name}A new name renames the label on every contact, group chat and rule.
Path parameters
namestringrequired
Request body
namestringcolorstringdescriptionstring | null
Responses
- 200Saved
Response fields
labelobjectrequiredlabel.namestringrequiredNormalised name: lowercase, spaces become dasheslabel.colorstringrequired#RRGGBBlabel.descriptionstring | nullrequiredlabel.countintegerrequiredContacts and group chats that carry it
- 400Body is not valid JSON (
INVALID_JSON) or fails validation (VALIDATION_FAILED) - 401Missing, invalid or expired credentials
- 403Forbidden for a customer-service agent login (
Agent access is not allowed for this operation) - 404Label not found, or it belongs to another tenant (
NOT_FOUND) - 409A label with the new name already exists (
CONFLICT)
curl -X PATCH "https://api.chatkomodo.com/v1/labels/NAME" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Example",
"color": "#0a7350",
"description": "Short description"
}'const res = await fetch('https://api.chatkomodo.com/v1/labels/NAME', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Example",
"color": "#0a7350",
"description": "Short description"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.patch(
"https://api.chatkomodo.com/v1/labels/NAME",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "Example",
"color": "#0a7350",
"description": "Short description",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('PATCH', 'https://api.chatkomodo.com/v1/labels/NAME', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'Example',
'color' => '#0a7350',
'description' => 'Short description',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"label": {
"name": "Example",
"color": "#0a7350",
"description": "Short description",
"count": 12
}
}Delete a label
/v1/labels/{name}Removes the label from every contact, group chat and rule.
Path parameters
namestringrequired
Responses
- 200Deleted
Response fields
okbooleanrequiredremoved_fromintegerrequired
- 401Missing, invalid or expired credentials
- 403Forbidden for a customer-service agent login (
Agent access is not allowed for this operation) - 404Label not found, or it belongs to another tenant (
NOT_FOUND)
curl -X DELETE "https://api.chatkomodo.com/v1/labels/NAME" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/labels/NAME', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.delete(
"https://api.chatkomodo.com/v1/labels/NAME",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('DELETE', 'https://api.chatkomodo.com/v1/labels/NAME', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true,
"removed_from": 1
}List automatic labelling rules
/v1/labels/rulesRules add or remove labels and move people to a lead stage by themselves: keyword (an incoming message contains the words), first_message (a new chat), store_event (an order from the connected store), inactive (no message for N days, checked hourly) and ai (the AI reads the conversation and decides; at most once every 15 minutes per chat, each check uses 1 AI reply of the plan). Rules work on chats with a person. A label someone removed by hand is never put back by a rule.
Responses
- 200Rules
Response fields
rulesarray of objectrequiredrules[].idstringrequiredrules[].namestringrequiredrules[].enabledbooleanrequiredrules[].triggerstringrequiredrules[].configobjectrequiredrules[].config.keywordsarray of stringkeyword: words or phrases, matched at the start of a word (hargaalso findsharganya), accents and case ignoredrules[].config.matchstringkeyword: any (default) or all keywordsrules[].config.eventsarray of stringstore_event: which store eventsrules[].config.daysintegerinactive: days without a message (1–365)rules[].config.instructionstringai: when the rule applies, in plain words, e.g. "the customer asks for a price or wants to order"rules[].add_labelsarray of stringrequiredrules[].remove_labelsarray of stringrequiredrules[].set_stagestring | nullrequiredLead stage to move the person torules[].session_idsarray of string | nullrequiredOnly these devices (null = all)rules[].fire_countintegerrequiredrules[].last_fired_atinteger | nullrequiredUnix time in milliseconds, or nullrules[].created_atintegerrequiredUnix time in millisecondsrules[].updated_atintegerrequiredUnix time in milliseconds
- 401Missing, invalid or expired credentials
curl "https://api.chatkomodo.com/v1/labels/rules" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/labels/rules', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.get(
"https://api.chatkomodo.com/v1/labels/rules",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('GET', 'https://api.chatkomodo.com/v1/labels/rules', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"rules": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"enabled": true,
"trigger": "keyword",
"config": {
"keywords": [
"price"
],
"match": "any",
"events": [
"order_created"
],
"days": 1,
"instruction": "string"
},
"add_labels": [
"string"
],
"remove_labels": [
"string"
],
"set_stage": "vip",
"session_ids": [
"YOUR_DEVICE_ID"
],
"fire_count": 12,
"last_fired_at": 1767225600000,
"created_at": 1767225600000,
"updated_at": 1767225600000
}
]
}Create a rule
/v1/labels/rulesA rule needs labels to add or remove, or a lead stage to set, and the settings of its trigger (see GET /v1/labels/rules). At most 50 rules per business.
Request body
namestringrequiredenabledbooleantriggerstringrequiredconfigobjectconfig.keywordsarray of stringkeyword: words or phrases, matched at the start of a word (hargaalso findsharganya), accents and case ignoredconfig.matchstringkeyword: any (default) or all keywordsconfig.eventsarray of stringstore_event: which store eventsconfig.daysintegerinactive: days without a message (1–365)config.instructionstringai: when the rule applies, in plain words, e.g. "the customer asks for a price or wants to order"add_labelsarray of stringremove_labelsarray of stringset_stagestring | nullsession_idsarray of string | null
Responses
- 201Created
Response fields
ruleobjectrequiredrule.idstringrequiredrule.namestringrequiredrule.enabledbooleanrequiredrule.triggerstringrequiredrule.configobjectrequiredrule.config.keywordsarray of stringkeyword: words or phrases, matched at the start of a word (hargaalso findsharganya), accents and case ignoredrule.config.matchstringkeyword: any (default) or all keywordsrule.config.eventsarray of stringstore_event: which store eventsrule.config.daysintegerinactive: days without a message (1–365)rule.config.instructionstringai: when the rule applies, in plain words, e.g. "the customer asks for a price or wants to order"rule.add_labelsarray of stringrequiredrule.remove_labelsarray of stringrequiredrule.set_stagestring | nullrequiredLead stage to move the person torule.session_idsarray of string | nullrequiredOnly these devices (null = all)rule.fire_countintegerrequiredrule.last_fired_atinteger | nullrequiredUnix time in milliseconds, or nullrule.created_atintegerrequiredUnix time in millisecondsrule.updated_atintegerrequiredUnix time in milliseconds
- 400Invalid rule (
VALIDATION_FAILED) or more than 50 rules (LIMIT_REACHED) - 401Missing, invalid or expired credentials
- 403Forbidden for a customer-service agent login (
Agent access is not allowed for this operation)
curl -X POST "https://api.chatkomodo.com/v1/labels/rules" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Example",
"enabled": true,
"trigger": "keyword",
"config": {
"keywords": [
"price"
],
"match": "any",
"events": [
"order_created"
],
"days": 1
}
}'const res = await fetch('https://api.chatkomodo.com/v1/labels/rules', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Example",
"enabled": true,
"trigger": "keyword",
"config": {
"keywords": [
"price"
],
"match": "any",
"events": [
"order_created"
],
"days": 1
}
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.post(
"https://api.chatkomodo.com/v1/labels/rules",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "Example",
"enabled": True,
"trigger": "keyword",
"config": {
"keywords": [
"price",
],
"match": "any",
"events": [
"order_created",
],
"days": 1,
},
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('POST', 'https://api.chatkomodo.com/v1/labels/rules', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'Example',
'enabled' => true,
'trigger' => 'keyword',
'config' => [
'keywords' => [
'price',
],
'match' => 'any',
'events' => [
'order_created',
],
'days' => 1,
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"rule": {
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"enabled": true,
"trigger": "keyword",
"config": {
"keywords": [
"price"
],
"match": "any",
"events": [
"order_created"
],
"days": 1,
"instruction": "string"
},
"add_labels": [
"string"
],
"remove_labels": [
"string"
],
"set_stage": "vip",
"session_ids": [
"YOUR_DEVICE_ID"
],
"fire_count": 12,
"last_fired_at": 1767225600000,
"created_at": 1767225600000,
"updated_at": 1767225600000
}
}Change a rule
/v1/labels/rules/{id}Fields left out keep their value. enabled: false pauses the rule.
Path parameters
idstringrequiredRule id
Request body
namestringenabledbooleantriggerstringconfigobjectconfig.keywordsarray of stringkeyword: words or phrases, matched at the start of a word (hargaalso findsharganya), accents and case ignoredconfig.matchstringkeyword: any (default) or all keywordsconfig.eventsarray of stringstore_event: which store eventsconfig.daysintegerinactive: days without a message (1–365)config.instructionstringai: when the rule applies, in plain words, e.g. "the customer asks for a price or wants to order"add_labelsarray of stringremove_labelsarray of stringset_stagestring | nullsession_idsarray of string | null
Responses
- 200Saved
Response fields
ruleobjectrequiredrule.idstringrequiredrule.namestringrequiredrule.enabledbooleanrequiredrule.triggerstringrequiredrule.configobjectrequiredrule.config.keywordsarray of stringkeyword: words or phrases, matched at the start of a word (hargaalso findsharganya), accents and case ignoredrule.config.matchstringkeyword: any (default) or all keywordsrule.config.eventsarray of stringstore_event: which store eventsrule.config.daysintegerinactive: days without a message (1–365)rule.config.instructionstringai: when the rule applies, in plain words, e.g. "the customer asks for a price or wants to order"rule.add_labelsarray of stringrequiredrule.remove_labelsarray of stringrequiredrule.set_stagestring | nullrequiredLead stage to move the person torule.session_idsarray of string | nullrequiredOnly these devices (null = all)rule.fire_countintegerrequiredrule.last_fired_atinteger | nullrequiredUnix time in milliseconds, or nullrule.created_atintegerrequiredUnix time in millisecondsrule.updated_atintegerrequiredUnix time in milliseconds
- 400Body is not valid JSON (
INVALID_JSON) or fails validation (VALIDATION_FAILED) - 401Missing, invalid or expired credentials
- 403Forbidden for a customer-service agent login (
Agent access is not allowed for this operation) - 404Rule not found, or it belongs to another tenant (
NOT_FOUND)
curl -X PATCH "https://api.chatkomodo.com/v1/labels/rules/ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Example",
"enabled": true,
"trigger": "keyword",
"config": {
"keywords": [
"price"
],
"match": "any",
"events": [
"order_created"
],
"days": 1
}
}'const res = await fetch('https://api.chatkomodo.com/v1/labels/rules/ID', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Example",
"enabled": true,
"trigger": "keyword",
"config": {
"keywords": [
"price"
],
"match": "any",
"events": [
"order_created"
],
"days": 1
}
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.patch(
"https://api.chatkomodo.com/v1/labels/rules/ID",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "Example",
"enabled": True,
"trigger": "keyword",
"config": {
"keywords": [
"price",
],
"match": "any",
"events": [
"order_created",
],
"days": 1,
},
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('PATCH', 'https://api.chatkomodo.com/v1/labels/rules/ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'Example',
'enabled' => true,
'trigger' => 'keyword',
'config' => [
'keywords' => [
'price',
],
'match' => 'any',
'events' => [
'order_created',
],
'days' => 1,
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"rule": {
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"enabled": true,
"trigger": "keyword",
"config": {
"keywords": [
"price"
],
"match": "any",
"events": [
"order_created"
],
"days": 1,
"instruction": "string"
},
"add_labels": [
"string"
],
"remove_labels": [
"string"
],
"set_stage": "vip",
"session_ids": [
"YOUR_DEVICE_ID"
],
"fire_count": 12,
"last_fired_at": 1767225600000,
"created_at": 1767225600000,
"updated_at": 1767225600000
}
}Delete a rule
/v1/labels/rules/{id}Labels the rule already applied stay where they are.
Path parameters
idstringrequiredRule id
Responses
- 200Deleted
Response fields
okbooleanrequired
- 401Missing, invalid or expired credentials
- 403Forbidden for a customer-service agent login (
Agent access is not allowed for this operation) - 404Rule not found, or it belongs to another tenant (
NOT_FOUND)
curl -X DELETE "https://api.chatkomodo.com/v1/labels/rules/ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/labels/rules/ID', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.delete(
"https://api.chatkomodo.com/v1/labels/rules/ID",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('DELETE', 'https://api.chatkomodo.com/v1/labels/rules/ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}The leads board
/v1/leadsPeople in a lead stage (at most 1 000, most recently moved first) with their labels and latest chat, and the business's stages. Filter by label or search q (name or number).
Query parameters
labelstringqstring
Responses
- 200Board
Response fields
stagesarray of objectrequiredstages[].idstringrequiredstages[].namestringrequiredstages[].colorstringrequiredleadsarray of objectrequiredleads[].contact_idstringrequiredleads[].namestring | nullrequiredleads[].phonestringrequiredleads[].stagestringrequiredleads[].labelsarray of objectrequiredleads[].labels[].namestringrequiredleads[].labels[].colorstringrequiredleads[].stage_updated_atinteger | nullrequiredUnix time in milliseconds, or nullleads[].session_idstring | nullrequiredleads[].chat_idstring | nullrequiredleads[].last_messagestring | nullrequiredleads[].last_message_atinteger | nullrequiredUnix time in milliseconds, or nullleads[].unread_countintegerrequired
- 401Missing, invalid or expired credentials
curl "https://api.chatkomodo.com/v1/leads" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/leads', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.get(
"https://api.chatkomodo.com/v1/leads",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('GET', 'https://api.chatkomodo.com/v1/leads', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350"
}
],
"leads": [
{
"contact_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"phone": "+447700900123",
"stage": "vip",
"labels": [
{
"name": "Example",
"color": "#0a7350"
}
],
"stage_updated_at": 1767225600000,
"session_id": "YOUR_DEVICE_ID",
"chat_id": "+447700900123",
"last_message": "Hi Sam, your order has shipped.",
"last_message_at": 1767225600000,
"unread_count": 12
}
]
}Set the lead stages
/v1/leads/stages1–12 stages in board order. People in a stage that is removed move to the first stage; rules that set it stop setting a stage.
Request body
stagesarray of objectrequiredstages[].idstringKept when renaming; default: from the namestages[].namestringrequiredstages[].colorstring
Responses
- 200Saved
Response fields
stagesarray of objectrequiredstages[].idstringrequiredstages[].namestringrequiredstages[].colorstringrequired
- 400Body is not valid JSON (
INVALID_JSON) or fails validation (VALIDATION_FAILED) - 401Missing, invalid or expired credentials
- 403Forbidden for a customer-service agent login (
Agent access is not allowed for this operation)
curl -X PUT "https://api.chatkomodo.com/v1/leads/stages" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350"
}
]
}'const res = await fetch('https://api.chatkomodo.com/v1/leads/stages', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350"
}
]
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.put(
"https://api.chatkomodo.com/v1/leads/stages",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350",
},
],
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('PUT', 'https://api.chatkomodo.com/v1/leads/stages', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'stages' => [
[
'id' => '01JA5V6Q8M2H7G4K9P3T0R1S2X',
'name' => 'Example',
'color' => '#0a7350',
],
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350"
}
]
}Move a lead
/v1/leads/{contactId}stage: null takes the person off the board.
Path parameters
contactIdstringrequired
Request body
stagestring | nullrequired
Responses
- 200Moved
Response fields
okbooleanrequiredstagestring | nullrequired
- 400Unknown lead stage (
VALIDATION_FAILED) - 401Missing, invalid or expired credentials
- 404Contact not found, or it belongs to another tenant (
NOT_FOUND)
curl -X PATCH "https://api.chatkomodo.com/v1/leads/CONTACT_ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"stage": "vip"
}'const res = await fetch('https://api.chatkomodo.com/v1/leads/CONTACT_ID', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"stage": "vip"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.patch(
"https://api.chatkomodo.com/v1/leads/CONTACT_ID",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"stage": "vip",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('PATCH', 'https://api.chatkomodo.com/v1/leads/CONTACT_ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'stage' => 'vip',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true,
"stage": "vip"
}Labels and stage of a chat
/v1/sessions/{sid}/inbox/{chatId}/labelsA chat can carry several labels (up to 20). For a chat with a person they are that person's contact labels, shared across devices.
Path parameters
sidstringrequiredSession (device) idchatIdstringrequiredChat id (JID), URL-encoded
Responses
- 200Labels
Response fields
labelsarray of objectrequiredlabels[].namestringrequiredlabels[].colorstringrequiredstagestring | nullrequiredLead stage (chats with a person only)stagesarray of objectrequiredstages[].idstringrequiredstages[].namestringrequiredstages[].colorstringrequiredpersonbooleanrequiredThe chat is with a person (labels live on their contact)historyarray of objectrequiredLatest 20 changeshistory[].labelstringrequiredhistory[].actionstringrequiredhistory[].sourcestringrequiredhistory[].rule_idstring | nullrequiredhistory[].rule_namestring | nullrequiredhistory[].actorstring | nullrequiredhistory[].atintegerrequiredUnix time in milliseconds
- 401Missing, invalid or expired credentials
curl "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.get(
"https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('GET', 'https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"labels": [
{
"name": "Example",
"color": "#0a7350"
}
],
"stage": "vip",
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350"
}
],
"person": true,
"history": [
{
"label": "string",
"action": "add",
"source": "manual",
"rule_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"rule_name": "string",
"actor": "string",
"at": 1767225600000
}
]
}Add or remove labels on a chat
/v1/sessions/{sid}/inbox/{chatId}/labelsAdds and removes some labels, keeping the others. Adding a label by hand lifts an earlier manual removal, so rules may add it again later.
Path parameters
sidstringrequiredSession (device) idchatIdstringrequiredChat id (JID), URL-encoded
Request body
addarray of stringremovearray of string
Responses
- 200Saved
Response fields
labelsarray of objectrequiredlabels[].namestringrequiredlabels[].colorstringrequiredstagestring | nullrequiredLead stage (chats with a person only)stagesarray of objectrequiredstages[].idstringrequiredstages[].namestringrequiredstages[].colorstringrequiredpersonbooleanrequiredThe chat is with a person (labels live on their contact)historyarray of objectrequiredLatest 20 changeshistory[].labelstringrequiredhistory[].actionstringrequiredhistory[].sourcestringrequiredhistory[].rule_idstring | nullrequiredhistory[].rule_namestring | nullrequiredhistory[].actorstring | nullrequiredhistory[].atintegerrequiredUnix time in milliseconds
- 400Invalid body or more than 20 labels (
LIMIT_REACHED) - 401Missing, invalid or expired credentials
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"add": [
"string"
],
"remove": [
"string"
]
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"add": [
"string"
],
"remove": [
"string"
]
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.post(
"https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"add": [
"string",
],
"remove": [
"string",
],
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('POST', 'https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'add' => [
'string',
],
'remove' => [
'string',
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"labels": [
{
"name": "Example",
"color": "#0a7350"
}
],
"stage": "vip",
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350"
}
],
"person": true,
"history": [
{
"label": "string",
"action": "add",
"source": "manual",
"rule_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"rule_name": "string",
"actor": "string",
"at": 1767225600000
}
]
}Replace the labels of a chat
/v1/sessions/{sid}/inbox/{chatId}/labelsLabelling a person who is not a contact yet saves them as a contact. Removing a label by hand stops rules and the AI from adding it again to this person.
Path parameters
sidstringrequiredSession (device) idchatIdstringrequiredChat id (JID), URL-encoded
Request body
labelsarray of stringrequired
Responses
- 200Saved
Response fields
labelsarray of objectrequiredlabels[].namestringrequiredlabels[].colorstringrequiredstagestring | nullrequiredLead stage (chats with a person only)stagesarray of objectrequiredstages[].idstringrequiredstages[].namestringrequiredstages[].colorstringrequiredpersonbooleanrequiredThe chat is with a person (labels live on their contact)historyarray of objectrequiredLatest 20 changeshistory[].labelstringrequiredhistory[].actionstringrequiredhistory[].sourcestringrequiredhistory[].rule_idstring | nullrequiredhistory[].rule_namestring | nullrequiredhistory[].actorstring | nullrequiredhistory[].atintegerrequiredUnix time in milliseconds
- 400Invalid body or more than 20 labels (
LIMIT_REACHED) - 401Missing, invalid or expired credentials
curl -X PUT "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"labels": [
"string"
]
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"labels": [
"string"
]
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.put(
"https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"labels": [
"string",
],
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('PUT', 'https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'labels' => [
'string',
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"labels": [
{
"name": "Example",
"color": "#0a7350"
}
],
"stage": "vip",
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350"
}
],
"person": true,
"history": [
{
"label": "string",
"action": "add",
"source": "manual",
"rule_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"rule_name": "string",
"actor": "string",
"at": 1767225600000
}
]
}Set the lead stage of a chat
/v1/sessions/{sid}/inbox/{chatId}/stagePuts the person on the leads board in this stage (null takes them off). The person is saved as a contact when needed.
Path parameters
sidstringrequiredSession (device) idchatIdstringrequiredChat id (JID), URL-encoded
Request body
stagestring | nullrequired
Responses
- 200Saved
Response fields
labelsarray of objectrequiredlabels[].namestringrequiredlabels[].colorstringrequiredstagestring | nullrequiredLead stage (chats with a person only)stagesarray of objectrequiredstages[].idstringrequiredstages[].namestringrequiredstages[].colorstringrequiredpersonbooleanrequiredThe chat is with a person (labels live on their contact)historyarray of objectrequiredLatest 20 changeshistory[].labelstringrequiredhistory[].actionstringrequiredhistory[].sourcestringrequiredhistory[].rule_idstring | nullrequiredhistory[].rule_namestring | nullrequiredhistory[].actorstring | nullrequiredhistory[].atintegerrequiredUnix time in milliseconds
- 400Not a chat with a person, or an unknown stage (
VALIDATION_FAILED) - 401Missing, invalid or expired credentials
curl -X PUT "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/stage" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"stage": "vip"
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/stage', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"stage": "vip"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.put(
"https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/stage",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"stage": "vip",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('PUT', 'https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/stage', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'stage' => 'vip',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"labels": [
{
"name": "Example",
"color": "#0a7350"
}
],
"stage": "vip",
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350"
}
],
"person": true,
"history": [
{
"label": "string",
"action": "add",
"source": "manual",
"rule_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"rule_name": "string",
"actor": "string",
"at": 1767225600000
}
]
}Run the AI rules on a chat now
/v1/sessions/{sid}/inbox/{chatId}/labels/aiLets the AI rules check this conversation immediately (normally they run after incoming messages, at most every 15 minutes per chat). Uses 1 AI reply of the plan; nothing happens without AI rules, an AI provider or AI quota.
Path parameters
sidstringrequiredSession (device) idchatIdstringrequiredChat id (JID), URL-encoded
Responses
- 200Checked
Response fields
labelsarray of objectrequiredlabels[].namestringrequiredlabels[].colorstringrequiredstagestring | nullrequiredLead stage (chats with a person only)stagesarray of objectrequiredstages[].idstringrequiredstages[].namestringrequiredstages[].colorstringrequiredpersonbooleanrequiredThe chat is with a person (labels live on their contact)historyarray of objectrequiredLatest 20 changeshistory[].labelstringrequiredhistory[].actionstringrequiredhistory[].sourcestringrequiredhistory[].rule_idstring | nullrequiredhistory[].rule_namestring | nullrequiredhistory[].actorstring | nullrequiredhistory[].atintegerrequiredUnix time in millisecondsfiredarray of stringrequiredIds of the rules that applied
- 400Not a chat with a person (
VALIDATION_FAILED) - 401Missing, invalid or expired credentials
- 403Forbidden for a customer-service agent login (
Agent access is not allowed for this operation)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels/ai" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels/ai', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.error}`);
console.log(data);import os
import requests
res = requests.post(
"https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels/ai",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('POST', 'https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/inbox/447700900123%40s.whatsapp.net/labels/ai', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"labels": [
{
"name": "Example",
"color": "#0a7350"
}
],
"stage": "vip",
"stages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"color": "#0a7350"
}
],
"person": true,
"history": [
{
"label": "string",
"action": "add",
"source": "manual",
"rule_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"rule_name": "string",
"actor": "string",
"at": 1767225600000
}
],
"fired": [
"string"
]
}