. Create an API key under API keys.Guide
Authentication
API keys
Send your key as a bearer token on every request to /v1:
Authorization: Bearer <your API key>A key acts as your business: it can use all of your devices, contacts and settings, within your plan. Keys are random 43-character strings, shown once when created, and stored by ChatKomodo only as a hash.
- Keep keys on your server. The API does not accept cross-origin calls from other websites, and a key in a web page or app can be copied.
- A key that leaked: create a new one, deploy it, then revoke the old one in API keys.
- Five wrong keys from the same address lock that address out for 15 minutes (
429).
Child keys for separate integrations
Give each integration its own key (POST /v1/api-keys): it acts as your business but has its own request limit and can be revoked alone. A child key can also be limited to some devices; such a scoped key cannot reach business-wide data:
| Scoped key | Endpoints |
|---|---|
| Not allowed | API keys, webhooks, audit log, privacy, onboarding, CRM, consent, contacts, contact groups, recurring messages, store connections |
| Read only | Billing, business profile, settings, rotators, templates, agents, AI assistant |
| Allowed | Everything under its own devices: /v1/sessions/{sessionId}/… |
Keys are created and revoked from a dashboard login (an API key cannot create keys).
Signed requests (optional)
For extra protection against replay, add two headers. ChatKomodo then checks that the body was not changed and that the request is less than 5 minutes old:
X-Timestamp: the current time in Unix millisecondsX-API-Signature: hex HMAC-SHA256, with your API key as the secret, of<timestamp>.<hex SHA-256 of the raw body>(an empty body hashes the empty string)
import { createHash, createHmac } from 'node:crypto';
const key = process.env.CHATKOMODO_API_KEY;
const body = JSON.stringify({ chat_id: '+447700900123', type: 'text', body: 'Signed hello' });
const ts = String(Date.now());
const bodyHash = createHash('sha256').update(body).digest('hex');
const signature = createHmac('sha256', key).update(`${ts}.${bodyHash}`).digest('hex');
await fetch('https://api.chatkomodo.com/v1/sessions/YOUR_DEVICE_ID/messages', {
method: 'POST',
headers: {
Authorization: `Bearer ${key}`,
'Content-Type': 'application/json',
'X-Timestamp': ts,
'X-API-Signature': signature,
},
body,
});Send exactly the bytes you hashed. A wrong signature or an old timestamp returns 401.
Dashboard logins
The dashboard signs people in with a one-time code sent over WhatsApp (POST /auth/request-otp, POST /auth/verify-otp) and uses the returned token the same way: Authorization: Bearer <token>. Tokens last 2 hours and are renewed with POST /auth/refresh. A few endpoints are meant for people, not integrations, and need the owner's dashboard login — they are marked Dashboard login in the reference (for example creating API keys, editing AI documents and connecting stores).
Check a credential
curl "https://api.chatkomodo.com/v1/me" \
-H "Authorization: Bearer $CHATKOMODO_API_KEY"const res = await fetch('https://api.chatkomodo.com/v1/me', {
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/me",
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/me', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
],
]);
print_r(json_decode((string) $res->getBody(), true));GET /v1/me says which business the credential belongs to, its plan, and whether it is an API key, the owner's login or an agent.