Рассылки
Массовые рассылки сообщений сегменту контактов по одному или нескольким каналам (WhatsApp/Telegram/Instagram). Группа покрывает весь жизненный цикл: создание черновика, публикацию и запуск(и), A/B-варианты, контроль скорости и окно отправки, отписки, отслеживание кликов, управление запусками и повторную отправку неудавшимся получателям. Все эндпоинты требуют активную подписку и фичу плана broadcasts.
Жизненный цикл и расписание
Рассылка может быть черновиком (is_draft: true) и позднее запускаться одним из способов:
- немедленно —
schedule.mode = now; - по расписанию —
later+scheduledAt; - по recurring-правилу —
recurrence.
Жизненный цикл: draft → publish → запуск(и) (run); каждый запуск отслеживает свой прогресс отдельно (sent/delivered/read/failed/skipped).
Статус рассылки (status): draft → scheduled/active → completed либо failed (cancelled при отмене). Для одноразовой рассылки (без recurring-расписания) статус failed выставляется, когда её запуск завершается с провалом или пропуском всех получателей — это же значение принимается фильтром statuses[] в GET /broadcasts. Повторная отправка неудавшимся получателям (retry-failed) возвращает такую рассылку обратно в scheduled.
A/B-варианты
Контент канала поддерживает A/B-варианты (2–3 на канал, content.channels[].variants): вариант назначается получателю детерминированно, разбивка статистики — в stats.byVariant.
Скорость отправки и окно
Скорость отправки регулируется через schedule.rateControl (messagesPerMinute, jitter, dailyLimit, skipContactedWithinHours) и окно sendWindow (режим smart шлёт каждому получателю в его исторически активный час).
Отписки (opt-out)
Контакты с opted_out_at всегда исключаются из аудитории; входящее сообщение-стоп-слово (stop/стоп/unsubscribe/отписаться) автоматически ставит opt-out.
Отслеживание кликов
При content.settings.trackClicks = true ссылки переписываются на трекинговые /r/{code} (публичный редирект без аутентификации учитывает клик и делает 302 на оригинал).
Управление запусками
Запуски можно ставить на паузу/возобновлять/отменять (pending-получатели → skipped), а неудавшихся получателей — отправлять повторно (retry-failed).
Валидация шаблона перед отправкой
Для записей content.channels[] с type = "template" перед стартом отправки проверяется, что на канале есть approved-версия выбранного шаблона. Проверка выполняется на трёх точках входа: POST /broadcasts (когда schedule.mode = "now"), POST /{broadcast}/run и POST /{broadcast}/publish. Если approved-шаблона нет, запрос отклоняется с 422, и errors.content[0] содержит сообщение вида Channel "..." has no approved template "..." (language ru). Approve this template for the channel or pick a channel where it is approved.
AI-помощник по тексту
AI-помощник текста (POST /broadcasts/assist, generate/improve) делит лимит 60/час с прочим AI-ассистом.
Эндпоинты
| Метод | Путь | Описание |
|---|---|---|
| GET | /v1/broadcasts/metaМетаданные конструктора рассылки (сегменты, переменные, шаблоны) | Метаданные конструктора рассылки (сегменты, переменные, шаблоны) |
| GET | /v1/broadcastsСписок рассылок (пагинация, фильтр по статусу) | Список рассылок (пагинация, фильтр по статусу) |
| GET | /v1/broadcasts/{broadcast}Получение рассылки | Получение рассылки |
| POST | /v1/broadcastsСоздание рассылки (поддерживает is_draft) | Создание рассылки (поддерживает is_draft) |
| PATCH | /v1/broadcasts/{broadcast}Обновление рассылки | Обновление рассылки |
| POST | /v1/broadcasts/{broadcast}Обновление рассылки (POST-алиас PATCH) | Обновление рассылки (POST-алиас PATCH) |
| DELETE | /v1/broadcasts/{broadcast}Удаление рассылки | Удаление рассылки |
| POST | /v1/broadcasts/estimateОценка размера аудитории рассылки | Оценка размера аудитории рассылки |
| POST | /v1/broadcasts/{broadcast}/duplicateДублирование рассылки | Дублирование рассылки |
| POST | /v1/broadcasts/{broadcast}/publishПубликация черновика (запуск/постановка на расписание) | Публикация черновика (запуск/постановка на расписание) |
| POST | /v1/broadcasts/{broadcast}/cancelОтмена разовой рассылки | Отмена разовой рассылки |
| POST | /v1/broadcasts/{broadcast}/runРучной запуск рассылки | Ручной запуск рассылки |
| GET | /v1/broadcasts/{broadcast}/messagesПолучатели запуска (пагинация, фильтр по статусу) | Получатели запуска (пагинация, фильтр по статусу) |
| GET | /v1/broadcasts/{broadcast}/runsСписок запусков рассылки | Список запусков рассылки |
| GET | /v1/broadcasts/{broadcast}/runs/{run}Получение конкретного запуска | Получение конкретного запуска |
| POST | /v1/broadcasts/{broadcast}/pause-recurringПауза recurring-расписания | Пауза recurring-расписания |
| POST | /v1/broadcasts/{broadcast}/resume-recurringВозобновление recurring-расписания | Возобновление recurring-расписания |
| POST | /v1/broadcasts/testОтправка тестового сообщения конкретному получателю | Отправка тестового сообщения конкретному получателю |
| POST | /v1/broadcasts/assistAI-помощник по тексту рассылки (generate/improve) | AI-помощник по тексту рассылки (generate/improve) |
| POST | /v1/broadcasts/{broadcast}/runs/{run}/pauseПауза запуска | Пауза запуска |
| POST | /v1/broadcasts/{broadcast}/runs/{run}/resumeВозобновление запуска | Возобновление запуска |
| POST | /v1/broadcasts/{broadcast}/runs/{run}/cancelОтмена запуска (pending-получатели → skipped) | Отмена запуска (pending-получатели → skipped) |
| POST | /v1/broadcasts/{broadcast}/runs/{run}/retry-failedПовторная отправка только failed-получателям | Повторная отправка только failed-получателям |
Примеры
Создание и немедленный запуск рассылки
Запрос
curl -X POST https://api.aisar.app/v1/broadcasts \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "February promo",
"is_draft": false,
"audience": { "segmentId": "12" },
"channels": { "mode": "specific", "channelIds": [7] },
"content": {
"channels": [
{ "type": "text", "channelId": 7, "accountType": "whatsapp", "text": "Hi {{first_name}}, 20% off this week!" }
]
},
"schedule": { "mode": "now" }
}'Ответ
{
"data": {
"id": 88,
"company_id": 1,
"name": "February promo",
"status": "active",
"audience": {
"conditions": [],
"group_logic": "and"
},
"channels": [{ "id": 7, "mode": "specific" }],
"content": [],
"schedule": { "mode": "now", "scheduledAt": null },
"recurring_schedule": null,
"runs": [
{ "id": 201, "broadcast_id": 88, "status": "processing", "total": 340, "sent": 0, "failed": 0, "delivered": 0, "read": 0, "started_at": "2026-03-15T10:00:00.000000Z", "completed_at": null }
],
"created_at": "2026-03-15T10:00:00.000000Z",
"updated_at": "2026-03-15T10:00:00.000000Z"
}
}Оценка аудитории рассылки
Запрос
curl -X POST https://api.aisar.app/v1/broadcasts/estimate \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"segment_id": 12,
"channel_ids": [7]
}'Ответ
{
"data": {
"total_contacts": 340,
"reachable_contacts": 312,
"excluded_contacts": 28,
"estimated_duration_seconds": 312,
"estimated_completion": "2026-03-15T10:05:12.000Z"
}
}Черновик с A/B-вариантами, контролем скорости и окном отправки
Запрос
curl -X POST https://api.aisar.app/v1/broadcasts \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Spring reactivation",
"is_draft": true,
"audience": { "segmentId": "12" },
"channels": { "mode": "specific", "channelIds": [7] },
"content": {
"channels": [
{
"type": "text",
"channelId": 7,
"accountType": "whatsapp",
"text": "Hi {{first_name}}, we miss you!",
"variants": [
{ "key": "A", "text": "Hi {{first_name}}, we miss you — here is 15% off." },
{ "key": "B", "text": "{{first_name}}, come back for 15% off this week." }
]
}
],
"settings": {
"trackClicks": true,
"includeOptOut": true,
"optOutText": "Reply STOP to unsubscribe"
}
},
"schedule": {
"mode": "later",
"scheduledAt": "2026-04-01T09:00:00Z",
"rateControl": {
"enabled": true,
"messagesPerMinute": 30,
"jitterMinSeconds": 2,
"jitterMaxSeconds": 8,
"dailyLimit": 5000,
"skipContactedWithinHours": 48
},
"sendWindow": {
"enabled": true,
"mode": "smart",
"startTime": "09:00",
"endTime": "20:00",
"timezone": "recipient"
}
}
}'Ответ
{
"data": {
"id": 89,
"company_id": 1,
"name": "Spring reactivation",
"status": "draft",
"audience": { "conditions": [], "group_logic": "and" },
"channels": [{ "id": 7, "mode": "specific" }],
"content": [],
"schedule": { "mode": "later", "scheduledAt": "2026-04-01T09:00:00.000000Z" },
"recurring_schedule": null,
"runs": [],
"created_at": "2026-03-20T12:00:00.000000Z",
"updated_at": "2026-03-20T12:00:00.000000Z"
}
}Публикация черновика (draft → scheduled)
Запрос
curl -X POST https://api.aisar.app/v1/broadcasts/89/publish \
-H "Authorization: Bearer YOUR_API_TOKEN"Ответ
{
"data": {
"id": 89,
"status": "scheduled",
"schedule": { "mode": "later", "scheduledAt": "2026-04-01T09:00:00.000000Z" },
"runs": [],
"updated_at": "2026-03-20T12:05:00.000000Z"
}
}Ошибка: на канале нет approved-шаблона
Запрос
curl -X POST https://api.aisar.app/v1/broadcasts/90/run \
-H "Authorization: Bearer YOUR_API_TOKEN"Ответ
{
"data": {
"message": "Channel \"WhatsApp Main\" has no approved template \"spring_promo\" (language ru). Approve this template for the channel or pick a channel where it is approved.",
"errors": {
"content": [
"Channel \"WhatsApp Main\" has no approved template \"spring_promo\" (language ru). Approve this template for the channel or pick a channel where it is approved."
]
}
}
}Тестовое сообщение перед запуском
Запрос
curl -X POST https://api.aisar.app/v1/broadcasts/test \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 7,
"recipient": "+77000000001",
"content": { "type": "text", "text": "Test: 15% off this week!" }
}'Ответ
{
"data": {
"message": "Test message queued.",
"message_id": "b1f2c3d4-EXAMPLE"
}
}AI-помощник по тексту рассылки
Запрос
curl -X POST https://api.aisar.app/v1/broadcasts/assist \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action": "improve",
"text": "hey buy our stuff now big sale",
"locale": "en"
}'Ответ
{
"data": {
"text": "Big news, {{first_name}} — our best sale of the season is live. Save 20% this week only.",
"action": "improve",
"tokens_used": 128
}
}Получатели запуска (фильтр по статусу failed)
Запрос
curl "https://api.aisar.app/v1/broadcasts/89/messages?status=failed&per_page=2" \
-H "Authorization: Bearer YOUR_API_TOKEN"Ответ
{
"data": [
{
"id": 7001,
"contact_id": 123,
"identifier": "+7700000XXXX",
"status": "failed",
"error_message": "recipient_not_on_whatsapp",
"attempts": 2,
"variant_key": "A",
"delivered_at": null,
"read_at": null,
"replied_at": null,
"clicked_at": null,
"contact": { "id": 123, "display_name": "Aylin Weber", "first_name": "Aylin", "last_name": "Weber" },
"channel": { "id": 7, "name": "WhatsApp Main" }
},
{
"id": 7002,
"contact_id": 124,
"identifier": "+7700000YYYY",
"status": "failed",
"error_message": "message_send_timeout",
"attempts": 3,
"variant_key": "B",
"delivered_at": null,
"read_at": null,
"replied_at": null,
"clicked_at": null,
"contact": { "id": 124, "display_name": "Marco Ricci", "first_name": "Marco", "last_name": "Ricci" },
"channel": { "id": 7, "name": "WhatsApp Main" }
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 2, "total": 2 }
}Повторная отправка неудавшимся получателям
Запрос
curl -X POST https://api.aisar.app/v1/broadcasts/89/runs/201/retry-failed \
-H "Authorization: Bearer YOUR_API_TOKEN"Ответ
{
"data": {
"id": 201,
"broadcast_id": 89,
"status": "processing",
"total": 340,
"sent": 300,
"failed": 0,
"delivered": 280,
"read": 190,
"started_at": "2026-04-01T09:00:00.000000Z",
"completed_at": null
}
}