<!-- GENERATED — не редактировать. source-hash: dda8c78fcc840785 -->
# QNNECT Public API

HTTP API для отправки WhatsApp-сообщений и шаблонов через ваш канал QNNECT
и для чтения каталога шаблонов канала.

## Аутентификация

Каждый запрос аутентифицируется двумя значениями, которые копируются из
кабинета QNNECT (**Интеграции → API**):

* `channel_uuid` — идентификатор канала, часть пути URL;
* `api_token` — секретный токен канала, передаётся query-параметром `token`.

Оба значения — per-канал. Держите токен в секрете: любой, у кого он есть,
может отправлять сообщения за ваш счёт. Токен можно перевыпустить в
кабинете в любой момент (старый перестаёт работать сразу).

## Модель доставки

Отправляющие эндпоинты асинхронны: успешный вызов возвращает `202` с
`message_uuid` — сообщение поставлено в очередь и доставляется в фоне.
Прогресс доставки приходит через webhook-интеграции (см. Webhooks).

## Ошибки

Ошибки — JSON-объекты `{"error": "<код>"}` с опциональным человекочитаемым
`message`. HTTP-коды: `400` неверный ввод, `401` нет или неверный токен,
`403` отправка приостановлена (компания заблокирована или нет средств),
`404` неизвестный канал или шаблон.


## Эндпоинты

### POST /api/v1/{channel_uuid}/message/

**Отправить текст или медиа**

Отправляет свободное сообщение пользователю WhatsApp. Свободные
сообщения доставляются только внутри 24-часового сервисного окна,
открытого последним входящим сообщением пользователя; вне окна
используйте шаблон.

`type` выбирает вид сообщения. Для `text` обязательно поле `text`.
Для медиа-типов (`image`, `video`, `audio`, `document`, `sticker`)
обязателен `media.url`; `text` становится подписью там, где WhatsApp
её поддерживает (`image`, `video`, `document`).

Поддерживаемые форматы и лимиты размера:

| type | MIME | макс. размер |
|---|---|---|
| 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 |

`media.url` должен быть публичным HTTPS-URL.


Тело запроса:

| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
| `type` | string (text, image, video, audio, document, sticker) | да | Вид сообщения. `text` требует `text`; медиа-виды требуют `media.url`. |
| `phone` | string | да | Телефон получателя в международном формате, только цифры (например 77778866697). |
| `text` | string | нет | Текст для `type=text`; подпись для image/video/document. |
| `media` | object | нет | Описание медиа; обязательно для медиа-типов. |

Пример запроса:

```bash
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."
}'
```

Ответы:

* `202` — Сообщение принято и поставлено в очередь доставки.
* `400` — Неверный ввод. В `error` — машиночитаемый код.
* `401` — Токен отсутствует (`missing_token`) или неверен (`invalid_token`).
* `403` — Отправка приостановлена — компания заблокирована или нет средств (`company_inactive`).
* `404` — Канала с таким `channel_uuid` нет (`channel_not_found`).

### POST /api/v1/{channel_uuid}/template/

**Отправить шаблонное сообщение**

Отправляет одобренный WhatsApp-шаблон. Шаблоны работают вне 24-часового
окна — это способ начать диалог первым.

`values` заполняет нумерованные плейсхолдеры тела `{{1}}, {{2}}, …`
по порядку; количество должно точно совпадать с шаблоном (см.
`GET /api/v1/{channel_uuid}/templates/` → `variables.body`).
`header_values` и `button_values` заполняют плейсхолдеры
заголовка/кнопок, если они есть в шаблоне.

Медиа-шаблоны (заголовок IMAGE/VIDEO/DOCUMENT): передайте публичный
`media_url` (опционально с `media_mime_type`) или заранее
зарегистрированный `media_id`. Карусели: `cards` подменяет картинки
карточек по индексу; `null` оставляет образец из шаблона.


Тело запроса:

| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
| `phone` | string | да | Телефон получателя в международном формате, только цифры. |
| `template_name` | string | да | Имя шаблона ровно как в каталоге (`listTemplates`). |
| `values` | array | нет | Значения плейсхолдеров тела `{{1}}, {{2}}, …` по порядку; количество должно совпадать с `variables.body`. |
| `header_values` | array | нет | Значения плейсхолдеров заголовка, если они есть в шаблоне. |
| `button_values` | array | нет | Значения плейсхолдеров кнопок (динамические суффиксы URL и т.п.). |
| `media_url` | string | нет | Публичный URL медиа для шаблонов с медиа-заголовком. |
| `media_id` | string | нет | Заранее зарегистрированный media id — альтернатива `media_url`. |
| `media_mime_type` | string | нет | MIME-тип `media_url` (например image/jpeg). |
| `cards` | array | нет | Только карусель — подмена картинок карточек по индексу; `null` оставляет образец. |

Пример запроса:

```bash
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"
  ]
}'
```

Ответы:

* `202` — Шаблон принят и поставлен в очередь доставки.
* `400` — Неверный ввод. В `error` — машиночитаемый код.
* `401` — Токен отсутствует (`missing_token`) или неверен (`invalid_token`).
* `403` — Отправка приостановлена — компания заблокирована или нет средств (`company_inactive`).
* `404` — Канал или шаблон не найден.

### GET /api/v1/{channel_uuid}/templates/

**Список шаблонов канала**

Возвращает каталог шаблонов канала со статусами и количеством
переменных. Используйте его, чтобы узнать, что можно отправить и
сколько `values` ждёт каждый шаблон, до вызова отправки.

По умолчанию возвращаются все статусы, включая `PENDING` и
`REJECTED` — реально отправить можно только `APPROVED`.


Query-параметры:

* `status` — Фильтр по точному статусу (например APPROVED, PENDING, REJECTED).
* `category` — Фильтр по категории.
* `type` — Фильтр по типу шаблона (TEXT, IMAGE, VIDEO, DOCUMENT, CAROUSEL, …).

Пример запроса:

```bash
curl 'https://qnnect.kz/api/v1/{channel_uuid}/templates/?token=YOUR_API_TOKEN'
```

Ответы:

* `200` — Каталог шаблонов канала.
* `401` — Токен отсутствует (`missing_token`) или неверен (`invalid_token`).
* `404` — Канала с таким `channel_uuid` нет (`channel_not_found`).

## Webhooks

### incoming_message

**Входящее сообщение от пользователя WhatsApp**

Отправляется на настроенный вами webhook-URL, когда пользователь
WhatsApp пишет в канал. Webhook-URL настраиваются в кабинете
(**Интеграции → Webhooks**) и включаются по типам событий.

Доставка: `POST` с JSON-телом, `Content-Type: application/json;
charset=utf-8`. Ответьте любым `2xx` за 12 секунд; неуспешные
доставки ретраятся в фоне.


Payload:

| Поле | Тип | Описание |
|---|---|---|
| `event` | string (incoming_message, outgoing_message, message_status_update) | Тип события; совпадает с именем вебхука. |
| `phone` | string | Номер телефона пользователя WhatsApp. |
| `channel_id` | string | Идентификатор канала (Gupshup app id), к которому относится событие. |
| `text` | string | Текст сообщения (пусто для нетекстового контента). |
| `message_uuid` | string | Идентификатор сообщения; для API-отправок совпадает с `QueuedResponse.message_uuid`. |
| `status` | string | Текущий статус сообщения (queued, sent, delivered, read, failed, …). |
| `sender` | string (CLIENT, COMPANY, AI) | Кто автор сообщения. |
| `timestamp` | string | Время события (ISO 8601). |

### outgoing_message

**Исходящее сообщение из канала**

Отправляется, когда сообщение уходит из канала — из интерфейса QNNECT,
по API или из интеграции. Контракт доставки как у `incoming_message`.


Payload:

| Поле | Тип | Описание |
|---|---|---|
| `event` | string (incoming_message, outgoing_message, message_status_update) | Тип события; совпадает с именем вебхука. |
| `phone` | string | Номер телефона пользователя WhatsApp. |
| `channel_id` | string | Идентификатор канала (Gupshup app id), к которому относится событие. |
| `text` | string | Текст сообщения (пусто для нетекстового контента). |
| `message_uuid` | string | Идентификатор сообщения; для API-отправок совпадает с `QueuedResponse.message_uuid`. |
| `status` | string | Текущий статус сообщения (queued, sent, delivered, read, failed, …). |
| `sender` | string (CLIENT, COMPANY, AI) | Кто автор сообщения. |
| `timestamp` | string | Время события (ISO 8601). |

### message_status_update

**Изменился статус доставки сообщения**

Отправляется, когда WhatsApp сообщает об изменении статуса ранее
отправленного сообщения (`sent` → `delivered` → `read` или `failed`).
Сопоставляйте по `message_uuid`. Контракт доставки как у
`incoming_message`.


Payload:

| Поле | Тип | Описание |
|---|---|---|
| `event` | string (incoming_message, outgoing_message, message_status_update) | Тип события; совпадает с именем вебхука. |
| `phone` | string | Номер телефона пользователя WhatsApp. |
| `channel_id` | string | Идентификатор канала (Gupshup app id), к которому относится событие. |
| `text` | string | Текст сообщения (пусто для нетекстового контента). |
| `message_uuid` | string | Идентификатор сообщения; для API-отправок совпадает с `QueuedResponse.message_uuid`. |
| `status` | string | Текущий статус сообщения (queued, sent, delivered, read, failed, …). |
| `sender` | string (CLIENT, COMPANY, AI) | Кто автор сообщения. |
| `timestamp` | string | Время события (ISO 8601). |
