← Learning Center العربية

Developer API Included on every plan

Send and receive messages on all your connected channels — WhatsApp, Telegram, Messenger, Instagram, TikTok — from your own systems, receive events by webhook, and even plug in your own AI key.

Authentication Send a message WhatsApp templates Status Incoming webhooks Event types Connect channels Comments Platform events Your own AI key Errors n8n / Make / Zapier / CRM →

🔑 Authentication & base URL

Create API keys from your dashboard: Messaging API page (each key is an independent instance with its own allowed channels and webhook). Keys are shown once — store them securely.

Base URL:  https://thikaa.com/<your-store>/api/messaging/

Authorization: Bearer <api_key>      (or X-API-Key: <api_key>)
The Messaging API is available on every plan. Messages sent through the API consume your normal message credits.

POST Send a message

POST /api/messaging/?action=send

FieldRequiredDescription
channel✓One of: wd (WhatsApp QR) · wa (WhatsApp API) · tg · fb · ig · tt
to✓Recipient — phone number with country code for WhatsApp; for WhatsApp QR (wd), you may also use a Baileys group JID such as 120363012345678901@g.us; platform user id otherwise
message✓Text to send (UTF-8, Arabic fully supported)
media_url—Optional public HTTPS URL of an image / document to attach
media_type—Hint like image, document

cURL

curl -X POST "https://thikaa.com/<your-store>/api/messaging/?action=send" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "wd",
    "to": "9647701234567",
    "message": "تحديث الوظائف الأسبوعي 👇 ..."
  }'

Response

{ "ok": true, "message_id": "...", "channel": "wd", "to": "9647701234567" }
Bulk sending: loop your recipient list with a small delay between calls and respect your per-key rate limit (default 60/min). For large recurring campaigns (e.g. weekly updates to thousands of students), the official WhatsApp API channel (wa) is the recommended long-term setup.

💬 WhatsApp message templates

A pre-approved template is the only lawful way to message a WhatsApp Cloud API (wa) contact who has never written to you, or to reopen a chat after the 24-hour window has closed. Without one, action=send returns 409 no_existing_conversation.

1. List your approved templates

GET /api/messaging/?action=templates

curl "https://thikaa.com/<your-store>/api/messaging/?action=templates" \
  -H "Authorization: Bearer YOUR_API_KEY"

{ "ok": true, "count": 1, "templates": [
    { "name": "order_update", "language": "en", "status": "APPROVED",
      "category": "UTILITY", "body": "Hi {{1}}, your order {{2}} is ready.", "variables": 2 }
] }
Templates live in your own WhatsApp Business Account. Create them in Meta Business Manager, or from your dashboard (WhatsApp API page → Message Templates), which submits them to Meta for approval. Approval is Meta’s decision, usually minutes.

2. Send one

POST /api/messaging/?action=send — channel wa only

FieldRequiredDescription
template.name✓Approved template name
template.language—Language code, e.g. en, ar, en_US. Defaults to en
template.variables—Array of strings filled into the body placeholders {{1}}, {{2}} … in order
template.components—Full Meta components array instead of variables — for header media, buttons or named parameters
from—Which of your WhatsApp numbers to send from — phone-number-id, display number or label. Defaults to your first number
curl -X POST "https://thikaa.com/<your-store>/api/messaging/?action=send" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "wa",
    "to": "+994105156977",
    "template": {
      "name": "order_update",
      "language": "en",
      "variables": ["Nurlan", "#1042"]
    }
  }'

{ "ok": true, "message_id": "wamid...", "conversation_id": 87,
  "template": "order_update", "language": "en", "delivery": "sent" }
The reply lands in the same thread. A template sent through the API creates the conversation in your inbox, so when the customer answers you get message.received with that same conversation_id, and normal text sending works from then on — no second thread, no 409.
200 means Meta accepted it, not that it arrived. Delivery is asynchronous: an invalid or unreachable number still returns a message id, then fails afterwards. The real outcome shows on the message in your inbox and on the delivery-status webhook.
Pick the right category. MARKETING templates need opt-in and are counted against your number’s marketing limits. For transactional messages — a requested callback, an order update, an appointment reminder — use UTILITY: cheaper, higher limits and far less likely to be flagged.
Template pricing is billed by Meta on your own WhatsApp account, at Meta’s per-conversation rates. Thikaa bills a template-opened conversation exactly like any other: once per conversation per period.

GET Account status

GET /api/messaging/?action=status — returns the key’s instance status, allowed channels and current balance.

curl "https://thikaa.com/<your-store>/api/messaging/?action=status" \
  -H "Authorization: Bearer YOUR_API_KEY"

📥 Incoming-message webhooks

Set a webhook URL per API key (Messaging API page). Every inbound customer message on the key’s channels is POSTed to your endpoint as JSON, signed with your key’s secret:

POST <your-webhook-url>
Content-Type: application/json
X-Thikaa-Event: message.received
X-Thikaa-Signature: sha256=<hmac_sha256(body, webhook_secret)>

{ "event": "message.received", "instance_id": "...", "data": {
    "channel": "wa",
    "conversation_id": 1290,
    "message_id": 84990,
    "from": "+9665XXXXXXXX",
    "account": { "id": "1297236690138576", "number": "+994 10 515 69 77", "label": "nurlan_dev" },
    "text": "Where is my order?",
    "attachments": []
} }
account is your own line that received the message — the Meta phone-number-id (or WhatsApp QR connection id, or page id) plus the readable number and label. When your workspace holds several numbers, this is what tells you which one a message belongs to.
WhatsApp groups (QR / Baileys only). Group messages use the group JID (ending in @g.us) as the conversation identity, so every participant lands in one shared Thikaa conversation. Each group event includes a whatsapp_group object with is_group, group_jid, participant, and participant_name. Replies sent with channel: wd and the same group JID go back to the group. Broadcasts and newsletters are excluded. WhatsApp Cloud API (wa) does not support normal group chats.

Verify the signature (PHP)

$body = file_get_contents('php://input');
$sig  = $_SERVER['HTTP_X_THIKAA_SIGNATURE'] ?? '';
$ok   = hash_equals('sha256=' . hash_hmac('sha256', $body, $secret), $sig);

Verify the signature (Node.js)

const crypto = require('crypto');
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers['x-thikaa-signature'] || ''));

🧾 Messaging API event types

Tick the events you want on each API key. The X-Thikaa-Event header and the event field always say which one you are handling.

EventFires when
message.receiveda customer sends you a message
message.sentanything leaves your workspace — origin is api, bot, dashboard, or phone for a reply typed straight into WhatsApp on the linked handset
message.statusa receipt moves a message forward: sent → delivered → read. WhatsApp reports all three; Messenger reports delivered and read; Instagram reports read. TikTok and Telegram expose no receipts, so nothing is emitted for them.
message.reactionsomeone adds or removes a reaction
comment.receivedsomeone comments on a Facebook post, Instagram post or TikTok video
channel.connecteda channel finished connecting — an OAuth link completed, or a WhatsApp number finished pairing
channel.disconnecteda channel was removed, by API or in the dashboard

🔌 Connect your clients’ channels from your own panel

Built for platforms that resell us: your customer never sees a Thikaa login. You mint a connect link, they authorize on Facebook or TikTok, and the page lands in your workspace.

See what is connected

curl "https://thikaa.com/<your-store>/api/messaging/?action=channels" \
  -H "Authorization: Bearer YOUR_API_KEY"

{ "ok": true, "channels": [
    { "channel": "wd", "id": "1000017", "name": "Lavida Travel", "identifier": "96555060830", "status": "connected" },
    { "channel": "fb", "id": "100877191952677", "name": "Pawlo Butchery", "status": "connected" },
    { "channel": "ig", "id": "17841478342647968", "name": "Pawlo Butchery", "status": "connected" },
    { "channel": "tt", "id": "-000HFd...", "name": "pawlo_butcher", "status": "connected" } ],
  "counts": { "wd": 1, "fb": 1, "ig": 1, "tt": 1 } }

Facebook, Instagram, TikTok — one link

GET /api/messaging/?action=connect-link&channel=fb        # fb | ig | tt
      &redirect_url=https://your-app.com/done?client=42

{ "ok": true, "channel": "fb",
  "connect_url": "https://www.facebook.com/v21.0/dialog/oauth?...",
  "redirect_url": "https://your-app.com/done?client=42" }

Send your client to connect_url. When they finish, we return them to your redirect_url with the outcome appended — ?thikaa_status=success&channel=fb&connected=2&ids=... — and POST you a signed channel.connected event per connected surface.

Render the redirect, trust the webhook. A browser redirect is user-controlled — anyone can type ?thikaa_status=success. Use it to show a result page; write to your database on the signed event.

One Meta authorization covers both surfaces: connecting a Facebook page also connects its Instagram DMs, and you get two channel.connected events for it.

Telegram — no OAuth, just the token

POST /api/messaging/?action=connect-telegram
{ "bot_token": "8765196861:AAG..." }      # from @BotFather
{ "ok": true, "channel": "tg", "status": "connected", "bot_username": "YourBot" }

WhatsApp QR — pair your client’s number

Pairing code is the primary flow: your client is usually holding the very phone being linked, where a QR on that same screen cannot be scanned.

POST /api/messaging/?action=create-session   { "label": "Clinic Riyadh" }
   -> { "session_token": "wds_...", "account_id": 1000021 }
POST /api/messaging/?action=pair-code        { "session_token": "wds_...", "phone": "+9665XXXXXXXX" }
   -> { "pairing_code": "ABCD-EFGH" }        # client types this into WhatsApp
GET  /api/messaging/?action=session-status&session_token=wds_...
GET  /api/messaging/?action=session-qr&session_token=wds_...      # desktop fallback
POST /api/messaging/?action=delete-session
Pairing finishes on your client’s phone where you cannot see it, so wait for channel.connected instead of polling session-status in a loop.

Disconnect

POST /api/messaging/?action=disconnect-channel
{ "channel": "fb", "id": "100877191952677" }       # fb | ig | tg | tt

{ "ok": true, "channel": "fb", "status": "disconnected",
  "also_disconnected": [ { "channel": "ig", "id": "17841478342647968" } ] }

For Facebook this is a full teardown: we unsubscribe our app from the page at Meta so delivery actually stops, then remove its routing and bot links. channel=ig detaches only the Instagram account and leaves Messenger working. WhatsApp QR uses delete-session.

💭 Comments — Facebook, Instagram & TikTok

Comments are a separate surface from DMs, with their own ids and their own reply mechanism. One event to receive them, two endpoints to read and answer.

{ "event": "comment.received", "data": {
    "platform": "fb",                      # fb | ig | tt
    "comment_id": "1221...._1795...",
    "post_id": "113700101731161_1220987...",
    "parent_id": null,
    "text": "How much is this?",
    "from": { "id": "7051...", "name": "Adham Ammar" },
    "conversation_id": 1841
} }
POST /api/messaging/?action=comment-reply
{ "comment_id": "1221...._1795...",
  "message": "It is 200 SAR",
  "private_message": "Here is the full list..." }   # Meta private reply, opens a real DM

GET /api/messaging/?action=comments&platform=tt&limit=50
Timing differs by platform, and we would rather say so. Meta pushes comments to us, so fb and ig events fire the instant a comment is posted. TikTok offers no comment webhook for our app type, so TikTok comments are polled and arrive within a few minutes. Replies are immediate on all three.
Per-platform limits. TikTok has no private reply — sending private_message there returns a clear error rather than silently doing nothing, and its comment replies are text only. Instagram public replies require Meta’s instagram_manage_comments permission on our app.

🔔 Platform event webhooks

Separately from the Messaging API, the platform can POST admin-level events to a single URL (Settings → Webhooks). Useful events include:

EventFires when
message-senta message is sent in any conversation
bot-messagethe AI bot replies
new-messagesnew inbound customer messages
new-conversation / new-conversation-createda new conversation starts
conversation-status-updateda conversation is resolved / archived
sms-sent · email-sentan SMS / email notification goes out

🧠 Bring your own AI key

You can run your bots on your own AI account instead of platform credit: connect an OpenAI, Google Gemini or Anthropic Claude API key from the AI Providers page in your dashboard, then select that connection in your bot’s model settings. Your key is stored per-tenant and used only for your own bots.

⚠️ Errors & limits

HTTPErrorMeaning
401missing_api_key / invalid_api_keyKey absent, disabled or revoked
402insufficient_balanceAccount out of credit / inactive
403channel_not_allowedThis key is not permitted to use that channel
400bad_redirect_urlredirect_url is not an absolute HTTPS URL on a resolvable public hostname
404unknown_comment · not_connectedThat comment was never delivered to you, or nothing with that id is connected here
405method_not_allowedWrong HTTP method
429rate_limitedPer-key rate limit exceeded (default 60 requests/minute)
502graph_error · tiktok_errorMeta or TikTok refused the call — their own message is passed through verbatim
Available on every plan, including Starter. There is no API add-on and no separate API fee — outbound messages consume your normal account credit, exactly like bot replies.

Questions? Message us on WhatsApp from the site — a human (or our own bot 😄) will help.