批量模板消息 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。 - 用
show.js替换stats.js。 - 按照下表中的新字段名读取响应。
v2 接口只识别通过 v2 send 创建的批量操作。若要跟踪在切换之前用 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(条目) |
请求中、send 响应中以及记录上的 bulkMessageId | 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,并可通过isMerge与各收件人专属的payload合并 - 定时发送(
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 | 系统中已有用户的 ID。 |
sessionId | string | 系统中已有会话的 ID。 |
referenceId | string | 可选的引用 ID(最多 256 个字符),用于与外部系统记录(CRM、订单、工单等)对应。如果提供,在同一次批量请求中必须唯一。 |
payload | object | 收件人专属的模板载荷(可选)。如果 isMerge: true,则与 defaultPayload 合并。 |
isMerge | boolean | 覆盖该收件人的合并行为(可选)。如果省略,则使用 defaultPayload.isMerge。 |
操作结构
| 字段 | 类型 | 说明 |
|---|---|---|
action.key | string | "assign-to-user" 把会话分配给指定的客服;"assign-to-workgroup" 把会话分配给某个工作组。 |
action.value | string | 目标用户或工作组的 ID。 |
模板载荷结构
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 为每位收件人设置变量
每位收件人使用不同的变量值。在 defaultPayload 中设置 isMerge: true 后,收件人只需提供 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: true,无需在每位收件人的载荷中重复templateName - 每位收件人的
variables数组完全独立 - 标题媒体 URL 必须可公开访问
- 如果收件人载荷中省略了
type,则继承defaultPayload.type
4. URL 按钮变量
当模板包含带动态 URL 后缀的按钮时,请使用 BUTTONS 组件。例如,把运单号追加到基础 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 必须以 ISO 8601 UTC 时间戳的形式提供。
{
"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 | 是 | 要跟踪的批量操作 ID(由 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,但消息可能尚未送达或被阅读
引用 ID
referenceId 是一个可选字段,您可以用它把投递条目与您自己系统中的 ID(例如订单号、工单 ID)对应起来,便于追踪。它会以 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 | 是 | 要查询的批量操作 ID |
{
"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 | 条目总数 |
- 批量操作处于
running时,no-message数量较高表示投递仍在进行中 delivered数量显示消息成功送达的情况read数量可用于衡量活动的互动程度- 您可以定期轮询该接口,以实时跟踪
Options 结构:分页、筛选和排序
list 和 list-with-messages 接口中使用的 options 参数,为分页、筛选和排序提供了标准结构。
Options 字段
| 字段 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
pagination | object | 否 | 分页设置 |
filtering | object | 否 | 筛选条件 |
sorting | object | 否 | 排序设置(例如 {"position": 1}) |
分页结构
如果未发送 pagination,则返回第一页,最多 50 个条目。如果发送了该参数,则 currentPage 为必填。
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
currentPage | number | — | 要获取的页码(发送 pagination 时为必填) |
pageItems | number | 50 | 每页条目数(最大值:50) |
筛选结构
筛选使用 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
}
}
}
}
排序结构
排序使用 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 | 是 | 要列出的批量操作 ID |
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 | 条目 ID |
bulkOperationId | string | 该条目所属的批量操作 ID |
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 | 收件人的用户 ID |
result.sessionId | string | 会话 ID |
result.messageId | string | 已发送消息的 ID(如果未发送消息则不存在) |
completedAt | string | 条目被处理的时间 |
message | object | 消息详情(仅限 list-with-messages) |
session | object | 会话详情(仅限 list-with-messages) |
List 与 List-With-Messages 对比
| 功能 | list | list-with-messages |
|---|---|---|
| 分页 | 是 | 是 |
| 筛选 | 是(仅条目字段) | 是(条目 + 消息字段) |
| Message / Session | 否 | 是(如果存在) |
| 性能 | 快 | 中等(执行 JOIN) |
| message.status 筛选 | 不可用 | 可用 |
- list:快速列出所有条目、按 referenceId 筛选、检查条目状态
- list-with-messages:查看 WhatsApp 消息状态(delivered、read)、检查消息载荷
- 筛选示例:
{"status": "failed"}— 投递失败的条目{"payload.referenceId": "ORDER-123"}— 特定的引用 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 | 是 | 要停止的批量操作 ID |
{
"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.