Документация Bulk Template Message API — v2
Этот API позволяет одновременно отправлять шаблонные сообщения нескольким получателям через канал WhatsApp.
Доставка сообщений обрабатывается асинхронно: API-запрос сразу возвращает bulkOperationId, а сообщения ставятся в очередь и обрабатываются в фоновом режиме.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/send.js
Каждый эндпоинт в этом документе — это пользовательская функция (custom function). Тело HTTP-ответа содержит собственные поля функции (_id, title, pathString…), а фактический ответ эндпоинта находится в result. Примеры ответов в этом документе показывают содержимое result:
{
"_id": "function_id",
"title": "Show",
"pathString": "/bulk-message-api-app/api/v2/bulk-operation/show.js",
"result": {
"bulkOperation": { "_id": "abc123xyz789", "status": "running" }
}
}
Переход с v1
v2 работает параллельно с v1, поэтому вы можете перейти в удобное для вас время. Эндпоинты v1 (/api/bulk-message/…, /api/bulk-message-records/…) будут выведены из эксплуатации; для новых интеграций используйте v2.
- Перенесите пути эндпоинтов на v2:
…/api/bulk-message/…становится…/api/v2/bulk-operation/…, а…/api/bulk-message-records/…—…/api/v2/bulk-operation-items/…. Тело запросаsendне меняется; теперь один запрос принимает до 100 000 получателей вместо 5 000. - Передавайте в запросах
bulkOperationIdвместоbulkMessageId. - Замените
stats.jsнаshow.js. - Читайте ответы с новыми именами полей из таблицы ниже.
Эндпоинты v2 знают только массовые операции, созданные через send версии v2. Чтобы отслеживать массовую рассылку, созданную через v1 до перехода, продолжайте использовать для неё эндпоинты v1.
Эндпоинты
| v1 | v2 | Что меняется в ответе |
|---|---|---|
bulk-message/send.js | v2/bulk-operation/send.js | { bulkMessageId } становится { bulkOperationId } |
bulk-message/stats.js | v2/bulk-operation/show.js | { bulkMessage, stats } становится { bulkOperation } |
bulk-message/message-stats.js | v2/bulk-operation/message-stats.js | Счётчики находятся в корне, а не в messageStats |
bulk-message/stop.js | v2/bulk-operation/stop.js | Ничего |
bulk-message-records/list.js | v2/bulk-operation-items/list.js | bulkMessageRecords становится bulkOperationItems |
bulk-message-records/list-with-messages.js | v2/bulk-operation-items/list-with-messages.js | Как в list, и каждый элемент также содержит session |
Имена полей
| v1 | v2 |
|---|---|
stats.success | bulkOperation.progress.succeeded |
stats.pending, stats.failed, stats.cancelled, stats.total | bulkOperation.progress.pending, .failed, .cancelled, .total |
| — | bulkOperation.progress.unknown, bulkOperation.status, bulkOperation.result.outcome |
bulkMessage (массовая рассылка) | bulkOperation (массовая операция) |
bulkMessageRecord (запись) | bulkOperationItem (элемент) |
bulkMessageId в запросах, в ответе send и в записях | bulkOperationId |
username / userId / sessionId записи в том виде, как были отправлены | payload.username / payload.userId / payload.sessionId |
referenceId записи | payload.referenceId |
payload записи (шаблонная нагрузка получателя) | payload.payload |
userId, sessionId, messageId записи после отправки | result.userId, result.sessionId, result.messageId |
статус записи success | succeeded |
errorMessage у неудачных записей | error.message, рядом с error.code и error.retryable |
| — | position (индекс получателя в recipients) |
фильтр {"status": "success"} | {"status": "succeeded"} |
фильтр {"referenceId": "…"} | {"payload.referenceId": "…"} |
ошибки send schema-error, invalidRequest | zod-schema-error, с путём к недопустимому полю в сообщении |
Ключевые возможности
- Отправка массовых шаблонных сообщений 1–100 000 получателям в одном запросе
- Персонализированные переменные для каждого получателя (HEADER, BODY, BUTTONS, CAROUSEL)
- Общий
defaultPayloadдля всех получателей с объединением с индивидуальнымpayloadполучателя (isMerge) - Отложенная отправка (
scheduleAt) - Указание получателей через
username(номер телефона),userIdилиsessionId - Отправка нескольких сообщений одному пользователю в одном массовом запросе
- Необязательный
referenceIdдля сопоставления записей с внешними системами - Автоматическое назначение диалогов пользователю или рабочей группе после отправки (
action)
Через этот API можно отправлять только шаблоны, одобренные Meta.
Название шаблона и код языка должны в точности совпадать с шаблоном, зарегистрированным в Meta Business Manager.
Параметры запроса
Параметры верхнего уровня
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
channelUsername | string | Да | Номер канала WhatsApp, с которого отправляется сообщение (например, "908506669933") |
connectorBrand | string | Да | Бренд коннектора канала. Сейчас поддерживается значение: "whatsapp" |
title | string | Нет | Название кампании. Используется для отображения на панели. По умолчанию: "-" |
scheduleAt | string (ISO 8601) | Нет | Дата и время отложенной отправки (например, "2026-06-10T10:00:00.000Z"). Если не указано, сообщения отправляются сразу. |
defaultPayload | object | Условно* | Шаблонная нагрузка по умолчанию, применяемая ко всем получателям. Обязательна, если у получателя нет собственного payload. |
recipients | array | Да | Список получателей. Минимум 1, максимум 100 000 получателей. |
action | object | Нет | Действие, применяемое к диалогу после отправки. assign-to-user или assign-to-workgroup. |
*Если у каждого получателя есть собственный payload, defaultPayload необязателен.
Структура получателя
Для каждого получателя нужно указать ровно один из параметров username, userId или sessionId. Несколько идентификаторов одновременно использовать нельзя, а если не указан ни один, будет ошибка.
Чтобы отправить несколько сообщений одному пользователю в одном массовом запросе, добавьте один и тот же идентификатор в список получателей несколько раз.
| Поле | Тип | Описание |
|---|---|---|
username | string | Номер телефона получателя (например, "905554443322"). Если пользователя нет в системе, он создаётся автоматически. |
userId | string | Идентификатор существующего пользователя в системе. |
sessionId | string | Идентификатор существующего диалога в системе. |
referenceId | string | Необязательный идентификатор для сопоставления с записями внешней системы (CRM, заказ, заявка и т. д.), до 256 символов. Если указан, должен быть уникальным в рамках одной рассылки. |
payload | object | Шаблонная нагрузка для конкретного получателя (необязательно). Если isMerge: true, она объединяется с defaultPayload. |
isMerge | boolean | Переопределяет поведение объединения для этого получателя (необязательно). Если не указано, используется defaultPayload.isMerge. |
Структура действия
| Поле | Тип | Описание |
|---|---|---|
action.key | string | "assign-to-user" назначает диалог конкретному сотруднику; "assign-to-workgroup" назначает его рабочей группе. |
action.value | string | Идентификатор целевого пользователя или рабочей группы. |
Структура шаблонной нагрузки
defaultPayload и payload конкретного получателя имеют одинаковую структуру. Для шаблонных сообщений необходимо указать type: "template".
{
"type": "template",
"template": {
"templateName": "order_confirmation",
"languageCode": "tr-TR",
"variables": []
},
"isMerge": true
}
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
type | string | Да | Тип нагрузки. Для шаблонных сообщений: "template" |
template.templateName | string | Да* | Название шаблона, зарегистрированного в Meta. В нагрузке получателя необязательно, если используется isMerge: true (наследуется из нагрузки по умолчанию). |
template.languageCode | string | Нет | Код языка шаблона (например, "tr", "en", "tr-TR", "en-US"). Должен в точности совпадать с языком, зарегистрированным в Meta. |
template.variables | array | Нет | Список переменных, применяемых к компонентам шаблона. Подробности ниже. |
isMerge | boolean | Нет | true: нагрузка получателя глубоко объединяется с defaultPayload. false или не указано: нагрузка получателя полностью заменяет defaultPayload. |
- Если
defaultPayload.isMerge: trueи получатель передаёт собственныйpayload, применяется глубокое объединение. - При глубоком объединении получатель может указать только
variables;templateNameиlanguageCodeнаследуются из нагрузки по умолчанию. - Поле
isMergeполучателя переопределяетdefaultPayload.isMerge. - Если получатель не передаёт
payload, всегда используетсяdefaultPayload.
Структура переменных
Каждый элемент массива variables соответствует компоненту шаблона. Тип компонента (type) может встречаться в массиве только один раз.
| type | Описание | parameters | cards |
|---|---|---|---|
"HEADER" | Компонент заголовка шаблона. Текстовая переменная или URL медиафайла (изображение, видео, документ) | Да | — |
"BODY" | Текстовые переменные тела шаблона | Да | — |
"BUTTONS" | Переменные динамического суффикса URL для кнопок | Да | — |
"CAROUSEL" | Компоненты карточек для шаблонов-каруселей | — | Да |
Форматы параметров
Поле parameters можно передавать в трёх разных форматах:
// Format 1: Array (index-based) — for placeholders like {{1}}, {{2}}, {{3}}
"parameters": ["value1", "value2", "value3"]
// Format 2: Object (numeric keys) — alternative representation for {{1}}, {{2}}
"parameters": { "1": "value1", "2": "value2" }
// Format 3: Object (named keys) — for placeholders like {{name}}, {{amount}}
"parameters": { "name": "John", "amount": "150 USD" }
- Если в вашем шаблоне Meta используются подстановки вида
{{1}},{{2}}, применяйте формат массива или объект с числовыми ключами. - Если в шаблоне используются именованные подстановки, например
{{firstName}}или{{orderTotal}}, применяйте объект с именованными ключами. - При использовании массивов важен порядок: первый элемент соответствует
{{1}}, второй —{{2}}и так далее.
Компонент HEADER
Используйте компонент HEADER, если заголовок шаблона содержит медиафайл (изображение, видео, документ) или динамический текст.
// Media header (image URL)
{
"type": "HEADER",
"parameters": ["https://example.com/product-image.jpg"]
}
// Text header variable
{
"type": "HEADER",
"parameters": ["Special Campaign"]
}
Компонент BODY
Используется для динамических текстовых переменных в теле шаблона.
// Array format — when the template uses {{1}}, {{2}}, {{3}}
{
"type": "BODY",
"parameters": ["John", "ORD-12345", "150.00 USD"]
}
// Named format — when the template uses {{name}}, {{orderAmount}}
{
"type": "BODY",
"parameters": {
"name": "John",
"orderAmount": "150.00 USD"
}
}
Компонент BUTTONS
Используется для кнопок с динамическими суффиксами URL. Если в шаблоне несколько URL-кнопок, последовательно нумеруются только кнопки с переменными (кнопки без переменных и кнопки FLOW игнорируются).
// Single URL button suffix variable
{
"type": "BUTTONS",
"parameters": ["tracking/ORD-12345"]
}
// Multiple URL button suffix variables (first URL button, second URL button)
{
"type": "BUTTONS",
"parameters": ["tracking/ORD-12345", "cancel/ORD-12345"]
}
Компонент CAROUSEL
Для шаблонов-каруселей переменные компонентов задаются отдельно для каждой карточки.
{
"type": "CAROUSEL",
"cards": [
{
"components": [
{
"type": "HEADER",
"parameters": ["https://example.com/card1.jpg"]
},
{
"type": "BODY",
"parameters": ["Product A", "99.00 USD"]
}
]
},
{
"components": [
{
"type": "HEADER",
"parameters": ["https://example.com/card2.jpg"]
},
{
"type": "BODY",
"parameters": ["Product B", "149.00 USD"]
}
]
}
]
}
Длина массива cards должна в точности совпадать с количеством карточек, определённых в шаблоне.
Примеры
1. Простой шаблон — без переменных, одинаковое содержимое для всех получателей
Это самый простой способ отправить статичный шаблон без переменных нескольким получателям.
{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "General Announcement",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "hello_world",
"languageCode": "tr-TR"
}
},
"recipients": [{ "username": "905554443301" }, { "username": "905554443302" }, { "username": "905554443303" }]
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/send.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "General Announcement",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "hello_world",
"languageCode": "tr-TR"
}
},
"recipients": [
{ "username": "905554443301" },
{ "username": "905554443302" },
{ "username": "905554443303" }
]
}'
- Получатели, указанные через
username, создаются автоматически, если их ещё нет в системе - Все получатели используют один и тот же
defaultPayload; данные для конкретных получателей не требуются - Если
isMergeне указан, каждый получатель напрямую используетdefaultPayload
2. Шаблон с общими переменными тела
Один и тот же шаблон отправляется всем получателям с одинаковыми значениями переменных. В шаблоне есть подстановки вроде {{1}} и {{2}}.
{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Summer Campaign",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "promo_notification",
"languageCode": "tr-TR",
"variables": [
{
"type": "BODY",
"parameters": ["30%", "July 31, 2026"]
}
]
}
},
"recipients": [{ "username": "905554443301" }, { "username": "905554443302" }]
}
- В этом примере тело шаблона может содержать текст вроде: «Скидка
{{1}}в нашей акции! Предложение действует до{{2}}.» parameters[0]заменяет{{1}}, аparameters[1]заменяет{{2}}
3. Персонализированный шаблон — переменные для каждого получателя с isMerge
Для каждого получателя используются разные значения переменных. Если задать isMerge: true в defaultPayload, получателям достаточно передать только variables; templateName и languageCode наследуются из нагрузки по умолчанию.
В этом примере шаблон содержит и медиазаголовок, и персонализированные переменные тела.
{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Personal Order Notification",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "order_confirmation",
"languageCode": "tr-TR"
},
"isMerge": true
},
"recipients": [
{
"username": "905554443301",
"payload": {
"template": {
"variables": [
{
"type": "HEADER",
"parameters": ["https://s3.example.com/product-a.jpg"]
},
{
"type": "BODY",
"parameters": ["Ahmet", "ORD-001", "150.00 TRY"]
}
]
}
}
},
{
"username": "905554443302",
"payload": {
"template": {
"variables": [
{
"type": "HEADER",
"parameters": ["https://s3.example.com/product-b.jpg"]
},
{
"type": "BODY",
"parameters": ["Fatma", "ORD-002", "289.00 TRY"]
}
]
}
}
}
]
}
- Благодаря
isMerge: truetemplateNameне нужно повторять в нагрузке каждого получателя - Массив
variablesкаждого получателя полностью независим - URL медиафайла заголовка должен быть общедоступным
- Если в нагрузке получателя не указан
type, наследуетсяdefaultPayload.type
4. Переменная URL-кнопки
Используйте компонент BUTTONS, если в шаблоне есть кнопка с динамическим суффиксом URL. Например, номер отслеживания, добавляемый к базовому URL https://example.com/track/.
{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Shipment Tracking Notification",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "shipment_tracking",
"languageCode": "tr-TR"
},
"isMerge": true
},
"recipients": [
{
"username": "905554443301",
"payload": {
"template": {
"variables": [
{
"type": "BODY",
"parameters": ["Ahmet", "TK-98765"]
},
{
"type": "BUTTONS",
"parameters": ["TK-98765"]
}
]
}
}
},
{
"username": "905554443302",
"payload": {
"template": {
"variables": [
{
"type": "BODY",
"parameters": ["Recep", "TK-12345"]
},
{
"type": "BUTTONS",
"parameters": ["TK-12345"]
}
]
}
}
}
]
}
- Параметры
BUTTONSсопоставляются в порядке кнопок, содержащих переменные - Кнопки FLOW и кнопки без переменных игнорируются; нумерация применяется только к кнопкам с динамическим URL
- Если URL кнопки в шаблоне —
https://example.com/track/{{1}}, тоparameters[0]заменяет{{1}}
5. Отложенная отправка
Запланируйте отправку сообщения на будущую дату и время. scheduleAt нужно передавать как метку времени UTC в формате ISO 8601.
{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Morning Campaign Message",
"scheduleAt": "2026-06-10T07:00:00.000Z",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "morning_campaign",
"languageCode": "en-US"
},
"isMerge": true
},
"action": {
"key": "assign-to-workgroup",
"value": "WORKGROUP_ID"
},
"recipients": [
{
"username": "905554443301",
"payload": {
"template": {
"variables": [
{
"type": "BODY",
"parameters": { "name": "Ahmet", "discountRate": "25" }
}
]
}
}
},
{
"username": "905554443302",
"payload": {
"template": {
"variables": [
{
"type": "BODY",
"parameters": { "name": "Zeynep", "discountRate": "40" }
}
]
}
}
}
]
}
scheduleAtнужно передавать в часовом поясе UTC (например, для 10:00 по времени Турции используйте07:00:00.000Z)- В этом примере используется формат именованных параметров; в шаблоне должны быть подстановки вроде
{{name}}и{{discountRate}} - С параметром
actionдиалоги, созданные при доставке сообщения, автоматически назначаются указанной рабочей группе
Ответ
Успешный запрос возвращает bulkOperationId, с помощью которого можно отслеживать процесс доставки:
{
"bulkOperationId": "abc123xyz789"
}
Ответы с ошибкой
| Статус | Описание |
|---|---|
recipients field is required | Поле recipients не передано |
Channel not found | Не найден верифицированный канал, соответствующий channelUsername и connectorBrand |
Channel is not verified | Подходящий канал существует, но ещё не верифицирован |
zod-schema-error | Поле тела запроса не прошло проверку схемы (отсутствует обязательное поле, неверный тип, неподдерживаемое значение, у получателя указано больше одного идентификатора или отсутствует payload). В сообщении указано поле, например recipients.0.referenceId: referenceId must be unique |
Возвращённый bulkOperationId можно использовать в эндпоинтах ниже, чтобы запрашивать статистику доставки и останавливать процесс доставки.
Show — статус и статистика массовой операции
Возвращает массовую операцию с её текущим статусом и счётчиками доставки её элементов в ключе bulkOperation.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/show.js
Параметры запроса
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
bulkOperationId | string | Да | Идентификатор отслеживаемой массовой операции (возвращается из send) |
{
"bulkOperationId": "abc123xyz789"
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/show.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"bulkOperationId": "abc123xyz789"
}'
Ответ
{
"bulkOperation": {
"_id": "abc123xyz789",
"type": "send-bulk-message",
"slug": "my-workspace",
"userId": "agent_user_id",
"payload": {
"title": "Campaign Title",
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"connectorSlug": "om2WabVegaCloud",
"defaultLanguageCode": "tr-TR",
"sentUser": { "firstname": "John", "lastname": "Doe" },
"defaultPayload": {
"type": "template",
"template": { "templateName": "order_confirmation", "languageCode": "tr-TR" },
"isMerge": true
},
"source": { "type": "recipients", "bulkOperationInputGroupId": "group_id" }
},
"status": "running",
"result": { "outcome": "unknown", "hasErrors": false },
"progress": {
"total": 100,
"pending": 45,
"succeeded": 42,
"failed": 3,
"cancelled": 10,
"unknown": 0
},
"scheduleAt": "2026-06-10T07:00:00.000Z",
"createdAt": "2026-06-08T10:00:00.000Z",
"updatedAt": "2026-06-10T07:00:30.000Z",
"startedAt": "2026-06-10T07:00:05.000Z"
}
}
Поля Show
Поля находятся в bulkOperation.
| Поле | Тип | Описание |
|---|---|---|
status | string | Статус массовой операции: preparing, scheduled, pending, running, stopping, stopped, completed, failed |
progress.total | number | Общее количество элементов |
progress.pending | number | Элементы, всё ещё ожидающие в очереди |
progress.succeeded | number | Элементы, успешно обработанные для доставки |
progress.failed | number | Элементы, при доставке которых возникла ошибка |
progress.cancelled | number | Элементы, отменённые через stop |
progress.unknown | number | Элементы, результат которых не удалось определить |
result.outcome | string | Итоговый результат после завершения массовой операции: success, partial, all-failed, cancelled, unknown |
result.hasErrors | boolean | true, если хотя бы один элемент завершился ошибкой |
scheduleAt | string | Запланированное время доставки (только для отложенных массовых операций) |
startedAt, completedAt | string | Время начала и окончания доставки |
progress.succeeded означает, что сообщение успешно передано системой. Это не гарантирует, что Meta доставила сообщение получателю. Последующие обновления статуса от Meta (такие как delivered, read или failed) не влияют на этот счётчик и здесь не отражаются.
- Эндпоинт show: показывает статус доставки элементов (
pending,succeeded,failed,cancelled,unknown) - Эндпоинт message-stats: показывает фактический статус сообщений (
pending,sending,sent,delivered,read,errorи т. д.) - Элемент может быть в статусе
succeeded, но сообщение при этом ещё может быть не доставлено или не прочитано
Reference ID
referenceId — необязательное поле, которое можно использовать, чтобы сопоставлять элементы доставки с идентификатором из вашей собственной системы для отслеживания (например, номер заказа, идентификатор заявки). Оно возвращается в каждом элементе как payload.referenceId.
Если поле указано, оно должно быть уникальным в рамках рассылки (максимум 256 символов).
- Использовать необязательно
- Нельзя дублировать в рамках одной массовой операции
- Можно повторно использовать в разных массовых операциях
Message Stats — статус сообщений WhatsApp
Возвращает статистику статусов сообщений массовой операции. В отличие от эндпоинта show, здесь показывается фактический message.status отправленных сообщений, а не статус элемента.
Возможные статусы сообщений: pending, sending, sent, delivered, read, deleted, warning, error, unknown, not-sended
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/message-stats.js
Параметры запроса
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
bulkOperationId | string | Да | Идентификатор запрашиваемой массовой операции |
{
"bulkOperationId": "abc123xyz789"
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/message-stats.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"bulkOperationId": "abc123xyz789"
}'
Ответ
{
"pending": 5,
"sending": 2,
"sent": 10,
"delivered": 45,
"read": 30,
"deleted": 2,
"warning": 1,
"error": 3,
"unknown": 0,
"not-sended": 2,
"no-message": 20,
"total": 120
}
Поля Message Stats
| Поле | Тип | Описание |
|---|---|---|
pending | number | Сообщения, которые ещё не отправлены |
sending | number | Сообщения, отправляемые в данный момент |
sent | number | Сообщения, переданные в WhatsApp, но ещё не доставленные |
delivered | number | Сообщения, доставленные на телефон получателя |
read | number | Сообщения, прочитанные получателем |
deleted | number | Удалённые сообщения |
warning | number | Сообщения с предупреждениями |
error | number | Сообщения с ошибками |
unknown | number | Сообщения с неизвестным статусом |
not-sended | number | Сообщения, которые не удалось отправить |
no-message | number | Элементы без сообщения (всё ещё в очереди, завершились ошибкой или отменены) |
total | number | Общее количество элементов |
- Большое значение
no-message, пока массовая операция находится в статусеrunning, означает, что доставка ещё продолжается - Значение
deliveredпоказывает успешную доставку сообщений - Значение
readможно использовать для измерения вовлечённости в кампанию - Вы можете периодически опрашивать этот эндпоинт для отслеживания в реальном времени
Структура Options — постраничный вывод, фильтрация и сортировка
Параметр options, используемый в эндпоинтах list и list-with-messages, задаёт стандартную структуру для постраничного вывода, фильтрации и сортировки.
Поля Options
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
pagination | object | Нет | Настройки постраничного вывода |
filtering | object | Нет | Критерии фильтрации |
sorting | object | Нет | Настройки сортировки (например, {"position": 1}) |
Структура Pagination
Если pagination не передан, возвращается первая страница, содержащая до 50 элементов. Если он передан, currentPage обязателен.
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
currentPage | number | — | Номер запрашиваемой страницы (обязателен, если передан pagination) |
pageItems | number | 50 | Количество элементов на странице (максимум: 50) |
Структура Filtering
Фильтрация выполняется в формате запросов MongoDB по полям элементов, с именами полей точно в том виде, в каком они приходят в ответе (например, status, payload.referenceId, result.messageId). В эндпоинте list-with-messages можно также фильтровать по полям сообщений (например, message.status).
// Filter by item status
{
"options": {
"filtering": {
"status": "succeeded"
}
}
}
// Filter by referenceId
{
"options": {
"filtering": {
"payload.referenceId": "ORDER-12345"
}
}
}
// Filter by message status (only list-with-messages)
{
"options": {
"filtering": {
"message.status": "delivered"
}
}
}
// Filter by multiple statuses using $in (MongoDB operator)
{
"options": {
"filtering": {
"message.status": {
"$in": ["delivered", "read"]
}
}
}
}
// Exclude specific statuses using $nin (MongoDB operator)
{
"options": {
"filtering": {
"message.status": {
"$nin": ["error", "not-sended"]
}
}
}
}
// List items that have no message (only list-with-messages)
{
"options": {
"filtering": {
"message": {
"$exists": false
}
}
}
}
Структура Sorting
Сортировка выполняется в формате сортировки MongoDB. 1 означает по возрастанию, -1 — по убыванию. position — порядковый номер получателя в массиве recipients запроса (начиная с 0).
// Sort in the order the recipients were sent in the request
{
"options": {
"sorting": {
"position": 1
}
}
}
// Sort by multiple fields
{
"options": {
"sorting": {
"status": 1,
"position": 1
}
}
}
Пример комбинированного использования
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 2,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
},
"sorting": {
"position": 1
}
}
}
Этот пример выводит вторую страницу доставленных сообщений в порядке получателей.
- Сочетайте
filteringиpaginationдля точечных запросов - Ответ содержит
options.pagination.totalCountиoptions.pagination.totalPagesдля навигации - Фильтр
message.statusработает только в эндпоинтеlist-with-messages
Items — сведения об элементах и их список
Возвращает список всех элементов доставки массовой операции. Каждый элемент соответствует одной записи массива recipients.
List — список элементов
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation-items/list.js
Параметры запроса
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
bulkOperationId | string | Да | Идентификатор массовой операции, элементы которой нужно вывести |
options | object | Нет | Параметры постраничного вывода, фильтрации и сортировки. Подробности см. в разделе Структура Options. |
Запрос — базовое использование
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
Запрос — фильтр по конкретному статусу
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"status": "failed"
}
}
}
Выводит только элементы с неудачной доставкой, причина указана в error.
Ответ
{
"bulkOperationItems": [
{
"_id": "item_1",
"bulkOperationId": "abc123xyz789",
"bulkOperationBatchId": "batch_1",
"slug": "my-workspace",
"position": 0,
"payload": {
"username": "905554443301",
"referenceId": "ORDER-12345",
"payload": {
"template": {
"variables": [{ "type": "BODY", "parameters": ["Ahmet", "ORD-001"] }]
}
}
},
"status": "succeeded",
"attempt": 1,
"result": {
"userId": "user_123",
"sessionId": "session_456",
"messageId": "msg_789"
},
"createdAt": "2026-06-10T10:00:00.000Z",
"updatedAt": "2026-06-10T10:00:01.000Z",
"completedAt": "2026-06-10T10:00:01.000Z"
},
{
"_id": "item_2",
"bulkOperationId": "abc123xyz789",
"bulkOperationBatchId": "batch_1",
"slug": "my-workspace",
"position": 1,
"payload": { "username": "905554443302", "referenceId": "ORDER-12346" },
"status": "failed",
"attempt": 1,
"error": { "code": "error", "message": "Variable missing", "retryable": false },
"result": { "userId": "user_124", "sessionId": "session_457" },
"createdAt": "2026-06-10T10:00:00.000Z",
"updatedAt": "2026-06-10T10:00:01.000Z",
"completedAt": "2026-06-10T10:00:01.000Z"
}
],
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50,
"totalCount": 150,
"totalPages": 3
},
"sorting": {},
"filtering": {},
"searching": {}
}
}
List With Messages — список со сведениями о сообщениях
Имеет те же возможности, что и эндпоинт list (постраничный вывод, фильтрация, сортировка). Отличие: каждый элемент также содержит связанные объекты message и session, если они существуют. Это позволяет увидеть статус сообщения (delivered, read, error и т. д.) и его нагрузку одним запросом.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation-items/list-with-messages.js
Запрос — базовое использование
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
Запрос — фильтр по статусу сообщения
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
}
}
}
Этот пример выбирает только сообщения со статусом "delivered".
Запрос — список неудачных сообщений
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "error"
}
}
}
Используется для просмотра сообщений, при доставке которых возникли ошибки.
Ответ
{
"bulkOperationItems": [
{
"_id": "item_1",
"bulkOperationId": "abc123xyz789",
"position": 0,
"payload": { "username": "905554443301", "referenceId": "ORDER-12345" },
"status": "succeeded",
"result": {
"userId": "user_123",
"sessionId": "session_456",
"messageId": "msg_789"
},
"message": {
"_id": "msg_789",
"type": "template",
"status": "delivered",
"payload": {
"template": {
"name": "order_notification"
}
},
"createdAt": "2026-06-10T10:01:00.000Z"
},
"session": {
"_id": "session_456",
"status": "opened"
}
}
],
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50,
"totalCount": 150,
"totalPages": 3
},
"sorting": {},
"filtering": {},
"searching": {}
}
}
Поля элемента
| Поле | Тип | Описание |
|---|---|---|
_id | string | Идентификатор элемента |
bulkOperationId | string | Идентификатор массовой операции, которой принадлежит элемент |
position | number | Порядковый номер получателя в массиве recipients запроса, начиная с 0 |
payload | object | Получатель точно в том виде, в каком он был отправлен в запросе (username / userId / sessionId, referenceId, payload, isMerge) |
status | string | Статус элемента: pending, succeeded, failed, cancelled, unknown |
error | object | Только у элементов failed: code, message и retryable |
result.userId | string | Идентификатор пользователя-получателя |
result.sessionId | string | Идентификатор диалога |
result.messageId | string | Идентификатор отправленного сообщения (отсутствует, если сообщение не отправлено) |
completedAt | string | Время обработки элемента |
message | object | Сведения о сообщении (только в list-with-messages) |
session | object | Сведения о диалоге (только в list-with-messages) |
Сравнение List и List-With-Messages
| Возможность | list | list-with-messages |
|---|---|---|
| Постраничный вывод | Да | Да |
| Фильтрация | Да (только по полям элемента) | Да (по полям элемента и сообщения) |
| Сообщение / диалог | Нет | Да (если существуют) |
| Производительность | Быстро | Средне (выполняется JOIN) |
| Фильтр message.status | Недоступен | Доступен |
- list: быстро вывести все элементы, отфильтровать по referenceId, проверить статусы элементов
- list-with-messages: посмотреть статусы сообщений WhatsApp (delivered, read), изучить нагрузку сообщений
- Примеры фильтров:
{"status": "failed"}— элементы с неудачной доставкой{"payload.referenceId": "ORDER-123"}— конкретный reference ID{"message.status": "delivered"}— доставленные сообщения (только list-with-messages){"message.status": "read"}— прочитанные сообщения (только list-with-messages){"message.status": "error"}— сообщения с ошибками (только list-with-messages){"message.status": {"$in": ["delivered", "read"]}}— сообщения, которые доставлены или прочитаны (только list-with-messages){"message.status": {"$nin": ["error", "not-sended"]}}— сообщения, кроме ошибочных и неотправленных (только list-with-messages){"message": {"$exists": false}}— элементы без сообщения (только list-with-messages){"status": {"$in": ["succeeded", "pending"]}}— элементы, которые успешны или ожидают
- Эндпоинт
listработает быстрее; используйте его для обычной проверки статусов - Используйте
list-with-messages, когда нужны сведения о сообщениях - Максимальное количество элементов на странице (pageItems) — 50; если не указано, по умолчанию 50
- Фильтр
message.statusработает только вlist-with-messages - У элементов без
result.messageIdнет объектаmessage
Stop — отмена доставки
Останавливает выполняющуюся доставку массовой операции. Все элементы со статусом pending переводятся в статус cancelled, а массовая операция переходит в статус stopped. Элементы, уже обработанные как succeeded или failed, не затрагиваются. Отложенную массовую операцию также можно остановить до наступления времени scheduleAt.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/stop.js
Это действие нельзя отменить. Остановленную доставку нельзя возобновить.
Параметры запроса
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
bulkOperationId | string | Да | Идентификатор останавливаемой массовой операции |
{
"bulkOperationId": "abc123xyz789"
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/stop.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"bulkOperationId": "abc123xyz789"
}'
Ответ
При успешном запросе тело ответа пустое. Статус HTTP 200 означает, что операция выполнена успешно.
{}
- Остановить можно только массовые операции, созданные через этот API
- После остановки доставки можно использовать эндпоинт
show, чтобы проверить количество отменённых элементов (bulkOperation.progress.cancelled) - Если массовая операция не найдена, API возвращает ошибку:
Bulk operation not found.