. Create an API key under API keys.API reference · Conversations
Agents & assignment
Customer-service agents who work the shared inbox, the queue of unassigned chats, assignment and resolving.
List customer-service agents
/v1/cs/agentsAgents of the tenant, ordered by name. Secrets (access code hash, authenticator secret) are never included.
Responses
- 200Agents
Response fields
agentsarray of objectrequiredagents[].idstringrequiredagents[].api_key_idstringrequiredOwning tenantagents[].namestringrequiredagents[].rolestringrequiredStored as given at creation (defaultagent)agents[].is_onlineintegerrequired1 or 0agents[].max_chatsinteger | nullrequiredConcurrent chat capagents[].active_chatsinteger | nullrequiredChats currently assigned and unresolvedagents[].created_atintegerrequiredUnix time in millisecondsagents[].phonestring | nullrequiredLogin number, digits with country codeagents[].has_access_codebooleanrequiredWhether an access code is set. The code and its hash are never returned
- 401Missing, invalid or expired credentials
curl "https://api.chatkomodo.com/v1/cs/agents" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/cs/agents', {
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/cs/agents",
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/cs/agents', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"agents": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"api_key_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"name": "Sam Carter",
"role": "agent",
"is_online": 1,
"max_chats": 1,
"active_chats": 1,
"created_at": 1767225600000,
"phone": "+447700900123",
"has_access_code": true
}
]
}Create a customer-service agent
/v1/cs/agentsDashboard loginAdds an agent who can sign in to the dashboard and work the shared inbox. An agent signs in with a WhatsApp number plus one-time code (phone), or with an access_code. The phone number must not already belong to another agent or to a tenant owner login.
Request body
namestringrequiredDisplay name; must contain a non-blank valuerolestringStored as given (defaultagent)max_chatsintegerConcurrent chat cap (default 10)access_codestringOptional login code. Stored only as a salted hash and never returnedphonestringWhatsApp number used for one-time-code login; international format, or local format resolved against the business country
Responses
- 201Created
Response fields
idstringrequiredphonestring | nullrequiredNormalised login number (digits), or null when none was given
- 400
nameis missing or blank (VALIDATION_FAILED) - 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) - 409The number is already used by another account (
PHONE_IN_USE)
curl -X POST "https://api.chatkomodo.com/v1/cs/agents" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Sam Carter",
"phone": "+447700900123",
"max_chats": 10
}'const res = await fetch('https://api.chatkomodo.com/v1/cs/agents', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Sam Carter",
"phone": "+447700900123",
"max_chats": 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/cs/agents",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "Sam Carter",
"phone": "+447700900123",
"max_chats": 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/cs/agents', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'Sam Carter',
'phone' => '+447700900123',
'max_chats' => 10,
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"phone": "+447700900123"
}Edit a customer-service agent
/v1/cs/agents/{id}Changes the name, online flag, chat cap and/or access code of one of the tenant's agents. Send only the fields to change. An id that does not exist (or belongs to another tenant) changes nothing but still returns ok: true. The phone number cannot be changed here.
Path parameters
idstringrequiredAgent id
Request body
namestringis_onlinebooleanmax_chatsintegerConcurrent chat capaccess_codestringNew login code (ignored when empty). Stored only as a salted hash
Responses
- 200Updated
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)
curl -X PATCH "https://api.chatkomodo.com/v1/cs/agents/ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Sam Carter",
"is_online": true,
"max_chats": 1,
"access_code": "482913"
}'const res = await fetch('https://api.chatkomodo.com/v1/cs/agents/ID', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Sam Carter",
"is_online": true,
"max_chats": 1,
"access_code": "482913"
}),
});
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/cs/agents/ID",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"name": "Sam Carter",
"is_online": True,
"max_chats": 1,
"access_code": "482913",
},
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/cs/agents/ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'name' => 'Sam Carter',
'is_online' => true,
'max_chats' => 1,
'access_code' => '482913',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Delete a customer-service agent
/v1/cs/agents/{id}Deletes the agent. Chats assigned to them become unassigned.
Path parameters
idstringrequiredAgent 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) - 404Agent not found (no
code)
curl -X DELETE "https://api.chatkomodo.com/v1/cs/agents/ID" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/cs/agents/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/cs/agents/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/cs/agents/ID', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Sign an agent out everywhere
/v1/cs/agents/{id}/revoke-sessionsDeletes all refresh tokens of the agent so they can no longer renew their login. An access token that was already issued stays valid until it expires. Recorded in the audit log as agent.revoke_sessions.
Path parameters
idstringrequiredAgent id
Responses
- 200Revoked
Response fields
okbooleanrequiredrevokedintegerrequiredNumber of refresh tokens deleted
- 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) - 404Agent not found (no
code)
curl -X POST "https://api.chatkomodo.com/v1/cs/agents/ID/revoke-sessions" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/cs/agents/ID/revoke-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/cs/agents/ID/revoke-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/cs/agents/ID/revoke-sessions', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true,
"revoked": 1
}List unassigned open chats
/v1/cs/queueOpen chats on the tenant's devices that no agent is assigned to yet, most recent activity first. Available to agents as well as the owner.
Responses
- 200Queue
Response fields
queuearray of objectrequiredqueue[].idstringrequiredqueue[].session_idstringrequiredqueue[].chat_idstringrequiredqueue[].chat_namestring | nullrequiredqueue[].last_messagestring | nullrequiredqueue[].last_message_atinteger | nullrequiredqueue[].unread_countinteger | nullrequiredqueue[].is_groupinteger | nullrequired1 = group chatqueue[].agent_idany | nullrequiredAlways null in the queuequeue[].statusstringrequiredopen
- 401Missing, invalid or expired credentials
curl "https://api.chatkomodo.com/v1/cs/queue" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/cs/queue', {
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/cs/queue",
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/cs/queue', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"queue": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"session_id": "YOUR_DEVICE_ID",
"chat_id": "+447700900123",
"chat_name": "string",
"last_message": "Hi Sam, your order has shipped.",
"last_message_at": 1767225600000,
"unread_count": 12,
"is_group": 1,
"agent_id": null,
"status": "active"
}
]
}Assign a chat to an agent
/v1/cs/assignAssigns a chat to one of the tenant's agents (replacing any earlier assignment) and updates the agent's active-chat count. Available to agents as well as the owner. The body is not validated beyond ownership of agent_id and session_id.
Request body
chat_idstringrequiredChat JIDsession_idstringrequiredDevice the chat belongs toagent_idstringrequiredAgent to assign
Responses
- 200Assigned
Response fields
okbooleanrequired
- 401Missing, invalid or expired credentials
- 403The agent or the device is not the tenant's (message
Forbidden, nocode)
curl -X POST "https://api.chatkomodo.com/v1/cs/assign" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"session_id": "YOUR_DEVICE_ID",
"chat_id": "[email protected]",
"agent_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X"
}'const res = await fetch('https://api.chatkomodo.com/v1/cs/assign', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"session_id": "YOUR_DEVICE_ID",
"chat_id": "[email protected]",
"agent_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/cs/assign",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"session_id": "YOUR_DEVICE_ID",
"chat_id": "[email protected]",
"agent_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/cs/assign', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'session_id' => 'YOUR_DEVICE_ID',
'chat_id' => '[email protected]',
'agent_id' => '01JA5V6Q8M2H7G4K9P3T0R1S2X',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Mark a chat as resolved
/v1/cs/resolveMarks a chat resolved, which removes it from the open queue, and frees one slot of the assigned agent. Available to agents as well as the owner.
Request body
chat_idstringrequiredChat JIDsession_idstringrequiredDevice the chat belongs to
Responses
- 200Resolved
Response fields
okbooleanrequired
- 401Missing, invalid or expired credentials
- 403The device is not the tenant's (message
Forbidden, nocode)
curl -X POST "https://api.chatkomodo.com/v1/cs/resolve" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"session_id": "YOUR_DEVICE_ID",
"chat_id": "[email protected]"
}'const res = await fetch('https://api.chatkomodo.com/v1/cs/resolve', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"session_id": "YOUR_DEVICE_ID",
"chat_id": "[email protected]"
}),
});
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/cs/resolve",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"session_id": "YOUR_DEVICE_ID",
"chat_id": "[email protected]",
},
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/cs/resolve', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'session_id' => 'YOUR_DEVICE_ID',
'chat_id' => '[email protected]',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}