. Create an API key under API keys.API reference · Messaging
Messages
Send every kind of WhatsApp message, read the message history, retry, cancel, edit, react and unsend. See the sending guide for message types, statuses and pacing.
List message history
/v1/sessions/{sessionId}/messagesPaged history of the messages of a session, optionally filtered by chat, status, direction or text. Each page is ordered oldest first; to go further back pass next_cursor as cursor. Error texts are PII-redacted (numbers, JIDs, e-mail addresses) and cut to 160 characters.
Path parameters
sessionIdstringrequiredSession (device) id
Query parameters
chat_idstringOnly this chat (exact JID)limitintegerPage size. Values outside 1-200 are clamped, not rejectedcursornumbercreated_atof the oldest message already seen; returns older messages onlystatusstringFilter by status; unknown values are ignoreddirectionstringFilter by direction; other values are ignoredqstringSubstring to find in the message text (first 200 characters are used)
Responses
- 200A page of messages
Response fields
messagesarray of objectrequiredOldest firstmessages[].idstringrequiredGateway message id (ULID)messages[].directionstringrequiredmessages[].chat_idstringrequiredChat JIDmessages[].message_typestringrequiredtext,image,video,document,audio,sticker,location,poll,contactorreactionmessages[].bodystring | nullrequiredText content, if anymessages[].media_r2_keystring | nullrequiredKey of the stored media file; download it withGET /v1/sessions/{sessionId}/messages/{id}/mediamessages[].statusstringrequiredqueued,sent,delivered,read,failed,cancelledordeletedmessages[].created_atintegerrequiredCreation time (Unix epoch, milliseconds)messages[].wa_message_idstring | nullrequiredWhatsApp message id; null until the message was handed to WhatsAppmessages[].sent_atinteger | nullrequiredTime the message was handed to WhatsApp (Unix epoch, milliseconds)messages[].errorstring | nullrequiredFailure reason of a failed messagehas_morebooleanrequiredtruewhen the page is full, so older messages may existnext_cursorinteger | nullrequiredcreated_atof the oldest message in the page (Unix epoch, milliseconds): pass it ascursorfor the next page. Null for an empty page
- 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/messages?limit=50&status=failed" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages?limit=50&status=failed', {
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/messages?limit=50&status=failed",
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/messages?limit=50&status=failed', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"messages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"direction": "inbound",
"chat_id": "+447700900123",
"message_type": "Hi Sam, your order has shipped.",
"body": "Hi Sam, your order has shipped.",
"media_r2_key": "uploads/abc123.jpg",
"status": "active",
"created_at": 1767225600000,
"wa_message_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"sent_at": 1767225600000,
"error": "string"
}
],
"has_more": true,
"next_cursor": 1
}Send a message
/v1/sessions/{sessionId}/messagesSend a WhatsApp message via the given session. Supports text, media (image/video/document/audio/sticker), location, poll, and contact. If the recipient has opted out the message is still sent and the response carries a RECIPIENT_OPTED_OUT warning, unless the tenant enabled enforce_api in the consent config, in which case the call fails with 409 RECIPIENT_OPTED_OUT.
Path parameters
sessionIdstringrequired
Headers
Idempotency-KeystringAny unique string (an order id, a UUID). Repeating a send with the same key returns the first result withidempotent_replay: trueinstead of sending again. Keys are unique per business and kept with the message (message retention).
Request body
chat_idstringrequiredRecipient: a WhatsApp JID ([email protected], group…@g.us) or a phone number. Use the international format+<country code><number>(e.g.+44 7700 900123); a number in local format (07700 900123) is resolved against the business country from the profile, or againstcountry_codewhen given.typestringrequiredWhat to send; each type needs its own field:text→body;image,video,audio,document,sticker→media_r2_keyorurl;location→location;poll→poll_name+ 2–12choices;contact→contactbodystringText content. Required when type=textcaptionstringImage/video captionmedia_r2_keystringurlstring (uri)Public URL of the media to send instead ofmedia_r2_key(downloaded server-side, max 25 MB)filenamestringFile name of a media file sent fromurl(its extension decides the stored file type)locationobjectlocation.latnumberrequiredlocation.lngnumberrequiredpoll_namestringPoll question (type=poll)choicesarray of stringPoll choices, 2–12 (type=poll)contactobjectContact card sent as a vCard (type=contact)contact.namestringrequiredcontact.phonestringrequiredInternational formatreply_tostringULID of message to reply to (quoted reply)connect_onlybooleanDefaulttrue: refuse with 409CONFLICTwhile the device is not connected.false: accept and queue the message until the device reconnectscountry_codestringCalling code (1-4 digits, e.g.44) used only for local-format numbers; defaults to the business country.0never prefixes a code.
Responses
- 200Message accepted
Response fields
idstringrequiredstatusstringrequiredidempotent_replaybooleantruewhen an earlier request with the sameIdempotency-Keywas returned instead of sending againwarningsarray of objectNon-fatal notices, e.g.RECIPIENT_OPTED_OUT(the message was still accepted; seeenforce_apiin the consent config)warnings[].codestringrequiredwarnings[].messagestringrequired
- 400Validation error
- 403Session not owned by tenant
- 409Session not connected (
CONFLICT) or recipient opted out in strict mode (RECIPIENT_OPTED_OUT) - 429Rate limited
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chat_id": "+447700900123",
"type": "text",
"body": "Hi Sam, your order #1042 has shipped 🚚"
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"chat_id": "+447700900123",
"type": "text",
"body": "Hi Sam, your order #1042 has shipped 🚚"
}),
});
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/messages",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"chat_id": "+447700900123",
"type": "text",
"body": "Hi Sam, your order #1042 has shipped 🚚",
},
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/messages', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'chat_id' => '+447700900123',
'type' => 'text',
'body' => 'Hi Sam, your order #1042 has shipped 🚚',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"status": "queued",
"idempotent_replay": true,
"warnings": [
{
"code": "RECIPIENT_OPTED_OUT",
"message": "Hi Sam, your order has shipped."
}
]
}Search message text
/v1/sessions/{sessionId}/messages/searchSubstring search over the message bodies of one session, newest first. Matching is case-insensitive for ASCII letters; % and _ in q are literal.
Path parameters
sessionIdstringrequiredSession (device) id
Query parameters
qstringrequiredText to search for (required, trimmed)chat_idstringOnly this chat (exact JID)directionstringOther values are ignoredlimitintegerValues outside 1-200 are clamped
Responses
- 200Matches
Response fields
messagesarray of objectrequiredNewest firstmessages[].idstringrequiredGateway message id (ULID)messages[].directionstringrequiredmessages[].chat_idstringrequiredChat JIDmessages[].message_typestringrequiredtext,image,video,document,audio,sticker,location,poll,contactorreactionmessages[].bodystring | nullrequiredText content, if anymessages[].media_r2_keystring | nullrequiredKey of the stored media file; download it withGET /v1/sessions/{sessionId}/messages/{id}/mediamessages[].statusstringrequiredqueued,sent,delivered,read,failed,cancelledordeletedmessages[].created_atintegerrequiredCreation time (Unix epoch, milliseconds)countintegerrequired
- 400
qis missing or empty (INVALID) - 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/messages/search?q=string" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/search?q=string', {
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/messages/search?q=string",
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/messages/search?q=string', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"messages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"direction": "inbound",
"chat_id": "+447700900123",
"message_type": "Hi Sam, your order has shipped.",
"body": "Hi Sam, your order has shipped.",
"media_r2_key": "uploads/abc123.jpg",
"status": "active",
"created_at": 1767225600000
}
],
"count": 12
}Get a message with its surroundings
/v1/sessions/{sessionId}/messages/{id}/contextReturns the message together with the messages around it from the same chat, oldest first. Messages with exactly the same timestamp as the anchor are left out.
Path parameters
sessionIdstringrequiredSession (device) ididstringrequiredGateway message id (theidof a message in the history)
Query parameters
beforeintegerMessages before the anchor (default 10, clamped to 0-50)afterintegerMessages after the anchor (default 10, clamped to 0-50)
Responses
- 200Anchor message and neighbours
Response fields
chat_idstringrequiredmessagesarray of objectrequiredOldest first, including the anchormessages[].idstringrequiredGateway message id (ULID)messages[].directionstringrequiredmessages[].chat_idstringrequiredChat JIDmessages[].message_typestringrequiredtext,image,video,document,audio,sticker,location,poll,contactorreactionmessages[].bodystring | nullrequiredText content, if anymessages[].media_r2_keystring | nullrequiredKey of the stored media file; download it withGET /v1/sessions/{sessionId}/messages/{id}/mediamessages[].statusstringrequiredqueued,sent,delivered,read,failed,cancelledordeletedmessages[].created_atintegerrequiredCreation time (Unix epoch, milliseconds)
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Message not found (
NOT_FOUND); unknown session, or a session of another tenant
curl "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/ID/context" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/ID/context', {
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/messages/ID/context",
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/messages/ID/context', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"chat_id": "+447700900123",
"messages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"direction": "inbound",
"chat_id": "+447700900123",
"message_type": "Hi Sam, your order has shipped.",
"body": "Hi Sam, your order has shipped.",
"media_r2_key": "uploads/abc123.jpg",
"status": "active",
"created_at": 1767225600000
}
]
}Download stored media
/v1/sessions/{sessionId}/messages/{id}/mediaReturns the media file stored for a message as raw bytes. The response is always application/octet-stream; the original MIME type is not sent.
Path parameters
sessionIdstringrequiredSession (device) ididstringrequiredGateway message id (theidof a message in the history)
Responses
- 200The media file (
application/octet-stream) - 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Message not found, the message has no media, or the file is gone (
NOT_FOUND); unknown session, or a session of another tenant
curl "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/ID/media" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/ID/media', {
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/messages/ID/media",
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/messages/ID/media', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));application/octet-stream — the file itself.
Cancel queued messages
/v1/sessions/{sessionId}/messages/cancelMarks messages that are still queued as cancelled and removes them from the send queue. Messages in any other status are left alone; duplicate ids are ignored.
Path parameters
sessionIdstringrequiredSession (device) id
Request body
idsarray of stringrequiredGateway message ids
Responses
- 200Result
Response fields
cancelledintegerrequiredMessages that were actually cancelled
- 400Invalid body (
VALIDATION_FAILED,INVALID_JSON) - 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
- 429Strict rate limit exceeded: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/cancel" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
"01JA5V6Q8M2H7G4K9P3T0R1S2X"
]
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/cancel', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": [
"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/sessions/YOUR_DEVICE_ID/messages/cancel",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"ids": [
"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/sessions/YOUR_DEVICE_ID/messages/cancel', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'ids' => [
'01JA5V6Q8M2H7G4K9P3T0R1S2X',
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"cancelled": 1
}Delete messages from history
/v1/sessions/{sessionId}/messages/deleteRemoves messages from the stored history and from the send queue. Nothing is unsent on WhatsApp; use /messages/unsend for that.
Path parameters
sessionIdstringrequiredSession (device) id
Request body
idsarray of stringrequiredGateway message ids
Responses
- 200Result
Response fields
deletedintegerrequiredHistory rows removed
- 400Invalid body (
VALIDATION_FAILED,INVALID_JSON) - 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
- 429Strict rate limit exceeded: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/delete" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
"01JA5V6Q8M2H7G4K9P3T0R1S2X"
]
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/delete', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": [
"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/sessions/YOUR_DEVICE_ID/messages/delete",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"ids": [
"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/sessions/YOUR_DEVICE_ID/messages/delete', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'ids' => [
'01JA5V6Q8M2H7G4K9P3T0R1S2X',
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"deleted": 1
}Unsend messages for everyone
/v1/sessions/{sessionId}/messages/unsendRevokes your own sent messages on WhatsApp ("delete for everyone") and marks them deleted in the history. Each id is processed on its own and the call answers 200 even if some fail: check results[].error.
Path parameters
sessionIdstringrequiredSession (device) id
Request body
idsarray of stringrequiredGateway message ids
Responses
- 200Per-message result
Response fields
unsentintegerrequiredfailedintegerrequiredresultsarray of objectrequiredresults[].idstringrequiredresults[].okbooleanrequiredresults[].errorstringnot_found: unknown id;not_sent: inbound message or not yet handed to WhatsApp;not_connected: session offline;wa_error: WhatsApp refused
- 400Invalid body (
VALIDATION_FAILED,INVALID_JSON) - 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
- 429Strict rate limit exceeded: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/unsend" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
"01JA5V6Q8M2H7G4K9P3T0R1S2X"
]
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/unsend', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": [
"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/sessions/YOUR_DEVICE_ID/messages/unsend",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"ids": [
"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/sessions/YOUR_DEVICE_ID/messages/unsend', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'ids' => [
'01JA5V6Q8M2H7G4K9P3T0R1S2X',
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"unsent": 12,
"failed": 1,
"results": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"ok": true,
"error": "not_found"
}
]
}Forward a message to another chat
/v1/sessions/{sessionId}/messages/{msgId}/forwardSends the stored type, text and media key of a logged message to another chat as a new message. It goes through the same opt-out check as POST /messages: an opted-out recipient yields a RECIPIENT_OPTED_OUT warning, or a 409 when strict mode (enforce_api) is on.
Path parameters
sessionIdstringrequiredSession (device) idmsgIdstringrequiredGateway message id to forward
Request body
to_chat_idstringrequiredDestination: a JID or a phone number (local-format numbers are resolved against the business country)
Responses
- 200Forwarded
Response fields
message_idstringrequiredId of the new messageokbooleanrequiredwarningsarray of objectPresent when the recipient has opted out (RECIPIENT_OPTED_OUT): the message was still accepted because strict mode (enforce_api) is offwarnings[].codestringrequiredwarnings[].messagestringrequired
- 400
to_chat_idmissing (VALIDATION_FAILED), or invalid (INVALID_NUMBER,INVALID_JID) - 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404The message was not found in this session (no
code); unknown session, or a session of another tenant - 409The session is not connected, or the recipient opted out in strict mode (
RECIPIENT_OPTED_OUT) - 429Strict rate limit exceeded: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED) - 500Sending or the WhatsApp call failed (
codeis usuallyINTERNAL)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/forward" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to_chat_id": "+12025550123"
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/forward', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"to_chat_id": "+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/messages/MSG_ID/forward",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"to_chat_id": "+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/messages/MSG_ID/forward', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'to_chat_id' => '+12025550123',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"message_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"ok": true,
"warnings": [
{
"code": "RECIPIENT_OPTED_OUT",
"message": "Hi Sam, your order has shipped."
}
]
}Resend an outbound message
/v1/sessions/{sessionId}/messages/{msgId}/retrySends a logged outbound message again as a new message with a new id. Only text, image, document, audio, video and sticker messages that still have their content can be retried. The same opt-out check as POST /messages applies, and the send is paced like any other.
Path parameters
sessionIdstringrequiredSession (device) idmsgIdstringrequiredGateway message id to resend
Responses
- 200Resend accepted
Response fields
message_idstringrequiredId of the new messagestatusstringrequiredsent,queued(paced),blocked(recipient on the session blocklist) orquota_exceeded(monthly plan quota used up)warningsarray of objectPresent when the recipient has opted out (RECIPIENT_OPTED_OUT): the message was still accepted because strict mode (enforce_api) is offwarnings[].codestringrequiredwarnings[].messagestringrequired
- 400The message is inbound, of an unsupported type or has no content (
NOT_RETRYABLE) - 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Message not found (
NOT_FOUND); unknown session, or a session of another tenant - 409The session is not connected (
CONFLICT), or the recipient opted out in strict mode (RECIPIENT_OPTED_OUT) - 429Strict rate limit exceeded: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED) - 500Sending or the WhatsApp call failed (
codeis usuallyINTERNAL)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/retry" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/retry', {
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/messages/MSG_ID/retry",
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/messages/MSG_ID/retry', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"message_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"status": "active",
"warnings": [
{
"code": "RECIPIENT_OPTED_OUT",
"message": "Hi Sam, your order has shipped."
}
]
}Delete a sent message for everyone
/v1/sessions/{sessionId}/messages/{msgId}/deleteRevokes one of your sent messages on WhatsApp and marks it deleted in the history. The message must already have a WhatsApp id, i.e. it was handed to WhatsApp.
Path parameters
sessionIdstringrequiredSession (device) idmsgIdstringrequiredGateway message id (theidof a message in the history)
Responses
- 200Revoked
Response fields
okbooleanrequired
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Message not found, or it has no WhatsApp id yet; unknown session, or a session of another tenant
- 409The session is not connected
- 429Strict rate limit exceeded: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED) - 500Sending or the WhatsApp call failed (
codeis usuallyINTERNAL)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/delete" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/delete', {
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/messages/MSG_ID/delete",
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/messages/MSG_ID/delete', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Edit a sent message
/v1/sessions/{sessionId}/messages/{msgId}/editReplaces the text of one of your sent messages on WhatsApp and updates the stored body. msgId is the gateway message id; the message must already have a WhatsApp id.
Path parameters
sessionIdstringrequiredSession (device) idmsgIdstringrequiredGateway message id (theidof a message in the history)
Request body
bodystringrequiredNew text
Responses
- 200Edited
Response fields
okbooleanrequired
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Message not found, or it has no WhatsApp id yet; unknown session, or a session of another tenant
- 409The session is not connected
- 429Strict rate limit exceeded: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED) - 500Sending or the WhatsApp call failed (
codeis usuallyINTERNAL)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/edit" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"body": "Hi Sam, your order has shipped."
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/edit', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"body": "Hi Sam, your order has shipped."
}),
});
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/messages/MSG_ID/edit",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"body": "Hi Sam, your order has shipped.",
},
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/messages/MSG_ID/edit', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'body' => 'Hi Sam, your order has shipped.',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Edit a message by WhatsApp id
/v1/sessions/{sessionId}/messages/{msgId}/editEdits a message addressed by its WhatsApp message id instead of the gateway id. Unlike POST …/messages/{msgId}/edit it does not look the message up and does not update the stored history.
Path parameters
sessionIdstringrequiredSession (device) idmsgIdstringrequiredWhatsApp message id (wa_message_id), not the gateway id
Request body
chat_idstringrequiredJID of the chat the message is innew_textstringrequiredNew text
Responses
- 200Edited
Response fields
okbooleanrequired
- 400The body is not valid JSON
- 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
- 500
WhatsApp operation failed: WhatsApp or the library rejected the call. The gateway does not validate this body, so missing or malformed fields end up here too
curl -X PUT "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/edit" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chat_id": "+447700900123",
"new_text": "Hi Sam, your order has shipped."
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/edit', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"chat_id": "+447700900123",
"new_text": "Hi Sam, your order has shipped."
}),
});
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/messages/MSG_ID/edit",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"chat_id": "+447700900123",
"new_text": "Hi Sam, your order has shipped.",
},
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/messages/MSG_ID/edit', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'chat_id' => '+447700900123',
'new_text' => 'Hi Sam, your order has shipped.',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}React to a message
/v1/sessions/{sessionId}/messages/{msgId}/reactSends an emoji reaction to a message through the normal send pipeline. msgId may be the gateway id or the WhatsApp id of the message.
Path parameters
sessionIdstringrequiredSession (device) idmsgIdstringrequiredGateway message id or WhatsApp message id
Request body
emojistringReaction emoji; defaults to 👍 when omitted
Responses
- 200Reaction sent
Response fields
okbooleanrequired
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Message not found; unknown session, or a session of another tenant
- 409The session is not connected
- 429Strict rate limit exceeded: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/react" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"emoji": "👍"
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/react', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"emoji": "👍"
}),
});
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/messages/MSG_ID/react",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"emoji": "👍",
},
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/messages/MSG_ID/react', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'emoji' => '👍',
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Mark a message as read
/v1/sessions/{sessionId}/messages/{msgId}/readSends a read receipt for the message to WhatsApp. The local unread counter of the inbox is not changed; use POST …/inbox/{chatId}/read for that.
Path parameters
sessionIdstringrequiredSession (device) idmsgIdstringrequiredGateway message id (theidof a message in the history)
Responses
- 200Read receipt sent
Response fields
okbooleanrequired
- 401Missing or invalid credentials
- 403The API key is restricted to other sessions
- 404Message not found, or it has no WhatsApp id yet; unknown session, or a session of another tenant
- 409The session is not connected
- 429Strict rate limit exceeded: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED) - 500Sending or the WhatsApp call failed (
codeis usuallyINTERNAL)
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/read" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/MSG_ID/read', {
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/messages/MSG_ID/read",
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/messages/MSG_ID/read', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Send a buttons or list message
/v1/sessions/{sessionId}/messages/interactiveSends a button or list message straight through the WhatsApp connection. Unlike POST /messages it is not queued or paced, not written to the message history and not checked against the opt-out list, and chat_id must already be a JID. A type other than buttons or list sends nothing but still answers 200.
Path parameters
sessionIdstringrequiredSession (device) id
Request body
chat_idstringrequiredRecipient JIDtypestringrequiredbodystringrequiredMessage textfooterstringbuttonsarray of objectForbuttons: the buttons, in order (button ids are generated asbtn_0,btn_1, …)buttons[].textstringrequiredButton labeltitlestringForlist: list titlesectionsarray of objectForlist: sections with rows, passed unchanged to the WhatsApp library. The list button is labelledMenusections[].titlestringsections[].rowsarray of objectrequiredsections[].rows[].titlestringrequiredsections[].rows[].rowIdstringrequiredsections[].rows[].descriptionstring
Responses
- 200Accepted
Response fields
okbooleanrequired
- 400The body is not valid JSON
- 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: the plan's send rate per minute per API key (
send_per_minuteinGET /v1/usage; 30 on the Free plan), shared with every other POST whose path containsmessages, includingPOST /messages. The response carriesRetry-After(seconds) andretry_after(RATE_LIMITED) - 500
WhatsApp operation failed: WhatsApp or the library rejected the call. The gateway does not validate this body, so missing or malformed fields end up here too
curl -X POST "https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/interactive" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chat_id": "+447700900123",
"type": "buttons",
"body": "Your order #1042 is ready. What next?",
"footer": "Acme Store",
"buttons": [
{
"text": "Track my order"
},
{
"text": "Talk to us"
}
]
}'const res = await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages/interactive', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"chat_id": "+447700900123",
"type": "buttons",
"body": "Your order #1042 is ready. What next?",
"footer": "Acme Store",
"buttons": [
{
"text": "Track my order"
},
{
"text": "Talk to us"
}
]
}),
});
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/messages/interactive",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"chat_id": "+447700900123",
"type": "buttons",
"body": "Your order #1042 is ready. What next?",
"footer": "Acme Store",
"buttons": [
{
"text": "Track my order",
},
{
"text": "Talk to us",
},
],
},
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/messages/interactive', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'chat_id' => '+447700900123',
'type' => 'buttons',
'body' => 'Your order #1042 is ready. What next?',
'footer' => 'Acme Store',
'buttons' => [
[
'text' => 'Track my order',
],
[
'text' => 'Talk to us',
],
],
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"ok": true
}Fetch a link preview
/v1/link-previewFetches an http(s) page (max 1 MB, 5 second timeout; private and internal addresses are refused and redirects are not followed) and extracts its Open Graph title, description and image, falling back to the <title>. If the page cannot be fetched, or the address is refused, the call still succeeds with null fields.
Query parameters
urlstringrequiredhttp or https URL to preview
Responses
- 200Preview
Response fields
urlstringrequiredtitlestring | nullrequireddescriptionstring | nullrequiredimagestring | nullrequiredImage URL, as found in the page
- 400
urlis missing, not a valid URL, or not http/https (nocode) - 401Missing, invalid or expired credentials
curl "https://api.chatkomodo.com/v1/link-preview?url=https%3A%2F%2Fexample.com%2Ffile.jpg" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/link-preview?url=https%3A%2F%2Fexample.com%2Ffile.jpg', {
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/link-preview?url=https%3A%2F%2Fexample.com%2Ffile.jpg",
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/link-preview?url=https%3A%2F%2Fexample.com%2Ffile.jpg', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"url": "https://example.com/file.jpg",
"title": "string",
"description": "Short description",
"image": "string"
}List messages across all devices
/v1/messagesMessage log of all the tenant's devices, newest first, filtered and paged with a cursor. Filters with an unrecognised value (direction, status) are ignored rather than rejected. Pass the returned next_cursor as cursor for the next page.
Query parameters
limitintegerValues outside 1-1 000 are clampedsincestringOnly messages created at or after this time: Unix ms or a date stringuntilstringOnly messages created before this time: Unix ms or a date stringsession_idstringOnly this devicedirectionstringstatusstringcursorstringOpaque cursor<created_at>:<id>from a previousnext_cursor
Responses
- 200Messages
Response fields
messagesarray of objectrequiredmessages[].idstringrequiredmessages[].session_idstringrequiredmessages[].chat_idstringrequiredmessages[].directionstringrequiredmessages[].message_typestringrequiredmessages[].statusstringrequiredmessages[].bodystring | nullrequiredmessages[].created_atintegerrequiredUnix time in millisecondsnext_cursorstring | nullrequirednull on the last page
- 401Missing, invalid or expired credentials
curl "https://api.chatkomodo.com/v1/messages?since=1767225600000&limit=1000" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/messages?since=1767225600000&limit=1000', {
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/messages?since=1767225600000&limit=1000",
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/messages?since=1767225600000&limit=1000', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));{
"messages": [
{
"id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
"session_id": "YOUR_DEVICE_ID",
"chat_id": "+447700900123",
"direction": "inbound",
"message_type": "Hi Sam, your order has shipped.",
"status": "active",
"body": "Hi Sam, your order has shipped.",
"created_at": 1767225600000
}
],
"next_cursor": "string"
}