Tài liệu Bulk Template Message API — v2
API này cho phép bạn gửi tin nhắn mẫu đến nhiều người nhận cùng lúc qua kênh WhatsApp.
Việc gửi tin được xử lý bất đồng bộ; yêu cầu API trả về ngay một bulkOperationId, trong khi các tin nhắn được đưa vào hàng đợi và xử lý ở chế độ nền.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/send.js
Mọi endpoint trong tài liệu này đều là một custom function. Nội dung phản hồi HTTP chứa các trường của chính hàm đó (_id, title, pathString…) và phản hồi thực tế của endpoint nằm trong result. Các ví dụ phản hồi trong tài liệu này hiển thị nội dung của result:
{
"_id": "function_id",
"title": "Show",
"pathString": "/bulk-message-api-app/api/v2/bulk-operation/show.js",
"result": {
"bulkOperation": { "_id": "abc123xyz789", "status": "running" }
}
}
Chuyển đổi từ v1
v2 chạy song song với v1, vì vậy bạn có thể chuyển đổi theo lịch trình của riêng mình. Các endpoint v1 (/api/bulk-message/…, /api/bulk-message-records/…) sẽ bị ngừng hỗ trợ; các tích hợp mới nên dùng v2.
- Chuyển đường dẫn endpoint sang v2:
…/api/bulk-message/…thành…/api/v2/bulk-operation/…, và…/api/bulk-message-records/…thành…/api/v2/bulk-operation-items/…. Nội dung yêu cầusendkhông thay đổi; giờ đây một yêu cầu nhận tối đa 100.000 người nhận thay vì 5.000. - Gửi
bulkOperationIdthay chobulkMessageIdtrong các yêu cầu. - Thay
stats.jsbằngshow.js. - Đọc phản hồi theo tên trường mới trong bảng bên dưới.
Các endpoint v2 chỉ nhận biết các thao tác hàng loạt được tạo bằng send của v2. Để theo dõi một tin nhắn hàng loạt đã tạo bằng v1 trước khi bạn chuyển đổi, hãy tiếp tục dùng các endpoint v1 cho nó.
Endpoint
| v1 | v2 | Những gì thay đổi trong phản hồi |
|---|---|---|
bulk-message/send.js | v2/bulk-operation/send.js | { bulkMessageId } thành { bulkOperationId } |
bulk-message/stats.js | v2/bulk-operation/show.js | { bulkMessage, stats } thành { bulkOperation } |
bulk-message/message-stats.js | v2/bulk-operation/message-stats.js | Các bộ đếm nằm ở cấp gốc thay vì trong messageStats |
bulk-message/stop.js | v2/bulk-operation/stop.js | Không có gì |
bulk-message-records/list.js | v2/bulk-operation-items/list.js | bulkMessageRecords thành bulkOperationItems |
bulk-message-records/list-with-messages.js | v2/bulk-operation-items/list-with-messages.js | Giống list, và mỗi mục còn kèm theo session |
Tên trường
| 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 (tin nhắn hàng loạt) | bulkOperation (thao tác hàng loạt) |
bulkMessageRecord (bản ghi) | bulkOperationItem (mục) |
bulkMessageId trong yêu cầu, trong phản hồi send và trên bản ghi | bulkOperationId |
username / userId / sessionId của bản ghi như khi gửi | payload.username / payload.userId / payload.sessionId |
referenceId của bản ghi | payload.referenceId |
payload của bản ghi (payload mẫu tin của người nhận) | payload.payload |
userId, sessionId, messageId của bản ghi sau khi gửi | result.userId, result.sessionId, result.messageId |
trạng thái bản ghi success | succeeded |
errorMessage trên bản ghi thất bại | error.message, cùng với error.code và error.retryable |
| — | position (chỉ số của người nhận trong recipients) |
bộ lọc {"status": "success"} | {"status": "succeeded"} |
bộ lọc {"referenceId": "…"} | {"payload.referenceId": "…"} |
lỗi send schema-error, invalidRequest | zod-schema-error, kèm đường dẫn của trường không hợp lệ trong thông báo |
Tính năng chính
- Gửi tin nhắn mẫu hàng loạt đến 1–100.000 người nhận trong một yêu cầu
- Biến được cá nhân hóa cho từng người nhận (HEADER, BODY, BUTTONS, CAROUSEL)
defaultPayloaddùng chung cho mọi người nhận, vớipayloadriêng của từng người nhận được gộp vào (isMerge)- Gửi theo lịch (
scheduleAt) - Chỉ định người nhận bằng
username(số điện thoại),userIdhoặcsessionId - Gửi nhiều tin nhắn cho cùng một người dùng trong một yêu cầu hàng loạt
referenceIdtùy chọn để theo dõi bản ghi với các hệ thống bên ngoài- Tự động giao cuộc trò chuyện cho một người dùng hoặc nhóm làm việc sau khi gửi (
action)
API này chỉ có thể gửi các mẫu tin đã được Meta duyệt.
Tên mẫu tin và mã ngôn ngữ phải khớp chính xác với mẫu tin được đăng ký trong Meta Business Manager.
Tham số yêu cầu
Tham số cấp cao nhất
| Tham số | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
channelUsername | string | Có | Số kênh WhatsApp dùng để gửi tin nhắn (ví dụ "908506669933") |
connectorBrand | string | Có | Thương hiệu trình kết nối kênh. Giá trị hiện được hỗ trợ: "whatsapp" |
title | string | Không | Tiêu đề chiến dịch. Dùng để hiển thị trên bảng điều khiển. Mặc định: "-" |
scheduleAt | string (ISO 8601) | Không | Ngày giờ gửi theo lịch (ví dụ "2026-06-10T10:00:00.000Z"). Nếu bỏ qua, tin nhắn được gửi ngay lập tức. |
defaultPayload | object | Có điều kiện* | Payload mẫu tin mặc định áp dụng cho mọi người nhận. Bắt buộc nếu một người nhận không cung cấp payload riêng. |
recipients | array | Có | Danh sách người nhận. Tối thiểu 1, tối đa 100.000 người nhận. |
action | object | Không | Hành động áp dụng cho cuộc trò chuyện sau khi gửi. assign-to-user hoặc assign-to-workgroup. |
*Nếu mọi người nhận đều cung cấp payload riêng, defaultPayload là tùy chọn.
Cấu trúc người nhận
Với mỗi người nhận, phải cung cấp đúng một trong username, userId hoặc sessionId. Không thể dùng nhiều định danh cùng lúc, và bỏ qua tất cả sẽ gây ra lỗi.
Để gửi nhiều tin nhắn cho cùng một người dùng trong một yêu cầu hàng loạt, hãy thêm cùng một định danh vào danh sách người nhận nhiều lần.
| Trường | Kiểu | Mô tả |
|---|---|---|
username | string | Số điện thoại của người nhận (ví dụ "905554443322"). Nếu người dùng chưa có trong hệ thống, người dùng sẽ được tạo tự động. |
userId | string | ID của một người dùng hiện có trong hệ thống. |
sessionId | string | ID của một phiên trò chuyện hiện có trong hệ thống. |
referenceId | string | ID tham chiếu tùy chọn (tối đa 256 ký tự) để đối chiếu với bản ghi của hệ thống bên ngoài (CRM, đơn hàng, ticket, v.v.). Nếu được cung cấp, phải là duy nhất trong đợt gửi hàng loạt. |
payload | object | Payload mẫu tin riêng cho người nhận (tùy chọn). Nếu isMerge: true, payload này được gộp với defaultPayload. |
isMerge | boolean | Ghi đè cách gộp cho người nhận này (tùy chọn). Nếu bỏ qua, defaultPayload.isMerge được dùng. |
Cấu trúc hành động
| Trường | Kiểu | Mô tả |
|---|---|---|
action.key | string | "assign-to-user" giao cuộc trò chuyện cho một nhân viên cụ thể; "assign-to-workgroup" giao cho một nhóm làm việc. |
action.value | string | ID của người dùng hoặc nhóm làm việc đích. |
Cấu trúc payload mẫu tin
defaultPayload và payload riêng của người nhận có cùng cấu trúc. Với tin nhắn mẫu, phải chỉ định type: "template".
{
"type": "template",
"template": {
"templateName": "order_confirmation",
"languageCode": "tr-TR",
"variables": []
},
"isMerge": true
}
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
type | string | Có | Loại payload. Với tin nhắn mẫu: "template" |
template.templateName | string | Có* | Tên mẫu tin đã đăng ký trên Meta. Không bắt buộc trong payload của người nhận khi dùng isMerge: true (kế thừa từ mặc định). |
template.languageCode | string | Không | Mã ngôn ngữ của mẫu tin (ví dụ "tr", "en", "tr-TR", "en-US"). Phải khớp chính xác với ngôn ngữ đã đăng ký trên Meta. |
template.variables | array | Không | Danh sách biến áp dụng cho các thành phần của mẫu tin. Xem chi tiết bên dưới. |
isMerge | boolean | Không | true: payload của người nhận được gộp sâu với defaultPayload. false hoặc bỏ qua: payload của người nhận thay thế hoàn toàn defaultPayload. |
- Nếu
defaultPayload.isMerge: truevà người nhận cung cấppayloadriêng, việc gộp sâu sẽ được áp dụng. - Khi gộp sâu, người nhận có thể chỉ cung cấp
variables;templateNamevàlanguageCodeđược kế thừa từ payload mặc định. - Trường
isMergecủa người nhận ghi đèdefaultPayload.isMerge. - Nếu người nhận không cung cấp
payload,defaultPayloadluôn được dùng.
Cấu trúc biến
Mỗi phần tử trong mảng variables tương ứng với một thành phần của mẫu tin. Mỗi loại thành phần (type) chỉ được xuất hiện một lần trong mảng.
| type | Mô tả | parameters | cards |
|---|---|---|---|
"HEADER" | Thành phần tiêu đề của mẫu tin. Biến văn bản hoặc URL đa phương tiện (hình ảnh, video, tài liệu) | Có | — |
"BODY" | Các biến văn bản trong phần nội dung của mẫu tin | Có | — |
"BUTTONS" | Các biến hậu tố URL động cho nút | Có | — |
"CAROUSEL" | Các thành phần thẻ cho mẫu tin dạng carousel | — | Có |
Định dạng tham số
Trường parameters có thể được cung cấp theo ba định dạng khác nhau:
// 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" }
- Nếu mẫu tin trên Meta của bạn dùng các placeholder như
{{1}},{{2}}, hãy dùng định dạng mảng hoặc định dạng object với khóa dạng số. - Nếu mẫu tin của bạn dùng các placeholder có tên như
{{firstName}}hoặc{{orderTotal}}, hãy dùng định dạng object với khóa có tên. - Khi dùng mảng, thứ tự rất quan trọng: phần tử đầu tiên tương ứng với
{{1}}, phần tử thứ hai với{{2}}, và cứ thế tiếp tục.
Thành phần HEADER
Dùng thành phần HEADER khi tiêu đề của mẫu tin chứa đa phương tiện (hình ảnh, video, tài liệu) hoặc văn bản động.
// Media header (image URL)
{
"type": "HEADER",
"parameters": ["https://example.com/product-image.jpg"]
}
// Text header variable
{
"type": "HEADER",
"parameters": ["Special Campaign"]
}
Thành phần BODY
Dùng cho các biến văn bản động trong phần nội dung của mẫu tin.
// 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"
}
}
Thành phần BUTTONS
Dùng cho các nút có hậu tố URL động. Nếu mẫu tin có nhiều nút URL, chỉ những nút có biến mới được đánh chỉ số tuần tự (các nút không có biến hoặc nút FLOW bị bỏ qua).
// 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"]
}
Thành phần CAROUSEL
Với mẫu tin dạng carousel, biến của các thành phần được định nghĩa riêng cho từng thẻ.
{
"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"]
}
]
}
]
}
Độ dài của mảng cards phải khớp chính xác với số thẻ được định nghĩa trong mẫu tin.
Ví dụ
1. Mẫu tin đơn giản — Không có biến, cùng nội dung cho mọi người nhận
Đây là cách đơn giản nhất để gửi một mẫu tin tĩnh không có biến đến nhiều người nhận.
{
"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" }
]
}'
- Người nhận được chỉ định qua
usernamesẽ được tạo tự động nếu chưa có trong hệ thống - Mọi người nhận dùng cùng một
defaultPayload; không cần dữ liệu riêng cho từng người nhận - Khi không chỉ định
isMerge, mỗi người nhận dùng trực tiếpdefaultPayload
2. Mẫu tin có biến nội dung dùng chung
Cùng một mẫu tin được gửi đến mọi người nhận với các giá trị biến giống nhau. Mẫu tin chứa các placeholder như {{1}} và {{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" }]
}
- Trong ví dụ này, nội dung mẫu tin có thể là: "Nhận ưu đãi giảm
{{1}}trong chiến dịch của chúng tôi! Ưu đãi có hiệu lực đến{{2}}." parameters[0]thay cho{{1}}, cònparameters[1]thay cho{{2}}
3. Mẫu tin được cá nhân hóa — Biến riêng cho từng người nhận với isMerge
Mỗi người nhận dùng các giá trị biến khác nhau. Khi đặt isMerge: true trong defaultPayload, người nhận chỉ cần cung cấp variables; templateName và languageCode được kế thừa từ payload mặc định.
Trong ví dụ này, mẫu tin có cả tiêu đề đa phương tiện lẫn các biến nội dung được cá nhân hóa.
{
"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"]
}
]
}
}
}
]
}
- Nhờ
isMerge: true, không cần lặp lạitemplateNametrong payload của từng người nhận - Mảng
variablescủa mỗi người nhận hoàn toàn độc lập - URL đa phương tiện của tiêu đề phải truy cập công khai được
- Nếu bỏ qua
typetrong payload của người nhận,defaultPayload.typesẽ được kế thừa
4. Biến của nút URL
Dùng thành phần BUTTONS khi mẫu tin có một nút với hậu tố URL động. Ví dụ: một mã vận đơn được nối vào URL gốc 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"]
}
]
}
}
}
]
}
- Tham số của
BUTTONSđược khớp theo thứ tự của các nút có chứa biến - Nút FLOW và nút không có biến bị bỏ qua; việc đánh chỉ số chỉ áp dụng cho các nút URL động
- Nếu URL của nút trong mẫu tin là
https://example.com/track/{{1}}, thìparameters[0]thay cho{{1}}
5. Gửi theo lịch
Lên lịch gửi tin nhắn vào một ngày giờ trong tương lai. scheduleAt phải được cung cấp dưới dạng dấu thời gian UTC theo 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" }
}
]
}
}
}
]
}
scheduleAtphải được cung cấp theo múi giờ UTC (ví dụ: với 10:00 sáng giờ Thổ Nhĩ Kỳ, hãy dùng07:00:00.000Z)- Ví dụ này dùng định dạng tham số có tên; mẫu tin cần chứa các placeholder như
{{name}}và{{discountRate}} - Với
action, các cuộc trò chuyện được tạo ra khi gửi tin sẽ tự động được giao cho nhóm làm việc đã chỉ định
Phản hồi
Một yêu cầu thành công trả về bulkOperationId, có thể dùng để theo dõi quá trình gửi:
{
"bulkOperationId": "abc123xyz789"
}
Phản hồi lỗi
| Trạng thái | Mô tả |
|---|---|
recipients field is required | Trường recipients không được gửi |
Channel not found | Không tìm thấy kênh đã xác minh nào khớp với channelUsername và connectorBrand |
Channel is not verified | Kênh khớp tồn tại nhưng chưa được xác minh |
zod-schema-error | Một trường trong nội dung yêu cầu không qua được kiểm tra lược đồ (thiếu trường bắt buộc, sai kiểu, giá trị không được hỗ trợ, nhiều hơn một định danh trên một người nhận, hoặc thiếu payload). Thông báo nêu tên trường, ví dụ recipients.0.referenceId: referenceId must be unique |
bulkOperationId được trả về có thể dùng với các endpoint bên dưới để truy vấn thống kê gửi tin và dừng quá trình gửi.
Show — Trạng thái và thống kê của thao tác hàng loạt
Lấy thao tác hàng loạt cùng trạng thái hiện tại và các bộ đếm gửi tin của các mục, trong khóa bulkOperation.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/show.js
Tham số yêu cầu
| Tham số | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
bulkOperationId | string | Có | ID của thao tác hàng loạt cần theo dõi (được trả về từ 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"
}'
Phản hồi
{
"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"
}
}
Các trường Show
Các trường nằm trong bulkOperation.
| Trường | Kiểu | Mô tả |
|---|---|---|
status | string | Trạng thái của thao tác hàng loạt: preparing, scheduled, pending, running, stopping, stopped, completed, failed |
progress.total | number | Tổng số mục |
progress.pending | number | Số mục vẫn đang chờ trong hàng đợi |
progress.succeeded | number | Số mục đã được xử lý để gửi thành công |
progress.failed | number | Số mục gặp lỗi khi gửi |
progress.cancelled | number | Số mục bị hủy bởi stop |
progress.unknown | number | Số mục không xác định được kết quả |
result.outcome | string | Kết quả cuối cùng khi thao tác hàng loạt đã kết thúc: success, partial, all-failed, cancelled, unknown |
result.hasErrors | boolean | true nếu có ít nhất một mục thất bại |
scheduleAt | string | Thời điểm gửi theo lịch (chỉ với thao tác hàng loạt được lên lịch) |
startedAt, completedAt | string | Thời điểm bắt đầu và kết thúc gửi |
progress.succeeded cho biết tin nhắn đã được hệ thống chuyển giao thành công. Điều này không bảo đảm rằng Meta đã gửi tin nhắn đến người nhận. Các cập nhật trạng thái tiếp theo do Meta tạo ra (như delivered, read hoặc failed) không ảnh hưởng đến bộ đếm này và không được phản ánh ở đây.
- Endpoint show: Hiển thị trạng thái gửi của các mục (
pending,succeeded,failed,cancelled,unknown) - Endpoint message-stats: Hiển thị trạng thái thực tế của tin nhắn (
pending,sending,sent,delivered,read,error, v.v.) - Một mục có thể ở trạng thái
succeeded, nhưng tin nhắn có thể chưa được gửi đến/đọc
Reference ID
referenceId là trường tùy chọn mà bạn có thể dùng để đối chiếu các mục gửi tin với một ID từ hệ thống của chính bạn nhằm mục đích theo dõi (ví dụ: số đơn hàng, ID ticket). Trường này được trả về trên mỗi mục dưới dạng payload.referenceId.
Nếu được cung cấp, phải là duy nhất trong đợt gửi hàng loạt (tối đa 256 ký tự).
- Không bắt buộc phải dùng
- Không thể trùng lặp trong cùng một thao tác hàng loạt
- Có thể dùng lại ở các thao tác hàng loạt khác nhau
Message Stats — Trạng thái tin nhắn WhatsApp
Lấy thống kê trạng thái tin nhắn của một thao tác hàng loạt. Khác với endpoint show, endpoint này hiển thị message.status thực tế của các tin nhắn đã gửi thay vì trạng thái của mục.
Các trạng thái tin nhắn có thể có: 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
Tham số yêu cầu
| Tham số | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
bulkOperationId | string | Có | ID của thao tác hàng loạt cần truy vấn |
{
"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"
}'
Phản hồi
{
"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
}
Các trường Message Stats
| Trường | Kiểu | Mô tả |
|---|---|---|
pending | number | Tin nhắn chưa được gửi |
sending | number | Tin nhắn đang được gửi |
sent | number | Tin nhắn đã chuyển cho WhatsApp, chưa được gửi đến |
delivered | number | Tin nhắn đã được gửi đến điện thoại của người nhận |
read | number | Tin nhắn đã được người nhận đọc |
deleted | number | Tin nhắn đã bị xóa |
warning | number | Tin nhắn có cảnh báo |
error | number | Tin nhắn bị lỗi |
unknown | number | Tin nhắn có trạng thái không xác định |
not-sended | number | Tin nhắn không thể gửi |
no-message | number | Mục không có tin nhắn (vẫn trong hàng đợi, thất bại hoặc đã hủy) |
total | number | Tổng số mục |
- Số
no-messagecao khi thao tác hàng loạt đang ở trạng tháirunningcho thấy việc gửi vẫn đang diễn ra - Số
deliveredcho biết số tin nhắn đã được gửi đến thành công - Số
readcó thể dùng để đo mức độ tương tác của chiến dịch - Bạn có thể gọi endpoint này định kỳ để theo dõi theo thời gian thực
Cấu trúc Options — Phân trang, lọc và sắp xếp
Tham số options dùng trong các endpoint list và list-with-messages cung cấp một cấu trúc chuẩn cho việc phân trang, lọc và sắp xếp.
Các trường Options
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
pagination | object | Không | Cài đặt phân trang |
filtering | object | Không | Tiêu chí lọc |
sorting | object | Không | Cài đặt sắp xếp (ví dụ {"position": 1}) |
Cấu trúc phân trang
Nếu không gửi pagination, trang đầu tiên được trả về với tối đa 50 mục. Nếu có gửi, currentPage là bắt buộc.
| Trường | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
currentPage | number | — | Số trang cần lấy (bắt buộc khi gửi pagination) |
pageItems | number | 50 | Số mục mỗi trang (tối đa: 50) |
Cấu trúc lọc
Việc lọc dùng định dạng truy vấn MongoDB trên các trường của mục, với tên trường đúng như trong phản hồi (ví dụ status, payload.referenceId, result.messageId). Trong endpoint list-with-messages, bạn cũng có thể lọc theo các trường của tin nhắn (ví dụ 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
}
}
}
}
Cấu trúc sắp xếp
Việc sắp xếp dùng định dạng sắp xếp của MongoDB. 1 nghĩa là tăng dần, -1 nghĩa là giảm dần. position là thứ tự của người nhận trong mảng recipients của yêu cầu (bắt đầu từ 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
}
}
}
Ví dụ sử dụng kết hợp
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 2,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
},
"sorting": {
"position": 1
}
}
}
Ví dụ này liệt kê trang thứ hai của các tin nhắn đã được gửi đến, theo thứ tự người nhận.
- Kết hợp
filteringvàpaginationđể truy vấn có mục tiêu - Phản hồi có
options.pagination.totalCountvàoptions.pagination.totalPagesđể điều hướng - Bộ lọc
message.statuschỉ hoạt động trong endpointlist-with-messages
Items — Chi tiết và danh sách mục
Liệt kê tất cả các mục gửi tin của một thao tác hàng loạt. Mỗi mục tương ứng với một phần tử của mảng recipients.
List — Danh sách mục
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation-items/list.js
Tham số yêu cầu
| Tham số | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
bulkOperationId | string | Có | ID của thao tác hàng loạt cần liệt kê |
options | object | Không | Tùy chọn phân trang, lọc, sắp xếp. Xem chi tiết tại Cấu trúc Options. |
Yêu cầu — Cách dùng cơ bản
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
Yêu cầu — Lọc theo một trạng thái cụ thể
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"status": "failed"
}
}
}
Chỉ liệt kê các mục gửi tin thất bại, kèm lý do trong error.
Phản hồi
{
"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 — Danh sách kèm chi tiết tin nhắn
Có cùng các tính năng như endpoint list (phân trang, lọc, sắp xếp). Điểm khác biệt: mỗi mục còn kèm theo các object message và session liên quan khi chúng tồn tại. Nhờ đó bạn có thể xem trạng thái tin nhắn (delivered, read, error, v.v.) và payload trong một truy vấn duy nhất.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation-items/list-with-messages.js
Yêu cầu — Cách dùng cơ bản
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
Yêu cầu — Lọc theo trạng thái tin nhắn
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
}
}
}
Ví dụ này chỉ lấy các tin nhắn có trạng thái "delivered".
Yêu cầu — Liệt kê tin nhắn thất bại
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "error"
}
}
}
Dùng để xem lại các tin nhắn gặp lỗi khi gửi.
Phản hồi
{
"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": {}
}
}
Các trường của mục
| Trường | Kiểu | Mô tả |
|---|---|---|
_id | string | ID của mục |
bulkOperationId | string | ID của thao tác hàng loạt chứa mục này |
position | number | Thứ tự của người nhận trong mảng recipients của yêu cầu, bắt đầu từ 0 |
payload | object | Người nhận đúng như khi được gửi trong yêu cầu (username / userId / sessionId, referenceId, payload, isMerge) |
status | string | Trạng thái của mục: pending, succeeded, failed, cancelled, unknown |
error | object | Chỉ có trên các mục failed: code, message và retryable |
result.userId | string | ID người dùng của người nhận |
result.sessionId | string | ID phiên trò chuyện |
result.messageId | string | ID tin nhắn đã gửi (không có nếu chưa có tin nhắn nào được gửi) |
completedAt | string | Thời điểm mục được xử lý |
message | object | Chi tiết tin nhắn (chỉ có trong list-with-messages) |
session | object | Chi tiết cuộc trò chuyện (chỉ có trong list-with-messages) |
So sánh List và List-With-Messages
| Tính năng | list | list-with-messages |
|---|---|---|
| Phân trang | Có | Có |
| Lọc | Có (chỉ các trường của mục) | Có (trường của mục + tin nhắn) |
| Message / Session | Không | Có (nếu tồn tại) |
| Hiệu năng | Nhanh | Trung bình (thực hiện JOIN) |
| Bộ lọc message.status | Không có | Có |
- list: Liệt kê nhanh tất cả các mục, lọc theo referenceId, kiểm tra trạng thái của mục
- list-with-messages: Xem trạng thái tin nhắn WhatsApp (delivered, read), kiểm tra payload của tin nhắn
- Ví dụ về lọc:
{"status": "failed"}— Các mục gửi tin thất bại{"payload.referenceId": "ORDER-123"}— Một reference ID cụ thể{"message.status": "delivered"}— Tin nhắn đã được gửi đến (chỉ list-with-messages){"message.status": "read"}— Tin nhắn đã đọc (chỉ list-with-messages){"message.status": "error"}— Tin nhắn bị lỗi (chỉ list-with-messages){"message.status": {"$in": ["delivered", "read"]}}— Tin nhắn đã được gửi đến hoặc đã đọc (chỉ list-with-messages){"message.status": {"$nin": ["error", "not-sended"]}}— Tin nhắn không bị lỗi và không thuộc loại không gửi được (chỉ list-with-messages){"message": {"$exists": false}}— Các mục không có tin nhắn (chỉ list-with-messages){"status": {"$in": ["succeeded", "pending"]}}— Các mục thành công hoặc đang chờ
- Endpoint
listnhanh hơn; hãy ưu tiên dùng cho việc kiểm tra trạng thái chung - Dùng
list-with-messageskhi cần chi tiết tin nhắn - Số mục tối đa mỗi trang (pageItems) là 50; mặc định là 50 nếu không chỉ định
- Bộ lọc
message.statuschỉ hoạt động tronglist-with-messages - Các mục không có
result.messageIdsẽ không có objectmessage
Stop — Hủy gửi tin
Dừng một thao tác hàng loạt đang gửi. Tất cả các mục pending được chuyển sang trạng thái cancelled và thao tác hàng loạt chuyển sang stopped. Các mục đã được xử lý là succeeded hoặc failed không bị ảnh hưởng. Một thao tác hàng loạt đã lên lịch cũng có thể được dừng trước thời điểm scheduleAt của nó.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/stop.js
Không thể hoàn tác thao tác này. Một đợt gửi đã dừng không thể tiếp tục lại.
Tham số yêu cầu
| Tham số | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
bulkOperationId | string | Có | ID của thao tác hàng loạt cần dừng |
{
"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"
}'
Phản hồi
Với một yêu cầu thành công, nội dung phản hồi để trống. Trạng thái HTTP 200 cho biết thao tác đã hoàn tất thành công.
{}
- Chỉ có thể dừng các thao tác hàng loạt được tạo qua API này
- Sau khi dừng một đợt gửi, bạn có thể dùng endpoint
showđể kiểm tra số mục đã hủy (bulkOperation.progress.cancelled) - Nếu không tìm thấy thao tác hàng loạt, API trả về lỗi:
Bulk operation not found.