Chuyển tới nội dung chính

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
Định dạng phản hồi

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.

  1. 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ầu send khô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.
  2. Gửi bulkOperationId thay cho bulkMessageId trong các yêu cầu.
  3. Thay stats.js bằng show.js.
  4. Đọ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​

v1v2Những gì thay đổi trong phản hồi
bulk-message/send.jsv2/bulk-operation/send.js{ bulkMessageId } thành { bulkOperationId }
bulk-message/stats.jsv2/bulk-operation/show.js{ bulkMessage, stats } thành { bulkOperation }
bulk-message/message-stats.jsv2/bulk-operation/message-stats.jsCác bộ đếm nằm ở cấp gốc thay vì trong messageStats
bulk-message/stop.jsv2/bulk-operation/stop.jsKhông có gì
bulk-message-records/list.jsv2/bulk-operation-items/list.jsbulkMessageRecords thành bulkOperationItems
bulk-message-records/list-with-messages.jsv2/bulk-operation-items/list-with-messages.jsGiống list, và mỗi mục còn kèm theo session

Tên trường​

v1v2
stats.successbulkOperation.progress.succeeded
stats.pending, stats.failed, stats.cancelled, stats.totalbulkOperation.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 ghibulkOperationId
username / userId / sessionId của bản ghi như khi gửipayload.username / payload.userId / payload.sessionId
referenceId của bản ghipayload.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ửiresult.userId, result.sessionId, result.messageId
trạng thái bản ghi successsucceeded
errorMessage trên bản ghi thất bạierror.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, invalidRequestzod-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)
  • defaultPayload dùng chung cho mọi người nhận, với payload riê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), userId hoặc sessionId
  • 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
  • referenceId tù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)
cảnh báo

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ểuBắt buộcMô tả
channelUsernamestringCóSố kênh WhatsApp dùng để gửi tin nhắn (ví dụ "908506669933")
connectorBrandstringCóThương hiệu trình kết nối kênh. Giá trị hiện được hỗ trợ: "whatsapp"
titlestringKhôngTiêu đề chiến dịch. Dùng để hiển thị trên bảng điều khiển. Mặc định: "-"
scheduleAtstring (ISO 8601)KhôngNgà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.
defaultPayloadobjectCó đ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.
recipientsarrayCóDanh sách người nhận. Tối thiểu 1, tối đa 100.000 người nhận.
actionobjectKhôngHà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ườngKiểuMô tả
usernamestringSố đ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.
userIdstringID của một người dùng hiện có trong hệ thống.
sessionIdstringID của một phiên trò chuyện hiện có trong hệ thống.
referenceIdstringID 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.
payloadobjectPayload 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.
isMergebooleanGhi đè 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ườngKiểuMô tả
action.keystring"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.valuestringID 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ườngKiểuBắt buộcMô tả
typestringCóLoại payload. Với tin nhắn mẫu: "template"
template.templateNamestringCó*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.languageCodestringKhôngMã 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.variablesarrayKhôngDanh 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.
isMergebooleanKhôngtrue: 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.
Hành vi của isMerge
  • Nếu defaultPayload.isMerge: true và người nhận cung cấp payload riê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; templateName và languageCode được kế thừa từ payload mặc định.
  • Trường isMerge của người nhận ghi đè defaultPayload.isMerge.
  • Nếu người nhận không cung cấp payload, defaultPayload luô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.

typeMô tảparameterscards
"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 tinCó—
"BUTTONS"Các biến hậu tố URL động cho nútCó—
"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" }
Tôi nên dùng định dạng nào?
  • 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"]
}

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"]
}
]
}
]
}
cảnh báo

Độ 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" }
]
}'
mẹo
  • Người nhận được chỉ định qua username sẽ đượ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ếp defaultPayload

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" }]
}
mẹo
  • 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òn parameters[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"]
}
]
}
}
}
]
}
mẹo
  • Nhờ isMerge: true, không cần lặp lại templateName trong payload của từng người nhận
  • Mảng variables củ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 type trong payload của người nhận, defaultPayload.type sẽ đượ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"]
}
]
}
}
}
]
}
mẹo
  • 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" }
}
]
}
}
}
]
}
mẹo
  • scheduleAt phả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ùng 07: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áiMô tả
recipients field is requiredTrường recipients không được gửi
Channel not foundKhông tìm thấy kênh đã xác minh nào khớp với channelUsername và connectorBrand
Channel is not verifiedKênh khớp tồn tại nhưng chưa được xác minh
zod-schema-errorMộ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ểuBắt buộcMô tả
bulkOperationIdstringCó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ườngKiểuMô tả
statusstringTrạng thái của thao tác hàng loạt: preparing, scheduled, pending, running, stopping, stopped, completed, failed
progress.totalnumberTổng số mục
progress.pendingnumberSố mục vẫn đang chờ trong hàng đợi
progress.succeedednumberSố mục đã được xử lý để gửi thành công
progress.failednumberSố mục gặp lỗi khi gửi
progress.cancellednumberSố mục bị hủy bởi stop
progress.unknownnumberSố mục không xác định được kết quả
result.outcomestringKế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.hasErrorsbooleantrue nếu có ít nhất một mục thất bại
scheduleAtstringThời điểm gửi theo lịch (chỉ với thao tác hàng loạt được lên lịch)
startedAt, completedAtstringThời điểm bắt đầu và kết thúc gửi
ghi chú

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.

Show so với Message Stats
  • 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ự).

Quan trọng
  • 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ểuBắt buộcMô tả
bulkOperationIdstringCó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ườngKiểuMô tả
pendingnumberTin nhắn chưa được gửi
sendingnumberTin nhắn đang được gửi
sentnumberTin nhắn đã chuyển cho WhatsApp, chưa được gửi đến
deliverednumberTin nhắn đã được gửi đến điện thoại của người nhận
readnumberTin nhắn đã được người nhận đọc
deletednumberTin nhắn đã bị xóa
warningnumberTin nhắn có cảnh báo
errornumberTin nhắn bị lỗi
unknownnumberTin nhắn có trạng thái không xác định
not-sendednumberTin nhắn không thể gửi
no-messagenumberMục không có tin nhắn (vẫn trong hàng đợi, thất bại hoặc đã hủy)
totalnumberTổng số mục
Mẹo sử dụng
  • Số no-message cao khi thao tác hàng loạt đang ở trạng thái running cho thấy việc gửi vẫn đang diễn ra
  • Số delivered cho biết số tin nhắn đã được gửi đến thành công
  • Số read có 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ườngKiểuBắt buộcMô tả
paginationobjectKhôngCài đặt phân trang
filteringobjectKhôngTiêu chí lọc
sortingobjectKhôngCà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ườngKiểuMặc địnhMô tả
currentPagenumber—Số trang cần lấy (bắt buộc khi gửi pagination)
pageItemsnumber50Số 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.

Mẹo thực tế
  • Kết hợp filtering và pagination để truy vấn có mục tiêu
  • Phản hồi có options.pagination.totalCount và options.pagination.totalPages để điều hướng
  • Bộ lọc message.status chỉ hoạt động trong endpoint list-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ểuBắt buộcMô tả
bulkOperationIdstringCóID của thao tác hàng loạt cần liệt kê
optionsobjectKhôngTù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ườngKiểuMô tả
_idstringID của mục
bulkOperationIdstringID của thao tác hàng loạt chứa mục này
positionnumberThứ tự của người nhận trong mảng recipients của yêu cầu, bắt đầu từ 0
payloadobjectNgười nhận đúng như khi được gửi trong yêu cầu (username / userId / sessionId, referenceId, payload, isMerge)
statusstringTrạng thái của mục: pending, succeeded, failed, cancelled, unknown
errorobjectChỉ có trên các mục failed: code, message và retryable
result.userIdstringID người dùng của người nhận
result.sessionIdstringID phiên trò chuyện
result.messageIdstringID tin nhắn đã gửi (không có nếu chưa có tin nhắn nào được gửi)
completedAtstringThời điểm mục được xử lý
messageobjectChi tiết tin nhắn (chỉ có trong list-with-messages)
sessionobjectChi tiết cuộc trò chuyện (chỉ có trong list-with-messages)

So sánh List và List-With-Messages​

Tính nănglistlist-with-messages
Phân trangCóCó
LọcCó (chỉ các trường của mục)Có (trường của mục + tin nhắn)
Message / SessionKhôngCó (nếu tồn tại)
Hiệu năngNhanhTrung bình (thực hiện JOIN)
Bộ lọc message.statusKhông cóCó
Kịch bản sử dụng
  • 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ờ
Lưu ý về hiệu năng và cách dùng
  • Endpoint list nhanh hơn; hãy ưu tiên dùng cho việc kiểm tra trạng thái chung
  • Dùng list-with-messages khi 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.status chỉ hoạt động trong list-with-messages
  • Các mục không có result.messageId sẽ không có object message

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
cảnh báo

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ểuBắt buộcMô tả
bulkOperationIdstringCó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.

{}
mẹo
  • 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.