ChatKomodo Docs Home Sign in

API reference · Customers

Chat links & widget

Click-to-WhatsApp short links (for ads, bios, QR codes) and a chat button for your website. Visits are counted with their campaign tags (UTM); when a visitor sends the ready message, the chat is matched to the visit through a short code (#K7Q2MX) and the person gets the link as their lead source, plus the link's labels and stage.

Create a link

POST/v1/links

A short link that opens a WhatsApp chat with one of your devices with message ready to send. Share it in ads, bios, emails or as a QR code; add ?utm_source=…&utm_medium=…&utm_campaign=… to a shared copy to tag that placement. When someone writes through it, their contact gets source (the link name) and the campaign tags as attributes, the link's labels, and stage if they are not on the board yet. At most 200 links. Recorded as link.create.

Request body

  • namestringrequired
    Up to 80 characters
  • session_idstringrequired
  • messagestringrequired
    Up to 1 000 characters
  • add_refboolean
  • utm_sourcestring | null
    Up to 100 characters
  • utm_mediumstring | null
    Up to 100 characters
  • utm_campaignstring | null
    Up to 100 characters
  • labelsarray of string
    Up to 10 items
  • stagestring | null
  • widgetobject | null
  • widget.enabledbooleanrequired
  • widget.colorstringrequired
    #rrggbb
  • widget.positionstringrequired
    One of: right, left
  • widget.titlestringrequired
    Greeting title; empty = your business name
  • widget.textstringrequired
    Greeting text; empty = a default greeting. When both are empty the button opens the chat directly
  • widget.buttonstringrequired
    Button text; empty = "Start chat"
  • widget.delay_sintegerrequired
    Open the greeting by itself after this many seconds (0 = only on click)
    From 0 to 120
  • disabledboolean

Responses

  • 201The link
    Response fields
    • idstringrequired
    • codestringrequired
    • namestringrequired
    • urlstringrequired
      The short link to share (your agency's domain for its clients)
    • session_idstringrequired
      The device the chat opens with
    • messagestringrequired
      The message the customer's WhatsApp has ready to send
    • add_refbooleanrequired
      Add a short reference (#K7Q2MX) to the message so the chat can be matched to the visit. Without it visits are counted but chats are not
    • utm_sourcestring | nullrequired
    • utm_mediumstring | nullrequired
    • utm_campaignstring | nullrequired
    • labelsarray of stringrequired
      Put on people who write through the link
    • stagestring | nullrequired
      Lead stage for people who write through the link and are not on the board yet
    • widgetobject | nullrequired
    • widget.enabledbooleanrequired
    • widget.colorstringrequired
      #rrggbb
    • widget.positionstringrequired
      One of: right, left
    • widget.titlestringrequired
      Greeting title; empty = your business name
    • widget.textstringrequired
      Greeting text; empty = a default greeting. When both are empty the button opens the chat directly
    • widget.buttonstringrequired
      Button text; empty = "Start chat"
    • widget.delay_sintegerrequired
      Open the greeting by itself after this many seconds (0 = only on click)
      From 0 to 120
    • widget_snippetstringrequired
      The <script> tag to paste into a website
    • clicksintegerrequired
      Visits, all time (link-preview bots not counted)
    • chatsintegerrequired
      Visits that became a chat, all time
    • clicks_30dintegerrequired
    • chats_30dintegerrequired
    • leadsintegerrequired
      People who first came through this link and are on the leads board
    • wonintegerrequired
      …of them in a won stage
    • disabledbooleanrequired
    • created_atintegerrequired
      Unix time in milliseconds
    • updated_atintegerrequired
      Unix time in milliseconds
  • 400VALIDATION_FAILED
  • 409LIMIT_REACHED
Request
curl -X POST "https://api.chatkomodo.com/v1/links" \
  -H "Authorization: Bearer $CHATKOMODO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Instagram bio",
  "session_id": "YOUR_DEVICE_ID",
  "message": "Hello, I'\''d like to know more.",
  "utm_source": "instagram",
  "utm_medium": "social",
  "labels": [
    "instagram"
  ],
  "stage": "new"
}'
const res = await fetch('https://api.chatkomodo.com/v1/links', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CHATKOMODO_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Instagram bio",
    "session_id": "YOUR_DEVICE_ID",
    "message": "Hello, I'd like to know more.",
    "utm_source": "instagram",
    "utm_medium": "social",
    "labels": [
      "instagram"
    ],
    "stage": "new"
  }),
});
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/links",
    headers={
        "Authorization": f"Bearer {os.environ['CHATKOMODO_API_KEY']}",
    },
    json={
        "name": "Instagram bio",
        "session_id": "YOUR_DEVICE_ID",
        "message": "Hello, I'd like to know more.",
        "utm_source": "instagram",
        "utm_medium": "social",
        "labels": [
            "instagram",
        ],
        "stage": "new",
    },
    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/links', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('CHATKOMODO_API_KEY'),
    ],
    'json' => [
        'name' => 'Instagram bio',
        'session_id' => 'YOUR_DEVICE_ID',
        'message' => 'Hello, I\'d like to know more.',
        'utm_source' => 'instagram',
        'utm_medium' => 'social',
        'labels' => [
            'instagram',
        ],
        'stage' => 'new',
    ],
]);

print_r(json_decode((string) $res->getBody(), true));
Response 201
{
  "id": "01JA5V6Q8M2H7G4K9P3T0R1S2X",
  "code": "RECIPIENT_OPTED_OUT",
  "name": "Example",
  "url": "https://example.com/file.jpg",
  "session_id": "YOUR_DEVICE_ID",
  "message": "Hi Sam, your order has shipped.",
  "add_ref": true,
  "utm_source": "string",
  "utm_medium": "string",
  "utm_campaign": "string",
  "labels": [
    "string"
  ],
  "stage": "vip",
  "widget": {
    "enabled": true,
    "color": "#0a7350",
    "position": "right",
    "title": "string",
    "text": "Hi Sam, your order has shipped.",
    "button": "string",
    "delay_s": 1
  },
  "widget_snippet": "string",
  "clicks": 1,
  "chats": 1,
  "clicks_30d": 1,
  "chats_30d": 1
}

Open a link (visitor)

GET/public/go/{code}No authentication

What the short link does: counts the visit (with utm_* from the query, overriding the link's) and redirects to the WhatsApp chat. Link-preview bots are redirected without being counted. https://chatkomodo.com/go/{code} forwards here. No authentication.

Path parameters

  • codestringrequired

Query parameters

  • utm_sourcestring
  • utm_mediumstring
  • utm_campaignstring
  • utm_contentstring
  • utm_termstring

Responses

  • 302To https://wa.me/<number>?text=…
  • 404Unknown link (an HTML page)
  • 503The link is off or its device has no number yet (an HTML page)
Request
curl "https://api.chatkomodo.com/public/go/CODE"
const res = await fetch('https://api.chatkomodo.com/public/go/CODE', {
  method: 'GET',
});
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/public/go/CODE",
    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/public/go/CODE', [
]);

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

Website widget script

GET/public/widget/{file}No authentication

The chat button for a website: <script src="https://api.chatkomodo.com/public/widget/{code}.js" async></script>. It opens the link with the page's own utm_* tags and address. Cached for 5 minutes; a link with the widget off serves an empty script. No authentication.

Path parameters

  • filestringrequired
    {code}.js

Responses

  • 200JavaScript
Request
curl "https://api.chatkomodo.com/public/widget/FILE"
const res = await fetch('https://api.chatkomodo.com/public/widget/FILE', {
  method: 'GET',
});
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/public/widget/FILE",
    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/public/widget/FILE', [
]);

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

application/javascript — the file itself.