Code samples use your device
. Create an API key under API keys.API reference · Customers
Consent
Who agreed to be messaged and who asked to stop. Replies such as STOP opt people out automatically; broadcasts skip them.
List consent records
GET
/v1/consentWho agreed to be messaged and who asked to stop, newest change first, with totals.
Query parameters
statusstringqstringPhone searchlimitintegerbeforeinteger | nullCursor: thenext_beforeof the previous pagebefore_idstringCursor tie-breaker: thenext_before_idof the previous page (send it together withbefore, otherwise records sharing one timestamp can be skipped)
Responses
- 200Consent records
Response fields
summaryobjectrequiredsummary.opted_inintegerrequiredsummary.opted_outintegerrequiredconsentarray of objectrequiredconsent[].chat_idstringrequiredconsent[].phonestringrequiredDigits with country code (no+)consent[].statusstringrequiredconsent[].sourcestringrequiredHow the status was set: the customer replied with a keyword, a person in the dashboard, a contacts import withopt_in, an API key, or a privacy erasureconsent[].notestring | nullrequiredconsent[].created_atintegerrequiredconsent[].updated_atintegerrequirednext_beforeinteger | nullrequirednext_before_idstring | nullrequired
Request
curl "https://api.chatkomodo.com/v1/consent" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/consent', {
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/consent",
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/consent', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));Response 200
{
"summary": {
"opted_in": 1,
"opted_out": 1
},
"consent": [
{
"chat_id": "+447700900123",
"phone": "+447700900123",
"status": "opted_in",
"source": "keyword",
"note": "Prefers delivery after 5 pm",
"created_at": 1767225600000,
"updated_at": 1767225600000
}
],
"next_before": 1767225600000,
"next_before_id": "01JA5V6Q8M2H7G4K9P3T0R1S2X"
}Get the consent settings
GET
/v1/consent/configOpt-out keywords, confirmation replies and enforcement settings.
Responses
- 200Config
Response fields
enabledbooleanrequiredListen for opt-out / opt-in keywords in inbound messages (STOP,UNSUBSCRIBE,START, … in several languages)optout_keywordsarray of stringrequiredoptin_keywordsarray of stringrequiredoptout_replystring | nullrequirednull= default confirmation in the tenant language, empty string = send no confirmationoptin_replystring | nullrequiredenforce_apibooleanrequiredRefuse 1:1 sends to opted-out recipients with 409RECIPIENT_OPTED_OUT(default: send and return a warning)require_attestationbooleanrequiredRequireconsent_attested: truebefore a blast starts
Request
curl "https://api.chatkomodo.com/v1/consent/config" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/consent/config', {
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/consent/config",
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/consent/config', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));Response 200
{
"enabled": true,
"optout_keywords": [
"string"
],
"optin_keywords": [
"string"
],
"optout_reply": "Hi Sam, your order has shipped.",
"optin_reply": "Hi Sam, your order has shipped.",
"enforce_api": true,
"require_attestation": true
}Update the consent settings
PUT
/v1/consent/configDashboard loginUpdate the consent configuration (partial update). Account owner only.
Request body
enabledbooleanListen for opt-out / opt-in keywords in inbound messages (STOP,UNSUBSCRIBE,START, … in several languages)optout_keywordsarray of stringoptin_keywordsarray of stringoptout_replystring | nullnull= default confirmation in the tenant language, empty string = send no confirmationoptin_replystring | nullenforce_apibooleanRefuse 1:1 sends to opted-out recipients with 409RECIPIENT_OPTED_OUT(default: send and return a warning)require_attestationbooleanRequireconsent_attested: truebefore a blast starts
Responses
- 200Saved config
Response fields
enabledbooleanrequiredListen for opt-out / opt-in keywords in inbound messages (STOP,UNSUBSCRIBE,START, … in several languages)optout_keywordsarray of stringrequiredoptin_keywordsarray of stringrequiredoptout_replystring | nullrequirednull= default confirmation in the tenant language, empty string = send no confirmationoptin_replystring | nullrequiredenforce_apibooleanrequiredRefuse 1:1 sends to opted-out recipients with 409RECIPIENT_OPTED_OUT(default: send and return a warning)require_attestationbooleanrequiredRequireconsent_attested: truebefore a blast starts
- 403Not the account owner
Request
curl -X PUT "https://api.chatkomodo.com/v1/consent/config" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"optout_keywords": [
"stop",
"unsubscribe"
],
"enforce_api": true,
"require_attestation": true
}'const res = await fetch('https://api.chatkomodo.com/v1/consent/config', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"enabled": true,
"optout_keywords": [
"stop",
"unsubscribe"
],
"enforce_api": true,
"require_attestation": 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.put(
"https://api.chatkomodo.com/v1/consent/config",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"enabled": True,
"optout_keywords": [
"stop",
"unsubscribe",
],
"enforce_api": True,
"require_attestation": True,
},
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/consent/config', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'enabled' => true,
'optout_keywords' => [
'stop',
'unsubscribe',
],
'enforce_api' => true,
'require_attestation' => true,
],
]);
print_r(json_decode((string) $res->getBody(), true));Response 200
{
"enabled": true,
"optout_keywords": [
"string"
],
"optin_keywords": [
"string"
],
"optout_reply": "Hi Sam, your order has shipped.",
"optin_reply": "Hi Sam, your order has shipped.",
"enforce_api": true,
"require_attestation": true
}Export consent records (CSV)
GET
/v1/consent/exportDownload all consent records as CSV (phone,status,source,note,updated_at).
Responses
- 200CSV file
Request
curl "https://api.chatkomodo.com/v1/consent/export" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/consent/export', {
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/consent/export",
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/consent/export', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));Response 200
text/csv — the file itself.
Set consent for many numbers
POST
/v1/consent/bulkSet the consent status of up to 10 000 numbers at once (e.g. importing a suppression list).
Request body
phonesarray of stringrequiredstatusstringrequirednotestring | null
Responses
- 200Result
Response fields
changedintegerrequiredunchangedintegerrequiredinvalidintegerrequired
Request
curl -X POST "https://api.chatkomodo.com/v1/consent/bulk" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phones": [
"+447700900123",
"+12025550123"
],
"status": "opted_out"
}'const res = await fetch('https://api.chatkomodo.com/v1/consent/bulk', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"phones": [
"+447700900123",
"+12025550123"
],
"status": "opted_out"
}),
});
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/consent/bulk",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"phones": [
"+447700900123",
"+12025550123",
],
"status": "opted_out",
},
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/consent/bulk', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'phones' => [
'+447700900123',
'+12025550123',
],
'status' => 'opted_out',
],
]);
print_r(json_decode((string) $res->getBody(), true));Response 200
{
"changed": 1,
"unchanged": 1,
"invalid": 1
}Get the consent history of a number
GET
/v1/consent/history/{phone}The append-only consent history of one person (the proof of consent).
Path parameters
phonestringrequiredInternational format+<country code><number>(URL-encode the+); digits only also work. Local numbers use the business country.
Responses
- 200History
Response fields
phonestringrequiredcurrentobject | nullrequiredcurrent.chat_idstringrequiredcurrent.phonestringrequiredDigits with country code (no+)current.statusstringrequiredcurrent.sourcestringrequiredHow the status was set: the customer replied with a keyword, a person in the dashboard, a contacts import withopt_in, an API key, or a privacy erasurecurrent.notestring | nullrequiredcurrent.created_atintegerrequiredcurrent.updated_atintegerrequiredhistoryarray of objectrequiredhistory[].statusstringrequiredhistory[].sourcestringrequiredhistory[].notestring | nullrequiredhistory[].atintegerrequired
- 400
INVALID_NUMBER
Request
curl "https://api.chatkomodo.com/v1/consent/history/447700900123" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/consent/history/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/consent/history/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/consent/history/447700900123', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));Response 200
{
"phone": "+447700900123",
"current": {
"chat_id": "+447700900123",
"phone": "+447700900123",
"status": "opted_in",
"source": "keyword",
"note": "Prefers delivery after 5 pm",
"created_at": 1767225600000,
"updated_at": 1767225600000
},
"history": [
{
"status": "opted_in",
"source": "string",
"note": "Prefers delivery after 5 pm",
"at": 1767225600000
}
]
}Opt a number in or out
PUT
/v1/consent/{phone}Opt one person in or out.
Path parameters
phonestringrequiredInternational format+<country code><number>(URL-encode the+); digits only also work. Local numbers use the business country.
Request body
statusstringrequirednotestring | null
Responses
- 200Saved
Response fields
okbooleanrequiredchangedbooleanrequiredconsentobjectrequiredconsent.chat_idstringrequiredconsent.phonestringrequiredDigits with country code (no+)consent.statusstringrequiredconsent.sourcestringrequiredHow the status was set: the customer replied with a keyword, a person in the dashboard, a contacts import withopt_in, an API key, or a privacy erasureconsent.notestring | nullrequiredconsent.created_atintegerrequiredconsent.updated_atintegerrequired
- 400
INVALID_NUMBER
Request
curl -X PUT "https://api.chatkomodo.com/v1/consent/447700900123" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "opted_out",
"note": "Asked to stop by email"
}'const res = await fetch('https://api.chatkomodo.com/v1/consent/447700900123', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"status": "opted_out",
"note": "Asked to stop by email"
}),
});
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/consent/447700900123",
headers={
"Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
},
json={
"status": "opted_out",
"note": "Asked to stop by email",
},
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/consent/447700900123', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
'json' => [
'status' => 'opted_out',
'note' => 'Asked to stop by email',
],
]);
print_r(json_decode((string) $res->getBody(), true));Response 200
{
"ok": true,
"changed": true,
"consent": {
"chat_id": "+447700900123",
"phone": "+447700900123",
"status": "opted_in",
"source": "keyword",
"note": "Prefers delivery after 5 pm",
"created_at": 1767225600000,
"updated_at": 1767225600000
}
}