ChatKomodo Docs Home Sign in

Guide

Quickstart: send your first message

From zero to a delivered WhatsApp message in five steps.

1. Create an account and link a number

Sign up at chatkomodo.com with your WhatsApp number. In the dashboard open Devices → Connect a device and scan the QR code with the phone whose number should send: WhatsApp → Settings → Linked devices → Link a device. The number keeps working on the phone as usual.

Use a number that is already active on WhatsApp. A brand-new number is warmed up for its first day: it sends more slowly.

2. Create an API key

In the dashboard open API keys → Create key. The key is shown once: store it in your server's secrets (an environment variable such as CHATKOMODO_API_KEY), never in a website or mobile app.

Shell
export CHATKOMODO_API_KEY="paste-your-key-here"

3. Find your device id

GET /v1/sessions lists your devices. Take the id of the one with "status": "connected".

Request
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));
Response
{
  "sessions": [
    {
      "id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
      "status": "connected",
      "phone_number": "447700900000",
      "phone_display": "+44 7700 900000",
      "wa_name": "Acme Dental"
    }
  ]
}

4. Send a message

Write the recipient in international format (+<country code><number>):

Request
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": "Hello from ChatKomodo 👋"
}'
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": "Hello from ChatKomodo 👋"
  }),
});
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": "Hello from ChatKomodo 👋",
    },
    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' => 'Hello from ChatKomodo 👋',
    ],
]);

print_r(json_decode((string) $res->getBody(), true));
Response
{
  "id": "01JA5W2B7C9D0E1F2G3H4J5K6M",
  "status": "queued"
}

Check where it is with GET /v1/sessions/{sessionId}/messages (queued → sent → delivered → read) — or let a webhook tell you.

5. Receive replies

Register an HTTPS endpoint of yours; ChatKomodo posts every incoming message to it, signed with your secret:

Request
curl -X POST "https://api.chatkomodo.com/v1/webhooks" \
  -H "Authorization: Bearer $CHATKOMODO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/webhooks/chatkomodo",
  "secret": "a-long-random-secret-of-32-characters-or-more",
  "events": [
    "message.received",
    "message.failed",
    "session.disconnected"
  ]
}'
const res = await fetch('https://api.chatkomodo.com/v1/webhooks', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "url": "https://example.com/webhooks/chatkomodo",
    "secret": "a-long-random-secret-of-32-characters-or-more",
    "events": [
      "message.received",
      "message.failed",
      "session.disconnected"
    ]
  }),
});
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/webhooks",
    headers={
        "Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
    },
    json={
        "url": "https://example.com/webhooks/chatkomodo",
        "secret": "a-long-random-secret-of-32-characters-or-more",
        "events": [
            "message.received",
            "message.failed",
            "session.disconnected",
        ],
    },
    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/webhooks', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
    ],
    'json' => [
        'url' => 'https://example.com/webhooks/chatkomodo',
        'secret' => 'a-long-random-secret-of-32-characters-or-more',
        'events' => [
            'message.received',
            'message.failed',
            'session.disconnected',
        ],
    ],
]);

print_r(json_decode((string) $res->getBody(), true));

Then verify the signature of each delivery. That is it — next, read Sending messages for media, polls, idempotency and pacing.