. Create an API key under API keys.API reference · Customers
Contacts
The phone book: import up to 10 000 contacts per call with tags and custom attributes, groups, update and delete.
List contacts
/v1/contactsList contacts (max 10 000 per call; page with offset).
Query parameters
segmentstringSaved segment idqstringtagstringgroup_idstringlimitintegeroffsetinteger | null
Responses
- 200Contacts
Response fields
contactsarray of objectrequiredcontacts[].idstringrequiredcontacts[].phonestringrequiredcontacts[].namestring | nullrequiredcontacts[].var1string | nullrequiredcontacts[].var2string | nullrequiredcontacts[].var3string | nullrequiredcontacts[].var4string | nullrequiredcontacts[].var5string | nullrequiredcontacts[].group_idstring | nullrequiredcontacts[].tagsarray of stringrequiredcontacts[].attrsobjectrequiredCustom attributes (attr.<key>in segments and message tokens)contacts[].created_atintegerrequiredcontacts[].updated_atintegerrequiredtotalintegerrequired
curl "https://api.chatkomodo.com/v1/contacts?tag=vip&limit=100" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/contacts?tag=vip&limit=100', {
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/contacts?tag=vip&limit=100",
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/contacts?tag=vip&limit=100', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"contacts": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"phone": "+447700900123",
"name": "Sam Carter",
"var1": "string",
"var2": "string",
"var3": "string",
"var4": "string",
"var5": "string",
"group_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"tags": [
"vip"
],
"attrs": {},
"created_at": 1767225600000,
"updated_at": 1767225600000
}
],
"total": 12
}Import contacts
/v1/contactsImport up to 10 000 contacts. A number that already exists is merged into the existing contact (tags are unioned) instead of duplicated. Rows that cannot be stored are returned in rejected (first 50).
Request body
contactsarray of objectrequiredcontacts[].phonestringrequiredInternational format+<country code><number>; local-format numbers use the business countrycontacts[].namestringcontacts[].varsarray of stringLegacy columns{var1}…{var5}contacts[].group_idstringcontacts[].tagsarray of stringMerged (union) with the tags the contact already hascontacts[].attrsobjectCustom attributes, keys as defined in /v1/crm/fieldscontacts[].opt_inbooleantruerecords consent with sourceimport(you state this person agreed to be messaged). It never overrides an existing opt-out.
Responses
- 201Imported
Response fields
idsarray of stringrequiredcountintegerrequiredcreatedintegerrequiredupdatedintegerrequiredrejectedarray of objectrejected[].indexintegerrequiredrejected[].errorstringrequired
- 400Validation error
curl -X POST "https://api.chatkomodo.com/v1/contacts" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{
"phone": "+447700900123",
"name": "Sam Carter",
"tags": [
"vip"
],
"attrs": {
"plan": "Pro",
"city": "London"
},
"opt_in": true
}
]
}'const res = await fetch('https://api.chatkomodo.com/v1/contacts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"contacts": [
{
"phone": "+447700900123",
"name": "Sam Carter",
"tags": [
"vip"
],
"attrs": {
"plan": "Pro",
"city": "London"
},
"opt_in": true
}
]
}),
});
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/contacts",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"contacts": [
{
"phone": "+447700900123",
"name": "Sam Carter",
"tags": [
"vip",
],
"attrs": {
"plan": "Pro",
"city": "London",
},
"opt_in": True,
},
],
},
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/contacts', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'contacts' => [
[
'phone' => '+447700900123',
'name' => 'Sam Carter',
'tags' => [
'vip',
],
'attrs' => [
'plan' => 'Pro',
'city' => 'London',
],
'opt_in' => true,
],
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ids": [
"01JA5V6Q8M2H7G4K9P3T0R1S2X"
],
"count": 12,
"created": 1,
"updated": 1,
"rejected": [
{
"index": 1,
"error": "string"
}
]
}Update a contact
/v1/contacts/{id}Update one contact. attrs is merged: an empty string removes a key.
Path parameters
idstringrequired
Request body
phonestringnamestring | nullvarsarray of string | nullgroup_idstring | nulltagsarray of stringattrsobject
Responses
- 200Updated
Response fields
okbooleanrequiredcontactobjectrequiredcontact.idstringrequiredcontact.phonestringrequiredcontact.namestring | nullrequiredcontact.var1string | nullrequiredcontact.var2string | nullrequiredcontact.var3string | nullrequiredcontact.var4string | nullrequiredcontact.var5string | nullrequiredcontact.group_idstring | nullrequiredcontact.tagsarray of stringrequiredcontact.attrsobjectrequiredCustom attributes (attr.<key>in segments and message tokens)contact.created_atintegerrequiredcontact.updated_atintegerrequired
- 404Contact or group not found
curl -X PATCH "https://api.chatkomodo.com/v1/contacts/ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Sam Carter-Jones",
"tags": [
"vip",
"newsletter"
],
"attrs": {
"city": "Bristol"
}
}'const res = await fetch('https://api.chatkomodo.com/v1/contacts/ID', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Sam Carter-Jones",
"tags": [
"vip",
"newsletter"
],
"attrs": {
"city": "Bristol"
}
}),
});
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/contacts/ID",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "Sam Carter-Jones",
"tags": [
"vip",
"newsletter",
],
"attrs": {
"city": "Bristol",
},
},
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/contacts/ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'Sam Carter-Jones',
'tags' => [
'vip',
'newsletter',
],
'attrs' => [
'city' => 'Bristol',
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true,
"contact": {
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"phone": "+447700900123",
"name": "Sam Carter",
"var1": "string",
"var2": "string",
"var3": "string",
"var4": "string",
"var5": "string",
"group_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"tags": [
"vip"
],
"attrs": {},
"created_at": 1767225600000,
"updated_at": 1767225600000
}
}Delete a contact
/v1/contacts/{id}Delete one contact.
Path parameters
idstringrequired
Responses
- 200Deleted
Response fields
okbooleanrequired
curl -X DELETE "https://api.chatkomodo.com/v1/contacts/ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/contacts/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/contacts/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/contacts/ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Delete or move many contacts
/v1/contacts/bulkDelete or move many contacts at once.
Request body
idsarray of stringrequiredactionstringrequiredgroup_idstring | nullTarget group formove(null= no group)
Responses
- 200Result:
{deleted}or{moved}Response fields
deletedintegermovedinteger
curl -X POST "https://api.chatkomodo.com/v1/contacts/bulk" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
"01JA5V6Q8M2H7G4K9P3T0R1S2X"
],
"action": "move",
"group_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X"
}'const res = await fetch('https://api.chatkomodo.com/v1/contacts/bulk', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": [
"01JA5V6Q8M2H7G4K9P3T0R1S2X"
],
"action": "move",
"group_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X"
}),
});
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/contacts/bulk",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"ids": [
"01JA5V6Q8M2H7G4K9P3T0R1S2X",
],
"action": "move",
"group_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
},
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/contacts/bulk', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'ids' => [
'01JA5V6Q8M2H7G4K9P3T0R1S2X',
],
'action' => 'move',
'group_id' => '01JA5V6Q8M2H7G4K9P3T0R1S2X',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"deleted": 1,
"moved": 1
}List contact groups
/v1/contact-groupsPhone-book groups of the tenant, ordered by name, with the number of contacts in each.
Responses
- 200Groups
Response fields
groupsarray of objectrequiredgroups[].idstringrequiredgroups[].api_key_idstringrequiredOwning tenantgroups[].namestringrequiredgroups[].created_atintegerrequiredUnix time in millisecondsgroups[].contact_countintegerrequired
- 401Missing, invalid or expired credentials
- 403Forbidden for an API key restricted to specific sessions (
KEY_SCOPE_FORBIDDEN)
curl "https://api.chatkomodo.com/v1/contact-groups" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/contact-groups', {
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/contact-groups",
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/contact-groups', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"groups": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"api_key_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "VIP customers",
"created_at": 1767225600000,
"contact_count": 12
}
]
}Create a contact group
/v1/contact-groupsCreates a phone-book group. The handler does not validate name, but it is required.
Request body
namestringrequiredGroup name
Responses
- 201Created
Response fields
idstringrequired
- 401Missing, invalid or expired credentials
- 403Forbidden for a customer-service agent login (
Agent access is not allowed for this operation) and an API key restricted to specific sessions (KEY_SCOPE_FORBIDDEN)
curl -X POST "https://api.chatkomodo.com/v1/contact-groups" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "VIP customers"
}'const res = await fetch('https://api.chatkomodo.com/v1/contact-groups', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "VIP customers"
}),
});
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/contact-groups",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "VIP customers",
},
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/contact-groups', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'VIP customers',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X"
}Delete a contact group
/v1/contact-groups/{id}Deletes the group. Its contacts are kept and simply lose their group.
Path parameters
idstringrequiredGroup 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) and an API key restricted to specific sessions (KEY_SCOPE_FORBIDDEN) - 404Group not found (no
code)
curl -X DELETE "https://api.chatkomodo.com/v1/contact-groups/ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/contact-groups/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/contact-groups/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/contact-groups/ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}