. Create an API key under API keys.API reference · Messaging
Devices
A device is one WhatsApp number linked to ChatKomodo (shown as a session in the API: its id is the sessionId in the paths). Create one, scan its QR code from WhatsApp → Linked devices (or use a pairing code), then send through it. GET /v1/sessions lists them with their status.
List devices
/v1/sessionsList all WhatsApp devices for the calling tenant.
Responses
- 200List of sessions
Response fields
sessionsarray of objectrequiredsessions[].idstringrequiredULID identifiersessions[].statusstringrequiredpending(starting),qr_ready(waiting for a scan),connected,disconnected(was working, connection lost) orfailedsessions[].phone_numberstring | nullrequiredPaired WhatsApp number as digits with country code (no+), e.g.447700900123sessions[].wa_namestring | nullrequiredWhatsApp display name, read from the phone when it is linked (no need to type it)sessions[].wa_aboutstring | nullThe number's WhatsApp "About" text (bio), read after linking and refreshed whenever the profile is fetched.""= no About;null= not read yet or hidden by the phone's privacy settingssessions[].phone_displaystring | nullThe number in international format with its country code, e.g.+44 7700 900123sessions[].phone_countrystring | nullISO 3166-1 alpha-2 country of the number, e.g.GB(nullwhen unknown)sessions[].phone_country_codestring | nullCountry calling code with+, e.g.+44sessions[].api_key_idstringrequiredOwning tenantsessions[].warmup_until_msinteger | nullrequiredPacing until this timestamp (anti-ban)sessions[].created_atintegerrequiredsessions[].connected_atinteger | nullrequired
- 401Unauthorized
curl "https://api.chatkomodo.com/v1/sessions" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions', {
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",
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', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"sessions": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"status": "pending",
"phone_number": "+447700900123",
"wa_name": "string",
"wa_about": "string",
"phone_display": "+447700900123",
"phone_country": "+447700900123",
"phone_country_code": "+447700900123",
"api_key_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"warmup_until_ms": 1767225600000,
"created_at": 1767225600000,
"connected_at": 1767225600000
}
]
}Create a device
/v1/sessionsCreate a new WhatsApp device (session). Poll qr_polling_url for the QR code and scan it from WhatsApp, or link with a pairing code (POST /v1/sessions/{id}/pairing-code). Limited by the plan's device quota.
Responses
- 201Session created
Response fields
idstringrequiredstatusstringrequiredqr_polling_urlstringrequired
- 401Unauthorized
- 403Plan device limit reached
curl -X POST "https://api.chatkomodo.com/v1/sessions" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions', {
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",
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', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"status": "pending",
"qr_polling_url": "https://example.com/file.jpg"
}Get a device
/v1/sessions/{id}Get a single session by id.
Path parameters
idstringrequired
Responses
- 200Session detail
Response fields
idstringrequiredULID identifierstatusstringrequiredpending(starting),qr_ready(waiting for a scan),connected,disconnected(was working, connection lost) orfailedphone_numberstring | nullrequiredPaired WhatsApp number as digits with country code (no+), e.g.447700900123wa_namestring | nullrequiredWhatsApp display name, read from the phone when it is linked (no need to type it)wa_aboutstring | nullThe number's WhatsApp "About" text (bio), read after linking and refreshed whenever the profile is fetched.""= no About;null= not read yet or hidden by the phone's privacy settingsphone_displaystring | nullThe number in international format with its country code, e.g.+44 7700 900123phone_countrystring | nullISO 3166-1 alpha-2 country of the number, e.g.GB(nullwhen unknown)phone_country_codestring | nullCountry calling code with+, e.g.+44api_key_idstringrequiredOwning tenantwarmup_until_msinteger | nullrequiredPacing until this timestamp (anti-ban)created_atintegerrequiredconnected_atinteger | nullrequired
- 404Not found or not owned by tenant
curl "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID', {
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",
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', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"status": "pending",
"phone_number": "+447700900123",
"wa_name": "string",
"wa_about": "string",
"phone_display": "+447700900123",
"phone_country": "+447700900123",
"phone_country_code": "+447700900123",
"api_key_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"warmup_until_ms": 1767225600000,
"created_at": 1767225600000,
"connected_at": 1767225600000
}Delete a device
/v1/sessions/{id}Closes the live connection, deletes the stored WhatsApp credentials and removes the session together with its auto-reply rules, blast campaigns, blocklist entries and message history. The inbox and scheduled messages are left in place, and WhatsApp is not asked to unlink the device. This cannot be undone.
Path parameters
idstringrequiredSession (device) id
Responses
- 200Deleted
Response fields
okbooleanrequired
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions, or the operation is not available to CS-agent logins
- 404Unknown session, or a session of another tenant
curl -X DELETE "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_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/sessions/YOUR_DEVICE_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/sessions/YOUR_DEVICE_ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Get the current QR code
/v1/sessions/{sessionId}/qrReturns the QR payload for linking the device: render the qr string with any QR library and scan it from WhatsApp (Linked devices). A code lasts about 60 seconds; qr is null while none is available, so keep polling until status is qr_ready. Answers 410 once the device is connected.
Path parameters
sessionIdstringrequiredSession (device) id
Responses
- 200Current QR state
Response fields
qrstring | nullrequiredRaw QR payload string (not an image); null when there is no valid code right nowexpires_atinteger | nullrequiredExpiry of the code (Unix epoch, milliseconds)statusstringrequiredSession status:pending,qr_ready,connected,disconnectedorfailed
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Unknown session, or a session of another tenant
- 410The device is already connected (
error:Already connected)
curl "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/qr" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/qr', {
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/qr",
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/qr', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"qr": "string",
"expires_at": 1767225600000,
"status": "active"
}Get the WhatsApp profile of a device
/v1/sessions/{sessionId}/profileReturns the linked account: number, display name, picture, About text and, for Business accounts, the business profile and catalog. A connected device is queried live with a 10-second limit, and parts that do not answer in time come back null or empty (syncing: true marks a timed-out lookup). A device that is not connected returns the cached values with connected: false.
Path parameters
sessionIdstringrequiredSession (device) id
Responses
- 200Profile
Response fields
connectedbooleanrequiredsyncingbooleantruewhen the live lookup timed out and only partial data is returnedphone_numberstring | nullrequiredDigits with country code, no+wa_namestring | nullrequiredprofile_pic_urlstring | nullrequiredaboutstring | nullrequiredThe About / status textis_businessbooleanrequiredbusiness_profileobject | nullrequiredOnly for Business accountsbusiness_profile.descriptionstring | nullrequiredbusiness_profile.categorystring | nullrequiredbusiness_profile.emailstring | nullrequiredbusiness_profile.websitearray of anyrequiredbusiness_profile.addressstring | nullrequiredbusiness_profile.business_hoursarray of objectrequiredbusiness_profile.business_hours[].daystringrequiredbusiness_profile.business_hours[].modestringrequiredbusiness_profile.business_hours[].openstring | nullrequiredHH:MMbusiness_profile.business_hours[].closestring | nullrequiredHH:MMcatalogarray of objectrequiredVisible catalog products (Business accounts only; empty otherwise)catalog[].idstringrequiredcatalog[].namestringrequiredcatalog[].pricenumberrequiredcatalog[].currencystringrequiredcatalog[].descriptionstringrequiredcatalog[].imagestring | nullrequiredcatalog[].urlstring | nullrequired
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Unknown session, or a session of another tenant
curl "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/profile" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/profile', {
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/profile",
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/profile', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"connected": true,
"syncing": true,
"phone_number": "+447700900123",
"wa_name": "string",
"profile_pic_url": "https://example.com/file.jpg",
"about": "string",
"is_business": true,
"business_profile": {
"description": "Short description",
"category": "string",
"email": "[email protected]",
"website": [
"string"
],
"address": "string",
"business_hours": [
{
"day": "string",
"mode": "string",
"open": "string",
"close": "string"
}
]
},
"catalog": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Example",
"price": 150000,
"currency": "IDR",
"description": "Short description",
"image": "string",
"url": "https://example.com/file.jpg"
}
]
}Request a phone-number pairing code
/v1/sessions/{sessionId}/pairing-codeLinks the device with a code instead of a QR scan: enter the returned code on the phone (WhatsApp, Linked devices, Link with phone number). Needs a session that has a live connection manager, so create it with POST /v1/sessions or call /reconnect first.
Path parameters
sessionIdstringrequiredSession (device) id
Request body
phone_numberstringrequiredNumber of the WhatsApp account to link, with country code. Everything but digits is stripped; local-format numbers are not resolved
Responses
- 200Pairing code
Response fields
codestringrequiredCode to type on the phone
- 400
phone_numberis missing - 401Missing or invalid credentials
- 403The API key is restricted to other sessions, or the operation is not available to CS-agent logins
- 404No live connection manager for this session; unknown session, or a session of another tenant
- 500The library could not create a code;
errorcarries its message
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/pairing-code" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+447700900123"
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/pairing-code', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"phone_number": "+447700900123"
}),
});
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/pairing-code",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"phone_number": "+447700900123",
},
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/pairing-code', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'phone_number' => '+447700900123',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"code": "RECIPIENT_OPTED_OUT"
}Reconnect a device
/v1/sessions/{sessionId}/reconnectRestarts the WhatsApp connection of the session. With clear_creds: true the stored credentials are wiped first and the status goes back to pending, so the device has to be linked again (QR or pairing code); this flag only takes effect when the session already has a live connection manager. Poll GET /v1/sessions/{id} for the resulting status.
Path parameters
sessionIdstringrequiredSession (device) id
Request body
clear_credsbooleanWipe the stored WhatsApp credentials before reconnecting (default false)
Responses
- 200Reconnect started
Response fields
okbooleanrequired
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions, or the operation is not available to CS-agent logins
- 404Unknown session, or a session of another tenant
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/reconnect" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"clear_creds": true
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/reconnect', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"clear_creds": 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/sessions/YOUR_DEVICE_ID/reconnect",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"clear_creds": 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/sessions/YOUR_DEVICE_ID/reconnect', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'clear_creds' => true,
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Resync groups and chats
/v1/sessions/{sessionId}/syncRe-fetches the participating groups and the WhatsApp app-state (chats, contacts) and refreshes group names in the inbox; waits up to 15 seconds for the app-state part. contacts counts the one-to-one chats known in the inbox, not an address book.
Path parameters
sessionIdstringrequiredSession (device) id
Responses
- 200Sync finished
Response fields
groupsintegerrequiredGroups the account participates incontactsintegerrequiredDistinct one-to-one chats in the inbox
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Unknown session, or a session of another tenant
- 409The session is not connected (
NOT_CONNECTED) - 502The sync failed (
SYNC_FAILED)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/sync" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/sync', {
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/sync",
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/sync', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"groups": 1,
"contacts": 1
}Check numbers on WhatsApp
/v1/sessions/{sessionId}/validateChecks which of up to 1 000 numbers or JIDs have a WhatsApp account. Targets are normalised like recipients elsewhere (international format, or local format resolved against the business country or country_code); targets that cannot be normalised are dropped. If the lookup itself fails, every target is reported in not_registered. Limited to 10 calls per minute per key.
Path parameters
sessionIdstringrequiredSession (device) id
Request body
targetsarray of stringrequiredPhone numbers or JIDscountry_codestringCalling code (digits) used for local-format numbers; defaults to the business country
Responses
- 200Result
Response fields
registeredarray of stringrequiredJIDs that have a WhatsApp accountnot_registeredarray of stringrequiredNormalised JIDs that were not found
- 400
targetsis not an array of strings, or has more than 1 000 entries - 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Unknown session, or a session of another tenant
- 409The session is not connected
- 429Strict rate limit exceeded: 10 requests per minute (
RATE_LIMITED)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/validate" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"targets": [
"+447700900123",
"+12025550123"
]
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/validate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"targets": [
"+447700900123",
"+12025550123"
]
}),
});
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/validate",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"targets": [
"+447700900123",
"+12025550123",
],
},
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/validate', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'targets' => [
'+447700900123',
'+12025550123',
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"registered": [
"string"
],
"not_registered": [
"string"
]
}