Build with Kalagh
Plain HTTP and JSON, a realtime event stream, and webhooks in both directions — the same API our own app is built on.
REST API
The same HTTP endpoints our own app runs on, under /api/v1/omni — messages, conversations, contacts and automation, with one JSON envelope for every reply.
Realtime Events
A Socket.IO stream pushes every inbound message and status change to your integration the moment it happens, over a single event typed by number.
Webhooks
Both directions: a signed POST starts a workflow or playbook, and a workflow HTTP action calls your endpoint when something happens. There is no event-subscription catalogue yet.
API
// Reply into an existing conversation. `type` is a MessageType
// (1 = Text) and may be omitted; the API then defaults to Text.
POST https://api.kalagh.chat/api/v1/omni/messages/send
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"conversationId": "0f8a3c2e-7b21-4c9e-8a1f-2d6b3e4f5a6c",
"message": "Hello from the Kalagh API!",
"type": 1
}
// The status line is ALWAYS 200 — success and failure arrive in the
// same envelope, so branch on isSuccess, never on the status code.
{
"isSuccess": true,
"status": 3,
"data": {
"channelId": "5c2e9d11-4a3b-4f8e-9c0d-1b2a3c4d5e6f",
"platform": 3,
"message": {
"id": "9b1d7c44-2e5f-4a6b-8c1d-0f9e8d7c6b5a",
"conversationId": "0f8a3c2e-7b21-4c9e-8a1f-2d6b3e4f5a6c",
"providerId": "wamid.HBgLMTU1NTAxMjM0NTY...",
"me": true,
"type": 1,
"status": 2,
"content": {
"type": 1,
"message": "Hello from the Kalagh API!",
"attachments": []
},
"createdAt": "2026-09-26T10:30:00.123Z",
"reactions": []
}
},
"message": "",
"errorCode": 0,
"trace": {}
}
// A failure fills the same fields. `status` says what went wrong, and
// `errorCode` narrows it where an endpoint has codes of its own:
// 4 the conversation does not exist, or you cannot see it
// 7 the body failed validation
// 9 the platform's reply window has closed (errorCode 7001 / 7002)
// 2 the provider refused the send
// 255 the token is missing, malformed or expired
{
"isSuccess": false,
"status": 9,
"data": null,
"message": "Cannot send: the messaging window for this conversation has expired.",
"errorCode": 7001,
"trace": {}
}Quick start in your
Language
There is no SDK to install — Kalagh speaks plain HTTP and JSON, so your language’s own client is all you need. Every tab below does the same thing: log in, then send one message.
import requests
BASE = "https://api.kalagh.chat/api/v1/omni"
CONVERSATION_ID = "0f8a3c2e-7b21-4c9e-8a1f-2d6b3e4f5a6c"
TEXT = 1 # MessageType.Text
# 1. Log in. There are no API keys: the credential is a user account,
# and the reply carries the bearer token every other call presents.
signin = requests.post(
f"{BASE}/account/signin",
json={"username": "[email protected]", "password": "..."},
timeout=30,
).json()
# Every reply is HTTP 200 — the outcome lives in the body.
if not signin["isSuccess"] or not signin["data"]["token"]:
raise SystemExit(f"sign-in failed ({signin['status']}): {signin['message']}")
token = signin["data"]["token"]
# 2. Send a message into an existing conversation.
sent = requests.post(
f"{BASE}/messages/send",
headers={"Authorization": f"Bearer {token}"},
json={
"conversationId": CONVERSATION_ID,
"message": "Hello from Python!",
"type": TEXT,
},
timeout=30,
).json()
if not sent["isSuccess"]:
raise SystemExit(f"send failed ({sent['status']}): {sent['message']}")
print(sent["data"]["message"]["id"])