Developers
QNNECT Public API: send WhatsApp messages and templates, read the channel's template catalog, receive webhooks. Tokens and channel identifiers live in the cabinet, under “Integrations → API”.
MCP
https://qnnect.kz/mcp · Streamable HTTPclaude mcp add --transport http qnnect https://qnnect.kz/mcp
Without a token the MCP server serves the API documentation. With a read-only token
from the cabinet (“API integrations & MCP” → “MCP”) it also exposes your company
data — channels and templates: connect using
https://qnnect.kz/mcp?token=<MCP_READ_TOKEN>.
One-click install buttons for Cursor and VS Code live in the cabinet as well.
HTTP API for sending WhatsApp messages and templates through your QNNECT channel, and for reading the channel's template catalog.
Authentication
Every request is authenticated with two values you can copy from the QNNECT cabinet (Integrations → API):
channel_uuid— the channel identifier, part of the URL path;api_token— the channel's secret token, passed as thetokenquery parameter.
Both values are per-channel. Keep the token secret: anyone who has it can send messages at your expense. The token can be regenerated in the cabinet at any time (the old one stops working immediately).
Delivery model
Sending endpoints are asynchronous: a successful call returns 202 with a message_uuid — the message is queued and delivered in the background. Delivery progress is reported through webhook integrations (see Webhooks).
Errors
Errors are JSON objects {"error": "<code>"} with an optional human-readable message. HTTP status codes: 400 invalid input, 401 missing or invalid token, 403 sending suspended (company blocked or out of funds), 404 unknown channel or template.
Endpoints
POST /api/v1/{channel_uuid}/message/Send a text or media message
Sends a free-form message to a WhatsApp user. Free-form messages are deliverable only inside the 24-hour customer-service window opened by the user's last inbound message; outside the window use a template.
type selects the payload kind. For text the text field is required. For media types (image, video, audio, document, sticker) the media.url field is required; text becomes the caption where WhatsApp supports it (image, video, document).
Supported media formats and size limits:
| type | MIME | max size |
|---|---|---|
| image | image/jpeg, image/png | 5 MB |
| video | video/mp4, video/3gpp | 16 MB |
| audio | audio/aac, audio/mp4, audio/mpeg, audio/amr, audio/ogg | 16 MB |
| document | pdf, doc(x), xls(x), ppt(x), txt | 100 MB |
| sticker | image/webp | 500 KB |
The media.url must be a public HTTPS URL.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
type | string (text, image, video, audio, document, sticker) | yes | Message kind. text requires text; media kinds require media.url. |
phone | string | yes | Recipient phone in international format, digits only (e.g. 77778866697). |
text | string | no | Message text for type=text; caption for image/video/document. |
media | object | no | Media descriptor; required for media types. |
Example request
curl -X POST 'https://qnnect.kz/api/v1/{channel_uuid}/message/?token=YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"type": "text",
"phone": "77778866697",
"text": "Hello! Your order is ready."
}'Responses
202— Message accepted and queued for delivery.400— Invalid input.errorholds a machine-readable code.401— Token is missing (missing_token) or wrong (invalid_token).403— Sending is suspended — the company is blocked or out of funds (company_inactive).404— No channel with thischannel_uuid(channel_not_found).
POST /api/v1/{channel_uuid}/template/Send a template message
Sends an approved WhatsApp template. Templates work outside the 24-hour window and are the way to start a conversation.
values fills the numbered body placeholders {{1}}, {{2}}, … in order; the count must match the template exactly (see GET /api/v1/{channel_uuid}/templates/ → variables.body). header_values and button_values fill header/button placeholders when the template has them.
Media templates (IMAGE/VIDEO/DOCUMENT header): pass a public media_url (with optional media_mime_type) or a pre-registered media_id. Carousel templates: cards replaces card images by index; null keeps the sample image from the template.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
phone | string | yes | Recipient phone in international format, digits only. |
template_name | string | yes | Template name exactly as in the catalog (listTemplates). |
values | array | no | Body placeholder values {{1}}, {{2}}, … in order; count must match variables.body. |
header_values | array | no | Header placeholder values, when the template header has variables. |
button_values | array | no | Button placeholder values (dynamic URL suffixes etc.). |
media_url | string | no | Public media URL for templates with a media header. |
media_id | string | no | Pre-registered media id — alternative to media_url. |
media_mime_type | string | no | MIME type of media_url (e.g. image/jpeg). |
cards | array | no | Carousel only — per-card image overrides; null keeps the sample image. |
Example request
curl -X POST 'https://qnnect.kz/api/v1/{channel_uuid}/template/?token=YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"phone": "77778866697",
"template_name": "order_confirm",
"values": [
"Ivan",
"12345"
]
}'Responses
202— Template accepted and queued for delivery.400— Invalid input.errorholds a machine-readable code.401— Token is missing (missing_token) or wrong (invalid_token).403— Sending is suspended — the company is blocked or out of funds (company_inactive).404— Channel or template not found.
GET /api/v1/{channel_uuid}/templates/List channel templates
Returns the channel's template catalog with statuses and variable counts. Use it to discover what can be sent and how many values each template expects before calling the send endpoint.
All statuses are returned by default, including PENDING and REJECTED — only APPROVED templates can actually be sent.
Query parameters
status— Filter by exact status (e.g. APPROVED, PENDING, REJECTED).category— Filter by category.type— Filter by template type (TEXT, IMAGE, VIDEO, DOCUMENT, CAROUSEL, …).
Example request
curl 'https://qnnect.kz/api/v1/{channel_uuid}/templates/?token=YOUR_API_TOKEN'Responses
200— Template catalog of the channel.401— Token is missing (missing_token) or wrong (invalid_token).404— No channel with thischannel_uuid(channel_not_found).
Webhooks
HOOK incoming_messageIncoming message from a WhatsApp user
Sent to your configured webhook URL when a WhatsApp user writes to the channel. Webhook URLs are configured in the cabinet (Integrations → Webhooks) and can be enabled per event type.
Delivery: POST with JSON body, Content-Type: application/json; charset=utf-8. Respond with any 2xx within 12 seconds; failed deliveries are retried in the background.
Payload
| Field | Type | Description |
|---|---|---|
event | string (incoming_message, outgoing_message, message_status_update) | Event type; matches the webhook name. |
phone | string | WhatsApp user's phone number. |
channel_id | string | Channel identifier (Gupshup app id) the event belongs to. |
text | string | Message text (empty for non-text content). |
message_uuid | string | Message identifier; matches QueuedResponse.message_uuid for API sends. |
status | string | Current message status (queued, sent, delivered, read, failed, …). |
sender | string (CLIENT, COMPANY, AI) | Who authored the message. |
timestamp | string | Event time (ISO 8601). |
HOOK outgoing_messageOutgoing message sent from the channel
Sent when a message leaves the channel — from the QNNECT UI, the API or an integration. Same delivery contract as incoming_message.
Payload
| Field | Type | Description |
|---|---|---|
event | string (incoming_message, outgoing_message, message_status_update) | Event type; matches the webhook name. |
phone | string | WhatsApp user's phone number. |
channel_id | string | Channel identifier (Gupshup app id) the event belongs to. |
text | string | Message text (empty for non-text content). |
message_uuid | string | Message identifier; matches QueuedResponse.message_uuid for API sends. |
status | string | Current message status (queued, sent, delivered, read, failed, …). |
sender | string (CLIENT, COMPANY, AI) | Who authored the message. |
timestamp | string | Event time (ISO 8601). |
HOOK message_status_updateDelivery status of an earlier message changed
Sent when WhatsApp reports a status change for a previously sent message (sent → delivered → read, or failed). Correlate by message_uuid. Same delivery contract as incoming_message.
Payload
| Field | Type | Description |
|---|---|---|
event | string (incoming_message, outgoing_message, message_status_update) | Event type; matches the webhook name. |
phone | string | WhatsApp user's phone number. |
channel_id | string | Channel identifier (Gupshup app id) the event belongs to. |
text | string | Message text (empty for non-text content). |
message_uuid | string | Message identifier; matches QueuedResponse.message_uuid for API sends. |
status | string | Current message status (queued, sent, delivered, read, failed, …). |
sender | string (CLIENT, COMPANY, AI) | Who authored the message. |
timestamp | string | Event time (ISO 8601). |