. Create an API key under API keys.API reference · Customers
CRM
Custom contact fields, tags, saved segments (dynamic audiences) and the contact card of a number.
List custom contact fields
/v1/crm/fieldsCustom contact attributes defined by the business (max 30).
Responses
- 200Fields
Response fields
fieldsarray of objectrequiredfields[].keystringrequiredLowercase letters, digits,_; starts with a letter; max 30fields[].labelstringrequiredfields[].typestringrequiredfields[].optionsarray of stringRequired forselect
curl "https://api.chatkomodo.com/v1/crm/fields" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/crm/fields', {
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/crm/fields",
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/crm/fields', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"fields": [
{
"key": "uploads/abc123.jpg",
"label": "string",
"type": "text",
"options": [
"string"
]
}
]
}Replace the custom contact fields
/v1/crm/fieldsReplace the whole list of custom attribute definitions.
Request body
fieldsarray of objectrequiredfields[].keystringrequiredLowercase letters, digits,_; starts with a letter; max 30fields[].labelstringrequiredfields[].typestringrequiredfields[].optionsarray of stringRequired forselect
Responses
- 200Saved
Response fields
fieldsarray of objectrequiredfields[].keystringrequiredLowercase letters, digits,_; starts with a letter; max 30fields[].labelstringrequiredfields[].typestringrequiredfields[].optionsarray of stringRequired forselect
- 400Validation error
curl -X PUT "https://api.chatkomodo.com/v1/crm/fields" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fields": [
{
"key": "plan",
"label": "Plan",
"type": "select",
"options": [
"Free",
"Pro"
]
},
{
"key": "renewal",
"label": "Renewal date",
"type": "date"
}
]
}'const res = await fetch('https://api.chatkomodo.com/v1/crm/fields', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"fields": [
{
"key": "plan",
"label": "Plan",
"type": "select",
"options": [
"Free",
"Pro"
]
},
{
"key": "renewal",
"label": "Renewal date",
"type": "date"
}
]
}),
});
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/crm/fields",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"fields": [
{
"key": "plan",
"label": "Plan",
"type": "select",
"options": [
"Free",
"Pro",
],
},
{
"key": "renewal",
"label": "Renewal date",
"type": "date",
},
],
},
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/crm/fields', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'fields' => [
[
'key' => 'plan',
'label' => 'Plan',
'type' => 'select',
'options' => [
'Free',
'Pro',
],
],
[
'key' => 'renewal',
'label' => 'Renewal date',
'type' => 'date',
],
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"fields": [
{
"key": "uploads/abc123.jpg",
"label": "string",
"type": "text",
"options": [
"string"
]
}
]
}List contact tags
/v1/crm/tagsAll tags in use with the number of contacts carrying each.
Responses
- 200Tags
Response fields
tagsarray of objectrequiredtags[].tagstringrequiredtags[].countintegerrequired
curl "https://api.chatkomodo.com/v1/crm/tags" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/crm/tags', {
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/crm/tags",
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/crm/tags', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"tags": [
{
"tag": "vip",
"count": 12
}
]
}Tag or untag many contacts
/v1/crm/contacts/tagsAdd and/or remove tags on many contacts, selected by ids or by a saved segment_id.
Request body
idsarray of stringsegment_idstringaddarray of stringremovearray of string
Responses
- 200Result
Response fields
updatedintegerrequiredskippedintegerrequired
curl -X POST "https://api.chatkomodo.com/v1/crm/contacts/tags" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"segment_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"add": [
"spring-sale"
],
"remove": [
"new"
]
}'const res = await fetch('https://api.chatkomodo.com/v1/crm/contacts/tags', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"segment_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"add": [
"spring-sale"
],
"remove": [
"new"
]
}),
});
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/crm/contacts/tags",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"segment_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"add": [
"spring-sale",
],
"remove": [
"new",
],
},
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/crm/contacts/tags', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'segment_id' => '01JA5V6Q8M2H7G4K9P3T0R1S2X',
'add' => [
'spring-sale',
],
'remove' => [
'new',
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"updated": 1,
"skipped": 1
}List segments
/v1/crm/segmentsSaved segments (dynamic audiences) with their current size.
Responses
- 200Segments
Response fields
segmentsarray of objectrequiredsegments[].idstringrequiredsegments[].namestringrequiredsegments[].filterobjectrequiredsegments[].filter.matchstringrequiredall= AND,any= ORsegments[].filter.rulesarray of objectrequiredsegments[].filter.rules[].fieldstringrequiredname,phone,group,tag,consent,createdorattr.<key>segments[].filter.rules[].opstringrequiredWhich operators apply depends on the field: text fields take is/is_not/contains/not_contains/starts_with/empty/not_empty;tagtakes has/not_has/has_any; dates take before/after/within_days; numbers also gt/gte/lt/ltesegments[].filter.rules[].valuestring | number | array of stringsegments[].countinteger | nullNumber of matching contacts (list only; cached for about a minute).nullwhile it has not been counted yetsegments[].count_pendingbooleantruewhencountisnullbecause the count is still being computed: only a few segments are counted per call, ask again shortlysegments[].created_atintegerrequiredsegments[].updated_atintegerrequired
curl "https://api.chatkomodo.com/v1/crm/segments" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/crm/segments', {
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/crm/segments",
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/crm/segments', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"segments": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "VIP customers",
"filter": {
"match": "all",
"rules": [
{
"field": null,
"op": "is",
"value": null
}
]
},
"count": 12,
"count_pending": true,
"created_at": 1767225600000,
"updated_at": 1767225600000
}
]
}Create a segment
/v1/crm/segmentsCreate a segment (max 200). Use its id as segment_id when creating a blast or listing contacts.
Request body
namestringrequiredfilterobjectrequiredfilter.matchstringrequiredall= AND,any= ORfilter.rulesarray of objectrequiredfilter.rules[].fieldstringrequiredname,phone,group,tag,consent,createdorattr.<key>filter.rules[].opstringrequiredWhich operators apply depends on the field: text fields take is/is_not/contains/not_contains/starts_with/empty/not_empty;tagtakes has/not_has/has_any; dates take before/after/within_days; numbers also gt/gte/lt/ltefilter.rules[].valuestring | number | array of string
Responses
- 201Created
Response fields
idstringrequirednamestringrequiredfilterobjectrequiredfilter.matchstringrequiredall= AND,any= ORfilter.rulesarray of objectrequiredfilter.rules[].fieldstringrequiredname,phone,group,tag,consent,createdorattr.<key>filter.rules[].opstringrequiredWhich operators apply depends on the field: text fields take is/is_not/contains/not_contains/starts_with/empty/not_empty;tagtakes has/not_has/has_any; dates take before/after/within_days; numbers also gt/gte/lt/ltefilter.rules[].valuestring | number | array of stringcountinteger | nullNumber of matching contacts (list only; cached for about a minute).nullwhile it has not been counted yetcount_pendingbooleantruewhencountisnullbecause the count is still being computed: only a few segments are counted per call, ask again shortlycreated_atintegerrequiredupdated_atintegerrequired
- 400Invalid filter
- 409
LIMIT_REACHED
curl -X POST "https://api.chatkomodo.com/v1/crm/segments" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Pro customers who are VIP",
"filter": {
"match": "all",
"rules": [
{
"field": "attr.plan",
"op": "is",
"value": "Pro"
},
{
"field": "tag",
"op": "has",
"value": "vip"
}
]
}
}'const res = await fetch('https://api.chatkomodo.com/v1/crm/segments', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Pro customers who are VIP",
"filter": {
"match": "all",
"rules": [
{
"field": "attr.plan",
"op": "is",
"value": "Pro"
},
{
"field": "tag",
"op": "has",
"value": "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.post(
"https://api.chatkomodo.com/v1/crm/segments",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "Pro customers who are VIP",
"filter": {
"match": "all",
"rules": [
{
"field": "attr.plan",
"op": "is",
"value": "Pro",
},
{
"field": "tag",
"op": "has",
"value": "vip",
},
],
},
},
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/crm/segments', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'Pro customers who are VIP',
'filter' => [
'match' => 'all',
'rules' => [
[
'field' => 'attr.plan',
'op' => 'is',
'value' => 'Pro',
],
[
'field' => 'tag',
'op' => 'has',
'value' => 'vip',
],
],
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "VIP customers",
"filter": {
"match": "all",
"rules": [
{
"field": "tag",
"op": "is",
"value": "vip"
}
]
},
"count": 12,
"count_pending": true,
"created_at": 1767225600000,
"updated_at": 1767225600000
}Preview a segment filter
/v1/crm/segments/previewHow many contacts a filter matches, plus a sample (max 50), without saving it.
Request body
filterobjectrequiredfilter.matchstringrequiredall= AND,any= ORfilter.rulesarray of objectrequiredfilter.rules[].fieldstringrequiredname,phone,group,tag,consent,createdorattr.<key>filter.rules[].opstringrequiredWhich operators apply depends on the field: text fields take is/is_not/contains/not_contains/starts_with/empty/not_empty;tagtakes has/not_has/has_any; dates take before/after/within_days; numbers also gt/gte/lt/ltefilter.rules[].valuestring | number | array of stringlimitinteger
Responses
- 200Preview
Response fields
countintegerrequiredsamplearray of objectrequiredsample[].idstringrequiredsample[].phonestringrequiredsample[].namestring | nullrequiredsample[].var1string | nullrequiredsample[].var2string | nullrequiredsample[].var3string | nullrequiredsample[].var4string | nullrequiredsample[].var5string | nullrequiredsample[].group_idstring | nullrequiredsample[].tagsarray of stringrequiredsample[].attrsobjectrequiredCustom attributes (attr.<key>in segments and message tokens)sample[].created_atintegerrequiredsample[].updated_atintegerrequired
curl -X POST "https://api.chatkomodo.com/v1/crm/segments/preview" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filter": {
"match": "any",
"rules": [
{
"field": "created",
"op": "within_days",
"value": 30
}
]
},
"limit": 10
}'const res = await fetch('https://api.chatkomodo.com/v1/crm/segments/preview', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"filter": {
"match": "any",
"rules": [
{
"field": "created",
"op": "within_days",
"value": 30
}
]
},
"limit": 10
}),
});
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/crm/segments/preview",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"filter": {
"match": "any",
"rules": [
{
"field": "created",
"op": "within_days",
"value": 30,
},
],
},
"limit": 10,
},
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/crm/segments/preview', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'filter' => [
'match' => 'any',
'rules' => [
[
'field' => 'created',
'op' => 'within_days',
'value' => 30,
],
],
],
'limit' => 10,
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"count": 12,
"sample": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"phone": "+447700900123",
"name": "VIP customers",
"var1": "string",
"var2": "string",
"var3": "string",
"var4": "string",
"var5": "string",
"group_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"tags": [
"vip"
],
"attrs": {},
"created_at": 1767225600000,
"updated_at": 1767225600000
}
]
}Update a segment
/v1/crm/segments/{id}Rename a segment and/or change its filter.
Path parameters
idstringrequired
Request body
namestringfilterobjectfilter.matchstringrequiredall= AND,any= ORfilter.rulesarray of objectrequiredfilter.rules[].fieldstringrequiredname,phone,group,tag,consent,createdorattr.<key>filter.rules[].opstringrequiredWhich operators apply depends on the field: text fields take is/is_not/contains/not_contains/starts_with/empty/not_empty;tagtakes has/not_has/has_any; dates take before/after/within_days; numbers also gt/gte/lt/ltefilter.rules[].valuestring | number | array of string
Responses
- 200Updated
Response fields
idstringrequirednamestringrequiredfilterobjectrequiredfilter.matchstringrequiredall= AND,any= ORfilter.rulesarray of objectrequiredfilter.rules[].fieldstringrequiredname,phone,group,tag,consent,createdorattr.<key>filter.rules[].opstringrequiredWhich operators apply depends on the field: text fields take is/is_not/contains/not_contains/starts_with/empty/not_empty;tagtakes has/not_has/has_any; dates take before/after/within_days; numbers also gt/gte/lt/ltefilter.rules[].valuestring | number | array of stringcountinteger | nullNumber of matching contacts (list only; cached for about a minute).nullwhile it has not been counted yetcount_pendingbooleantruewhencountisnullbecause the count is still being computed: only a few segments are counted per call, ask again shortlycreated_atintegerrequiredupdated_atintegerrequired
- 404Segment not found
curl -X PUT "https://api.chatkomodo.com/v1/crm/segments/ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "VIP customers",
"filter": {
"match": "all",
"rules": [
{
"field": "tag",
"op": "has",
"value": "vip"
}
]
}
}'const res = await fetch('https://api.chatkomodo.com/v1/crm/segments/ID', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "VIP customers",
"filter": {
"match": "all",
"rules": [
{
"field": "tag",
"op": "has",
"value": "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/crm/segments/ID",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "VIP customers",
"filter": {
"match": "all",
"rules": [
{
"field": "tag",
"op": "has",
"value": "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/crm/segments/ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'VIP customers',
'filter' => [
'match' => 'all',
'rules' => [
[
'field' => 'tag',
'op' => 'has',
'value' => 'vip',
],
],
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "VIP customers",
"filter": {
"match": "all",
"rules": [
{
"field": "tag",
"op": "is",
"value": "vip"
}
]
},
"count": 12,
"count_pending": true,
"created_at": 1767225600000,
"updated_at": 1767225600000
}Delete a segment
/v1/crm/segments/{id}Delete a segment (its contacts are not touched).
Path parameters
idstringrequired
Responses
- 200Deleted
Response fields
okbooleanrequired
- 404Segment not found
curl -X DELETE "https://api.chatkomodo.com/v1/crm/segments/ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/crm/segments/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/crm/segments/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/crm/segments/ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}List the contacts of a segment
/v1/crm/segments/{id}/contactsThe contacts currently matching a segment.
Path parameters
idstringrequired
Query parameters
limitinteger | nulloffsetinteger | null
Responses
- 200Contacts
Response fields
totalintegerrequiredcontactsarray 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_atintegerrequired
- 404Segment not found
curl "https://api.chatkomodo.com/v1/crm/segments/ID/contacts" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/crm/segments/ID/contacts', {
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/crm/segments/ID/contacts",
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/crm/segments/ID/contacts', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"total": 12,
"contacts": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"phone": "+447700900123",
"name": "VIP customers",
"var1": "string",
"var2": "string",
"var3": "string",
"var4": "string",
"var5": "string",
"group_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"tags": [
"vip"
],
"attrs": {},
"created_at": 1767225600000,
"updated_at": 1767225600000
}
]
}Get the contact card of a number
/v1/crm/contacts/by-phone/{phone}The contact card of one number (used by the inbox sidebar): the saved contact, if any, and its consent state.
Path parameters
phonestringrequiredInternational format+<country code><number>(URL-encode the+)
Responses
- 200Contact card
Response fields
phonestringrequiredcontactobject | nullrequiredcontact.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_atintegerrequiredconsentobject | nullrequiredconsent.statusstringrequiredconsent.sourcestringrequiredconsent.updated_atintegerrequired
- 400
INVALID_NUMBER
curl "https://api.chatkomodo.com/v1/crm/contacts/by-phone/447700900123" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/crm/contacts/by-phone/447700900123', {
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/crm/contacts/by-phone/447700900123",
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/crm/contacts/by-phone/447700900123', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"phone": "+447700900123",
"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
},
"consent": {
"status": "opted_in",
"source": "string",
"updated_at": 1767225600000
}
}Create or update a contact by number
/v1/crm/contacts/by-phone/{phone}Create or update the contact for a number (upsert). tags replaces, add_tags / remove_tags modify. For attrs, an empty string removes a key; values are strings of up to 500 characters and typed attributes are validated against the field definitions.
Path parameters
phonestringrequiredInternational format+<country code><number>(URL-encode the+)
Request body
namestring | nullgroup_idstring | nulltagsarray of stringadd_tagsarray of stringremove_tagsarray of stringattrsobject
Responses
- 200Existing contact updated
Response fields
createdbooleanrequiredcontactobjectrequiredcontact.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
- 201Contact created
Response fields
createdbooleanrequiredcontactobjectrequiredcontact.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
- 400Validation error
curl -X PUT "https://api.chatkomodo.com/v1/crm/contacts/by-phone/447700900123" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Sam Carter",
"add_tags": [
"vip"
],
"attrs": {
"plan": "Pro"
}
}'const res = await fetch('https://api.chatkomodo.com/v1/crm/contacts/by-phone/447700900123', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Sam Carter",
"add_tags": [
"vip"
],
"attrs": {
"plan": "Pro"
}
}),
});
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/crm/contacts/by-phone/447700900123",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "Sam Carter",
"add_tags": [
"vip",
],
"attrs": {
"plan": "Pro",
},
},
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/crm/contacts/by-phone/447700900123', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'Sam Carter',
'add_tags' => [
'vip',
],
'attrs' => [
'plan' => 'Pro',
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"created": false,
"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
}
}