Bulk Template Message API 문서
이 API를 사용하면 WhatsApp 채널을 통해 여러 수신자에게 템플릿 메시지를 동시에 보낼 수 있습니다.
메시지 발송은 비동기로 처리됩니다. API 요청은 즉시 bulkMessageId를 반환하고, 메시지는 대기열에 들어가 백그라운드에서 처리됩니다.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/send.js
주요 기능
- 한 번의 요청으로 1~5,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명, 최대 5,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 | 외부 시스템 레코드(CRM, 주문, 티켓 등)와 대조하기 위한 선택 참조 ID(최대 256자). 입력하는 경우 대량 요청 안에서 고유해야 합니다. |
payload | object | 수신자별 템플릿 페이로드(선택). isMerge: true이면 defaultPayload와 병합됩니다. |
isMerge | boolean | 이 수신자에 대한 병합 동작을 재정의합니다(선택). 생략하면 defaultPayload.isMerge가 사용됩니다. |
Action 구조
| 필드 | 유형 | 설명 |
|---|---|---|
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와 깊은 병합(deep merge)됩니다. 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/bulk-message/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시는07:00:00.000Z)- 이 예시는 이름 있는 파라미터 형식을 사용하므로, 템플릿에
{{name}},{{discountRate}}같은 자리 표시자가 있어야 합니다 action을 지정하면 메시지 발송으로 생성된 대화가 지정한 워크그룹에 자동 배정됩니다
응답
요청이 성공하면 발송 진행 상황을 추적하는 데 사용할 수 있는 bulkMessageId가 반환됩니다.
{
"bulkMessageId": "abc123xyz789"
}
오류 응답
| 상태 | 설명 |
|---|---|
Channel not found | channelUsername, connectorBrand와 일치하는 인증된 채널을 찾을 수 없습니다 |
Channel is not verified | 일치하는 채널은 있지만 아직 인증되지 않았습니다 |
invalidRequest | 수신자에 여러 식별자를 지정했거나 필수 페이로드가 누락되었습니다 |
channelNotFound | 입력한 channelId와 일치하는 활성 채널을 찾을 수 없습니다 |
schema-error | 요청 본문의 필드가 스키마 검증에 실패했습니다(필수 필드 누락, 잘못된 유형 또는 지원하지 않는 값) |
반환된 bulkMessageId는 아래 엔드포인트에서 발송 통계를 조회하거나 발송을 중단하는 데 사용할 수 있습니다.
Stats — 발송 통계
대량 메시지의 현재 발송 상태를 조회합니다. 대기 중, 성공, 실패, 취소된 레코드 수를 반환합니다.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/stats.js
요청 파라미터
| 파라미터 | 유형 | 필수 | 설명 |
|---|---|---|---|
bulkMessageId | string | 예 | 추적할 대량 메시지의 ID(createBulkPerRecipient에서 반환됨) |
{
"bulkMessageId": "abc123xyz789"
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/stats.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"bulkMessageId": "abc123xyz789"
}'
응답
{
"bulkMessage": {
"_id": "abc123xyz789",
"slug": "my-workspace",
"title": "Campaign Title",
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"connectorSlug": "whatsapp-cloud",
"payload": {
"recipientCount": 100,
"defaultPayloadType": "template",
"jobId": "job_abc123"
},
"schedule": {
"date": "2026-06-10T07:00:00.000Z",
"type": "later"
},
"createdAt": "2026-06-08T10:00:00.000Z",
"updatedAt": "2026-06-08T10:30:00.000Z"
},
"stats": {
"pending": 45,
"success": 42,
"failed": 3,
"cancelled": 10,
"total": 100
}
}
Stats 필드
| 필드 | 유형 | 설명 |
|---|---|---|
stats.pending | number | 아직 대기열에서 기다리는 레코드 수 |
stats.success | number | 발송 처리에 성공한 레코드 수 |
stats.failed | number | 발송 오류가 발생한 레코드 수 |
stats.cancelled | number | 취소된 레코드 수 |
stats.total | number | 전체 레코드 수(pending + success + failed + cancelled) |
stats.success는 시스템이 메시지를 성공적으로 전달 처리했다는 뜻입니다. Meta가 메시지를 수신자에게 전달했음을 보장하는 것은 아닙니다. Meta가 이후에 생성하는 상태 업데이트(delivered, read, failed 등)는 이 카운터에 영향을 주지 않으며 여기에 반영되지 않습니다.
- stats 엔드포인트: 발송 작업의 상태(pending, success, failed, cancelled)를 보여 줍니다
- message-stats 엔드포인트: 실제 메시지 상태(
pending,sending,sent,delivered,read,error등)를 보여 줍니다 - 작업은 성공했더라도 메시지가 아직 전달되지 않았거나 읽히지 않았을 수 있습니다
참조 ID
referenceId는 추적을 위해 발송 레코드를 자체 시스템의 ID(예: 주문 번호, 티켓 ID)와 대조할 때 사용하는 선택 필드입니다.
입력하는 경우 대량 요청 안에서 고유해야 합니다(최대 256자).
- 반드시 사용해야 하는 것은 아닙니다
- 같은 대량 메시지 안에서는 중복될 수 없습니다
- 서로 다른 대량 메시지에서는 다시 사용할 수 있습니다
Message Stats — WhatsApp 메시지 상태
대량 메시지의 메시지 상태 통계를 조회합니다. stats 엔드포인트와 달리 작업 상태가 아니라 레코드별 실제 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/bulk-message/message-stats.js
요청 파라미터
| 파라미터 | 유형 | 필수 | 설명 |
|---|---|---|---|
bulkMessageId | string | 예 | 조회할 대량 메시지의 ID |
{
"bulkMessageId": "abc123xyz789"
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/message-stats.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"bulkMessageId": "abc123xyz789"
}'
응답
{
"bulkMessage": {
"_id": "abc123xyz789",
"slug": "my-workspace",
"type": "perRecipient",
"title": "Campaign Title"
},
"messageStats": {
"pending": 5,
"sending": 2,
"sent": 10,
"delivered": 45,
"read": 30,
"deleted": 2,
"warning": 1,
"error": 3,
"unknown": 0,
"not-sended": 2,
"no-message": 10,
"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수가 많으면 발송이 아직 진행 중이라는 뜻입니다delivered수는 메시지가 성공적으로 전달된 건수를 보여 줍니다read수로 캠페인 참여도를 측정할 수 있습니다- 이 엔드포인트를 주기적으로 호출해 실시간으로 추적할 수 있습니다
Options 구조 — 페이지 나누기, 필터링, 정렬
list와 list-with-messages 엔드포인트에서 사용하는 options 파라미터는 페이지 나누기, 필터링, 정렬을 위한 표준 구조를 제공합니다.
Options 필드
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
pagination | object | 아니요 | 페이지 나누기 설정 |
filtering | object | 아니요 | 필터 조건 |
sorting | object | 아니요 | 정렬 설정(예: {"createdAt": -1}) |
Pagination 구조
| 필드 | 유형 | 기본값 | 설명 |
|---|---|---|---|
currentPage | number | 1 | 조회할 페이지 번호 |
pageItems | number | 50 | 페이지당 레코드 수(최대 50) |
Filtering 구조
필터링은 MongoDB 쿼리 형식을 사용합니다. 레코드 필드로 필터링할 수 있으며, list-with-messages 엔드포인트에서는 메시지 필드(예: message.status)로도 필터링할 수 있습니다.
// Filter by record status
{
"options": {
"filtering": {
"status": "success"
}
}
}
// Filter by referenceId
{
"options": {
"filtering": {
"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"]
}
}
}
}
Sorting 구조
정렬은 MongoDB 정렬 형식을 사용합니다. 1은 오름차순, -1은 내림차순입니다.
// Sort by creation date descending (newest first)
{
"options": {
"sorting": {
"createdAt": -1
}
}
}
// Sort by multiple fields
{
"options": {
"sorting": {
"status": 1,
"createdAt": -1
}
}
}
조합 사용 예시
{
"bulkMessageId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 2,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
},
"sorting": {
"createdAt": -1
}
}
}
이 예시는 전달된 메시지를 최신순으로 정렬합니다.
filtering과pagination을 함께 사용해 원하는 레코드만 조회하세요- 응답에는 페이지 이동에 쓸 수 있는
options.pagination.totalCount와options.pagination.totalPages가 포함됩니다 message.status필터는list-with-messages엔드포인트에서만 작동합니다
Records — 레코드 상세 및 목록
대량 메시지의 모든 발송 레코드를 조회합니다. 각 레코드는 수신자에게 보낸 메시지 하나를 나타냅니다.
List — 레코드 목록
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message-records/list.js
요청 파라미터
| 파라미터 | 유형 | 필수 | 설명 |
|---|---|---|---|
bulkMessageId | string | 예 | 조회할 대량 메시지의 ID |
options | object | 아니요 | 페이지 나누기, 필터링, 정렬 옵션. 자세한 내용은 Options 구조를 참고하세요. |
요청 — 기본 사용법
{
"bulkMessageId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
요청 — 특정 상태로 필터링
{
"bulkMessageId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"status": "success"
}
}
}
발송에 성공한 레코드(record.status = "success")만 조회합니다.
응답
{
"bulkMessageRecords": [
{
"_id": "record_1",
"bulkMessageId": "abc123xyz789",
"slug": "my-workspace",
"userId": "user_123",
"sessionId": "session_456",
"messageId": "msg_789",
"referenceId": "ORDER-12345",
"status": "success",
"createdAt": "2026-06-10T10:00:00.000Z"
}
],
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50,
"totalCount": 150,
"totalPages": 3
},
"sorting": {},
"filtering": {}
}
}
List With Messages — 메시지 상세가 포함된 목록
list 엔드포인트와 기능(페이지 나누기, 필터링, 정렬)이 같습니다. 단 하나의 차이점은 레코드에 messageId가 있으면 관련 message 객체도 함께 반환된다는 것입니다. 한 번의 조회로 메시지 상태(delivered, read, error 등)와 페이로드를 확인할 수 있습니다.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message-records/list-with-messages.js
요청 — 기본 사용법
{
"bulkMessageId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
요청 — 메시지 상태로 필터링
{
"bulkMessageId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
}
}
}
이 예시는 "delivered" 상태인 메시지만 가져옵니다.
요청 — 실패한 메시지 조회
{
"bulkMessageId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "error"
}
}
}
발송 오류가 발생한 메시지를 확인할 때 사용합니다.
응답
{
"bulkMessageRecords": [
{
"_id": "record_1",
"bulkMessageId": "abc123xyz789",
"userId": "user_123",
"messageId": "msg_789",
"referenceId": "ORDER-12345",
"status": "success",
"message": {
"_id": "msg_789",
"status": "delivered",
"payload": {
"type": "template",
"template": {
"templateName": "order_notification"
}
},
"createdAt": "2026-06-10T10:01:00.000Z",
"deliveredAt": "2026-06-10T10:01:05.000Z"
}
}
],
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50,
"totalCount": 150,
"totalPages": 3
},
"sorting": {},
"filtering": {}
}
}
Record 필드
| 필드 | 유형 | 설명 |
|---|---|---|
_id | string | 레코드 ID |
bulkMessageId | string | 이 레코드가 속한 대량 메시지 ID |
userId | string | 수신자 사용자 ID |
sessionId | string | 대화 세션 ID |
messageId | string | 발송된 메시지 ID(아직 발송되지 않았으면 null) |
referenceId | string | 선택 참조 ID(입력한 경우) |
status | string | 레코드 상태: pending, success, failed, cancelled |
message | object | 메시지 상세(list-with-messages에서만) |
List와 List-With-Messages 비교
| 기능 | list | list-with-messages |
|---|---|---|
| 페이지 나누기 | 예 | 예 |
| 필터링 | 예(레코드 필드만) | 예(레코드 + 메시지 필드) |
| Message 객체 | 아니요 | 예(messageId가 있는 경우) |
| 성능 | 빠름 | 보통(JOIN 수행) |
| message.status 필터 | 사용 불가 | 사용 가능 |
- list: 모든 레코드를 빠르게 조회하고, referenceId로 필터링하고, 레코드 상태를 확인
- list-with-messages: WhatsApp 메시지 상태(delivered, read)를 확인하고 메시지 페이로드를 검토
- 필터링 예시:
{"status": "failed"}— 발송에 실패한 레코드{"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 전용){"status": {"$in": ["success", "pending"]}}— 성공했거나 대기 중인 레코드
list엔드포인트가 더 빠르므로 일반적인 상태 확인에는 이것을 사용하세요- 메시지 상세가 필요하면
list-with-messages를 사용하세요 - 페이지당 최대 레코드 수(pageItems)는 50이며, 지정하지 않으면 기본값은 50입니다
message.status필터는list-with-messages에서만 작동합니다- messageId가 null인 레코드는
message객체도 null입니다
Stop — 발송 취소
진행 중인 대량 메시지 발송을 중단합니다. 대기 중인 작업이 취소되고 모든 pending 레코드가 cancelled 상태로 바뀝니다. 이미 success 또는 failed로 처리된 레코드는 영향을 받지 않습니다.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/stop.js
이 작업은 되돌릴 수 없습니다. 중단된 발송은 다시 시작할 수 없습니다.
요청 파라미터
| 파라미터 | 유형 | 필수 | 설명 |
|---|---|---|---|
bulkMessageId | string | 예 | 중단할 대량 메시지의 ID |
{
"bulkMessageId": "abc123xyz789"
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/stop.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"bulkMessageId": "abc123xyz789"
}'
응답
요청이 성공하면 응답 본문은 비어 있습니다. HTTP 200 상태는 작업이 성공적으로 완료되었음을 나타냅니다.
{}
- 이 API로 생성한 대량 메시지만 중단할 수 있습니다
- 발송을 중단한 후
stats엔드포인트로 취소된 레코드 수를 확인할 수 있습니다 - 대량 메시지를 찾을 수 없으면 API가
bulkMessageNotFound오류를 반환합니다