Отправка сообщений из вашей системы
Полный гайд по отправке сообщений из внешней системы (AI-ассистент, бот, CRM): пошаговый сценарий (найти контакт, выбрать канал, отправить текст или шаблон WhatsApp, получать входящие через вебхук) и подробный справочник эндпоинтов — каналы, загрузка медиа и голосовых, отправка текста и шаблонов.
Типичная интеграция — AI-ассистент, чат-бот, CRM или скрипт автоматизации — которой нужно отправлять исходящие сообщения через подключённые к AISAR каналы (WhatsApp, Telegram, Instagram и т.д.) и получать ответы контактов. Этот сценарий проведёт вас от токена до полного цикла «отправили → получили ответ», а в конце — подробный справочник по каждому эндпоинту отправки.
Все запросы выполняются с Bearer-токеном компании (см. раздел «Аутентификация») и в её контексте:
Authorization: Bearer YOUR_API_TOKENШаг 1 — выбрать канал
Получите список каналов компании, чтобы узнать channel_id, через который будете отправлять:
curl "https://api.aisar.app/v1/channels?status=connected" \
-H "Authorization: Bearer YOUR_API_TOKEN"{
"data": [
{
"id": 57,
"name": "WhatsApp test",
"account_name": "+77001234567",
"status": "connected",
"channel_type": { "id": 1, "key": "whatsapp", "name": "WhatsApp" },
"message_operations": { "can_create": true },
"limits": { "max_text_length": 4096 }
}
]
}Перед отправкой проверяйте status === "connected" и message_operations.can_create === true. Полный перечень query-параметров и полей ответа /channels — в разделе «GET /channels» ниже.
Шаг 2 — найти или создать контакт (опционально)
Отдельно искать или создавать контакт перед отправкой не обязательно: /messages/send сам находит диалог по получателю или создаёт новый контакт, тред и диалог. Ищите контакт заранее, только если вам нужно проверить, существует ли он, или сохранить дополнительные поля (email, теги и т.д.) до первой отправки.
curl "https://api.aisar.app/v1/contacts?search=%2B77001234567" \
-H "Authorization: Bearer YOUR_API_TOKEN"curl -X POST https://api.aisar.app/v1/contacts \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"displayName": "Иван Иванов",
"phones": [{ "phone": "+77001234567", "type": "mobile" }]
}'Шаг 3 — отправить текстовое сообщение
curl -X POST https://api.aisar.app/v1/messages/send \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 57,
"recipient": "+77001234567",
"message_content": "Здравствуйте! Чем могу помочь?"
}'{
"success": true
}recipient — идентификатор получателя в формате, ожидаемом каналом: номер E.164 для WhatsApp/SMS, username или chat_id для Telegram Bot, IGSID для Instagram. Для отправки в группу WhatsApp передайте JID группы (<id>@g.us) — суффикс @g.us распознаётся автоматически.
conversation.create у владельца токена — без него ответ будет 403 Forbidden.Чтобы прикрепить медиа, сначала загрузите файл через POST /v1/uploads (получите media_id), затем передайте его в attachments:
curl -X POST https://api.aisar.app/v1/messages/send \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 57,
"recipient": "+77001234567",
"message_content": "Смотрите фото",
"attachments": [{ "media_id": "med_01HZABCDEFGHIJKLMNOPQRSTUV" }]
}'Подробности загрузки — в разделах «POST /uploads» (обычные файлы, идемпотентность, рассылка одного медиа на много контактов) и «POST /uploads/voice» (голосовые сообщения) ниже. Полный список полей /messages/send (is_group, is_silent, лимиты вложений) — в разделе «POST /messages/send».
Шаг 4 — отправить шаблон WhatsApp и 24-часовое окно
WhatsApp Business запрещает отправлять произвольные сообщения контакту, который не писал вам последние 24 часа — так называемое «24-часовое окно обслуживания клиента» (customer service window). Чтобы начать диалог вне этого окна или сделать рассылку, используйте одобренный Meta шаблон через /messages/send-template.
Сначала получите список одобренных шаблонов:
curl "https://api.aisar.app/v1/templates?channel_id=57&metaStatuses[]=approved" \
-H "Authorization: Bearer YOUR_API_TOKEN"Отправлять можно только шаблон со статусом meta_status: "approved". Затем отправьте его получателю:
curl -X POST https://api.aisar.app/v1/messages/send-template \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 57,
"recipient": "+77001234567",
"template_id": 42,
"params": { "name": "Иван", "order_id": "A-100" }
}'{
"success": true,
"message_id": 12345
}params заполняет переменные шаблона: именованной картой ({{name}}) или по позиции — массивом либо картой с числовыми ключами ({{1}}, {{2}}). Требуется то же разрешение conversation.create; канал должен быть типа whatsapp_business. Полный перечень параметров шаблонов (фильтры /templates, поля header_media_url, thread_id, is_silent, структура display и quick-reply кнопки) — в разделах «GET /templates» и «POST /messages/send-template» ниже.
Шаг 5 — получать входящие через вебхук
Чтобы реагировать на ответы контакта (диалоговый сценарий, например с AI-ассистентом), подпишитесь на событие message.created — см. раздел «Вебхуки». Типичный цикл: получаете message.created с direction: "inbound" → обрабатываете текст → вызываете /messages/send или /messages/send-template для ответа.
После каждой отправки (текстом или шаблоном) подписанные webhook-интеграции получают message.created с direction: "outbound", а затем message.status.updated по мере продвижения статуса доставки (sent → delivered → read, либо failed).
Когда контакт нажимает quick-reply кнопку отправленного шаблона, нажатие приходит как обычное входящее сообщение type: "text" с текстом кнопки — обрабатывайте его так же, как любой другой message.created.
Полный цикл
1. Внешняя система → GET /v1/channels
(узнать channel_id)
2. Внешняя система → POST /v1/messages/send
{ channel_id, recipient, message_content }
3. AISAR создаёт/находит диалог, создаёт сообщение
4. AISAR → POST {webhook_url} (event: message.created, direction: outbound)
5. Коннектор доставляет сообщение в мессенджер
6. AISAR → POST {webhook_url} (event: message.status.updated)
7. Контакт отвечает → AISAR → POST {webhook_url} (event: message.created, direction: inbound)
8. Внешняя система обрабатывает ответ → снова POST /v1/messages/sendСправочник эндпоинтов
Ниже — подробный справочник по каждому эндпоинту отправки: поля запроса, форма ответа и краевые случаи. Он дополняет пошаговый сценарий выше; все запросы выполняются с тем же Bearer-токеном компании и в её контексте.
GET /channels
Список каналов, доступных текущему пользователю в рамках компании — используйте, чтобы узнать channel_id для /messages/send.
| Query-параметр | Описание |
|---|---|
type | Фильтр по ключу типа канала: whatsapp, whatsapp_business, telegram, telegram_bot, instagram, instagram_business, facebook_messenger, tiktok, live_chat, sms |
status | Фильтр по статусу: connected, disconnected, paused и др. |
setup_state | Фильтр по состоянию настройки: Draft, Setup, Active, Paused |
{
"data": [
{
"id": 57,
"name": "WhatsApp test",
"account_name": "+77084252291",
"status": "connected",
"message_operations": {
"can_create": true,
"can_edit": true,
"edit_window_seconds": 900,
"revoke_window_seconds": 172800
},
"limits": {
"max_text_length": 4096,
"file_limits": { "image": { "max_size_mb": 16 }, "video": { "max_size_mb": 64 } }
},
"channel_type": { "id": 1, "key": "whatsapp", "name": "WhatsApp" },
"broadcast_rate_limits": { "daily_limit": 1500, "messages_per_minute": 15 }
}
]
}Перед отправкой проверяйте status === "connected" и message_operations.can_create === true.
POST /uploads
Загружает файл в AISAR и возвращает компактный media_id, который подставляется в /messages/send. Доставка в мессенджер выполняется коннектором без повторного скачивания. Поддерживаются два режима.
Режим A — multipart-загрузка
POST /v1/uploads
Authorization: Bearer YOUR_API_TOKEN
Content-Type: multipart/form-data
file=@photo.jpgМаксимум 64 МБ. Разрешённые расширения: jpg, jpeg, png, gif, webp, bmp, svg, mp4, mov, avi, wmv, webm, mkv, mp3, ogg, wav, aac, flac, m4a, opus, amr, pdf, doc, docx, xls, xlsx, csv, txt, rtf, ppt, pptx, zip, rar, 7z, gz, json, xml.
Режим B — загрузка по URL
POST /v1/uploads
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
{ "url": "https://cdn.example.com/photo.jpg" }AISAR один раз скачивает файл, сохраняет в своё хранилище и возвращает media_id. URL обязательно http/https, размер ≤ 64 МБ, таймаут скачивания 20 сек.
{
"media_id": "med_01HZABCDEFGHIJKLMNOPQRSTUV",
"type": "image",
"filename": "photo.jpg",
"mime_type": "image/jpeg",
"size": 123456,
"width": null,
"height": null,
"duration": null,
"expires_at": "2026-05-16T10:30:00.000000Z"
}media_id, файл не дублируется в хранилище. При рассылке одной картинки на 100 контактов достаточно одного POST /uploads, даже если вы вызвали его дважды по ошибке.Требуется разрешение conversation.view.
POST /uploads/voice
Загружает аудиозапись и транскодирует её в OGG/Opus — формат, в котором WhatsApp и Telegram отображают голосовое сообщение (voice note), а не прикреплённый файл. Это единственный корректный способ отправить голосовое через API: обычный /uploads сохраняет файл как есть (тип audio), и получателю придёт аудиофайл, а не голосовое.
POST /v1/uploads/voice
Authorization: Bearer YOUR_API_TOKEN
Content-Type: multipart/form-data
file=@voice.m4aПринимаются audio/webm, audio/ogg, audio/mp4, audio/mpeg, audio/wav, audio/aac, audio/x-m4a (а также video/webm — контейнер браузерной записи). Сервер сам приводит запись к OGG/Opus.
{
"media_id": "med_01HZABCDEFGHIJKLMNOPQRSTUV",
"type": "audio",
"filename": "voice.ogg",
"mime_type": "audio/ogg",
"size": 24576,
"duration": 7,
"expires_at": "2026-05-16T10:30:00.000000Z"
}type в ответе — audio (это медиа-ассет). Чтобы сообщение ушло именно голосовым, при отправке укажите attachments[].type: "voice" (см. ниже). Голосовые поддерживаются на WhatsApp (личный), WhatsApp Business, Telegram (личный) и Telegram Bot; на остальных каналах вложение уйдёт как обычный аудиофайл. Требуется разрешение conversation.view.POST /messages/send
Отправляет исходящее сообщение от имени канала конкретному получателю. Если диалог ещё не существует — будет создан.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
channel_id | integer | Да | ID канала отправки (из /channels) |
recipient | string | Да | Идентификатор получателя в формате, ожидаемом каналом: номер E.164, username Telegram, IGSID и т.д. Для групп WhatsApp — JID группы <id>@g.us. Максимум 255 символов. |
is_group | boolean | Нет | true — получатель является группой WhatsApp. Не обязателен, если recipient уже в форме <id>@g.us (суффикс распознаётся автоматически). По умолчанию false. |
is_silent | boolean | Нет | true — «тихая» отправка: счётчик непрочитанных у оператора не сбрасывается. По умолчанию false. Полезно для служебных сообщений. |
message_content | string | Условно | Текст сообщения, максимум 65 535 символов (фактический лимит канала — в limits.max_text_length из /channels). Обязателен, если нет attachments. |
attachments | array | Условно | 1–10 вложений. Обязательно, если нет message_content. Каждый элемент: media_id (обязательно) + опциональный type (image/video/audio/voice/document/file). |
{
"channel_id": 42,
"recipient": "+79001234567",
"message_content": "Здравствуйте! Чем могу помочь?"
}{
"channel_id": 42,
"recipient": "120363398017778174@g.us",
"message_content": "Всем привет в группе!"
}Где взять идентификатор группы: JID <id>@g.us приходит в вебхуках входящих сообщений и доступен в GET /v1/conversations — threads[].contact_account.external_id группового треда (threads[].is_group: true). Ограничения: группы поддерживаются только на каналах WhatsApp; аккаунт канала должен состоять в группе; противоречивый запрос (recipient оканчивается на @g.us, но is_group: false) отклоняется с 422.
{ "success": true }Поведение. Существующий диалог с получателем на этом канале переиспользуется; иначе создаётся новый (контакт-аккаунт, тред, диалог). После создания сообщения подписанные webhook-интеграции получают message.created с direction: outbound. Эндпоинт создаёт сообщение синхронно, но доставка в мессенджер выполняется асинхронно через очередь коннекторов — итоговый статус доставки приходит событием message.status.updated. Требуется разрешение conversation.create, иначе 403 Forbidden.
GET /templates
Список шаблонов сообщений компании — используйте, чтобы найти одобренные Meta шаблоны WhatsApp Business и их id для /messages/send-template.
| Query-параметр | Описание |
|---|---|
channel_id | Фильтр по конкретному каналу WhatsApp Business |
metaStatuses[] | Статус одобрения Meta: approved, rejected, pending. Для отправляемых — metaStatuses[]=approved |
channelType | Ключ типа канала (например whatsapp_business) |
language | BCP-47, например en, ru |
search | Поиск по имени/тексту/slug/меткам |
sortBy / sortDir | name, status, created_at, updated_at, uses_count, language; asc/desc |
{
"data": {
"items": [
{
"id": 42,
"name": "order_update",
"meta_status": "approved",
"language": "en",
"body": "Здравствуйте, {{name}}! Ваш заказ {{order_id}} готов.",
"parameters": [
{ "name": "name", "type": "text", "sample_value": "Иван", "position": 1 },
{ "name": "order_id", "type": "text", "sample_value": "A-100", "position": 2 }
],
"channel_type": { "id": 1, "key": "whatsapp_business", "name": "WhatsApp Business" },
"channel": { "id": 57, "name": "WhatsApp test", "account_name": "+77084252291" }
}
],
"pagination": { "page": 1, "perPage": 15, "total": 1, "lastPage": 1 }
}
}meta_status — статус одобрения Meta; отправлять можно только `approved`. body содержит плейсхолдеры ({{name}} или {{1}}), по которым вы определяете, какие params нужны в /messages/send-template. Требуется разрешение template.view.
template.approved и template.rejected — они приходят при изменении meta_status и позволяют инвалидировать кеш.POST /messages/send-template
Отправляет одобренный шаблон WhatsApp Business по получателю (recipient) или в существующий тред (thread_id) — передайте одно из двух — для инициации диалога вне 24-часового окна и для рассылок (по одному запросу на получателя). Если диалога с получателем ещё нет — он будет создан.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
channel_id | integer | Да | Должен быть типа whatsapp_business |
recipient | string | Условно (required_without:thread_id) | Номер в формате E.164, максимум 255 символов |
thread_id | integer | Условно (required_without:recipient) | ID существующего треда; альтернатива recipient — передайте одно из двух (min: 1) |
template_id | integer | Да | ID шаблона из /templates, должен принадлежать компании и иметь meta_status = approved |
params | object/array | Нет | Значения переменных шаблона (см. ниже). Опустите для шаблонов без переменных. |
header_media_url | string (url) | Нет | Для шаблонов с медиа-заголовком (image/video/document) |
is_silent | boolean | Нет | Как в /messages/send — не сбрасывает счётчик непрочитанных |
Сервер сам собирает Meta-структуру components из определения шаблона. Значения params передаются одним из двух способов: именованная карта для плейсхолдеров {{name}} ({ "name": "Иван", "order_id": "A-100" }) или по позиции для числовых {{1}}, {{2}} — карта с числовыми ключами либо обычный массив (["Иван", "A-100"], значения по порядку: заголовок → тело → кнопки).
{
"channel_id": 57,
"recipient": "+79001234567",
"template_id": 42,
"params": { "name": "Иван", "order_id": "A-100" }
}{
"success": true,
"message_id": 12345
}Поведение. Отправка разрешена только для каналов whatsapp_business и шаблонов с meta_status = approved — иначе 422. Если не хватает значения для переменной — 422 с перечислением недостающих параметров. Отправленное сообщение сохраняет отрисованную структуру шаблона в message_content.display (видна в GET /messages): header, body, footer, buttons[] — каждая кнопка { "type": "quick_reply" | "url" | "phone", "label": "...", "value": "..." }. Когда контакт нажимает quick-reply кнопку, нажатие приходит обратно как входящее сообщение type: "text" с текстом кнопки и content.interactive_reply_payload. Требуется разрешение conversation.create.
Ошибки и коды ответов
| Код | Причина | Как обрабатывать |
|---|---|---|
401 | Неверный или отсутствующий токен | Проверьте Authorization: Bearer {token} |
403 | У владельца токена нет разрешения conversation.create | Выдайте владельцу токена право conversation.create |
404 | Компания не найдена (токен не привязан к компании) | Проверьте, что токен привязан к компании |
422 | Ошибка валидации, либо канал не принадлежит компании, либо шаблон не одобрен | Проверьте тело запроса и статус шаблона |
429 | Превышен лимит запросов | Повторите с экспоненциальной задержкой |
Подробнее о формате ошибок — в разделе «Ошибки».