Dokumentacja Bulk Template Message API — v2
To API umożliwia jednoczesne wysyłanie wiadomości szablonowych do wielu odbiorców przez kanał WhatsApp.
Dostarczanie wiadomości odbywa się asynchronicznie: żądanie API natychmiast zwraca bulkOperationId, a wiadomości są kolejkowane i przetwarzane w tle.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/send.js
Każdy endpoint w tym dokumencie jest funkcją niestandardową (custom function). Treść odpowiedzi HTTP zawiera własne pola funkcji (_id, title, pathString…), a właściwą odpowiedź endpointu w polu result. Przykłady odpowiedzi w tym dokumencie pokazują zawartość result:
{
"_id": "function_id",
"title": "Show",
"pathString": "/bulk-message-api-app/api/v2/bulk-operation/show.js",
"result": {
"bulkOperation": { "_id": "abc123xyz789", "status": "running" }
}
}
Migracja z v1
v2 działa równolegle z v1, więc możesz przeprowadzić migrację we własnym tempie. Endpointy v1 (/api/bulk-message/…, /api/bulk-message-records/…) zostaną wycofane; nowe integracje powinny korzystać z v2.
- Zmień ścieżki endpointów na v2:
…/api/bulk-message/…zmienia się na…/api/v2/bulk-operation/…, a…/api/bulk-message-records/…na…/api/v2/bulk-operation-items/…. Treść żądaniasendsię nie zmienia; jedno żądanie przyjmuje teraz do 100 000 odbiorców zamiast 5 000. - W żądaniach wysyłaj
bulkOperationIdzamiastbulkMessageId. - Zastąp
stats.jsprzezshow.js. - Odczytuj odpowiedzi z użyciem nowych nazw pól z tabeli poniżej.
Endpointy v2 znają tylko operacje masowe utworzone za pomocą send w v2. Aby śledzić wiadomość masową utworzoną w v1 przed migracją, nadal używaj dla niej endpointów v1.
Endpointy
| v1 | v2 | Co zmienia się w odpowiedzi |
|---|---|---|
bulk-message/send.js | v2/bulk-operation/send.js | { bulkMessageId } zmienia się na { bulkOperationId } |
bulk-message/stats.js | v2/bulk-operation/show.js | { bulkMessage, stats } zmienia się na { bulkOperation } |
bulk-message/message-stats.js | v2/bulk-operation/message-stats.js | Liczniki są na najwyższym poziomie zamiast w messageStats |
bulk-message/stop.js | v2/bulk-operation/stop.js | Nic |
bulk-message-records/list.js | v2/bulk-operation-items/list.js | bulkMessageRecords zmienia się na bulkOperationItems |
bulk-message-records/list-with-messages.js | v2/bulk-operation-items/list-with-messages.js | To samo co w list, a każdy element zawiera też session |
Nazwy pól
| 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 (wiadomość masowa) | bulkOperation (operacja masowa) |
bulkMessageRecord (rekord) | bulkOperationItem (element) |
bulkMessageId w żądaniach, w odpowiedzi send i w rekordach | bulkOperationId |
username / userId / sessionId rekordu w postaci wysłanej | payload.username / payload.userId / payload.sessionId |
referenceId rekordu | payload.referenceId |
payload rekordu (ładunek szablonu odbiorcy) | payload.payload |
userId, sessionId, messageId rekordu po wysłaniu | result.userId, result.sessionId, result.messageId |
status rekordu success | succeeded |
errorMessage w nieudanych rekordach | error.message, obok error.code i error.retryable |
| — | position (indeks odbiorcy w recipients) |
filtr {"status": "success"} | {"status": "succeeded"} |
filtr {"referenceId": "…"} | {"payload.referenceId": "…"} |
błędy send schema-error, invalidRequest | zod-schema-error, ze ścieżką nieprawidłowego pola w komunikacie |
Kluczowe funkcje
- Wysyłanie wiadomości szablonowych do 1–100 000 odbiorców w jednym żądaniu
- Spersonalizowane zmienne dla każdego odbiorcy (HEADER, BODY, BUTTONS, CAROUSEL)
- Wspólny
defaultPayloaddla wszystkich odbiorców ze scalaniem zpayloadkonkretnego odbiorcy (isMerge) - Zaplanowana wysyłka (
scheduleAt) - Wskazywanie odbiorców za pomocą
username(numer telefonu),userIdlubsessionId - Wysyłanie wielu wiadomości do tego samego użytkownika w jednym żądaniu masowym
- Opcjonalny
referenceIddo śledzenia rekordów w systemach zewnętrznych - Automatyczne przypisanie rozmów do użytkownika lub grupy roboczej po wysłaniu (
action)
To API może wysyłać tylko szablony zatwierdzone przez Meta.
Nazwa szablonu i kod języka muszą dokładnie odpowiadać szablonowi zarejestrowanemu w Meta Business Manager.
Parametry żądania
Parametry najwyższego poziomu
| Parametr | Typ | Wymagany | Opis |
|---|---|---|---|
channelUsername | string | Tak | Numer kanału WhatsApp używany do wysłania wiadomości (np. "908506669933") |
connectorBrand | string | Tak | Marka konektora kanału. Obecnie obsługiwana wartość: "whatsapp" |
title | string | Nie | Tytuł kampanii. Używany do wyświetlania w panelu. Domyślnie: "-" |
scheduleAt | string (ISO 8601) | Nie | Zaplanowana data i godzina wysyłki (np. "2026-06-10T10:00:00.000Z"). Jeśli pominięto, wiadomości są wysyłane natychmiast. |
defaultPayload | object | Warunkowo* | Domyślny ładunek szablonu stosowany do wszystkich odbiorców. Wymagany, jeśli odbiorca nie podaje własnego payload. |
recipients | array | Tak | Lista odbiorców. Minimum 1, maksimum 100 000 odbiorców. |
action | object | Nie | Działanie zastosowane do rozmowy po wysłaniu. assign-to-user lub assign-to-workgroup. |
*Jeśli każdy odbiorca podaje własny payload, defaultPayload jest opcjonalny.
Struktura odbiorcy
Dla każdego odbiorcy należy podać dokładnie jeden z parametrów username, userId lub sessionId. Nie można używać kilku identyfikatorów jednocześnie, a pominięcie wszystkich spowoduje błąd.
Aby wysłać wiele wiadomości do tego samego użytkownika w jednym żądaniu masowym, dodaj ten sam identyfikator do listy odbiorców wielokrotnie.
| Pole | Typ | Opis |
|---|---|---|
username | string | Numer telefonu odbiorcy (np. "905554443322"). Jeśli użytkownik nie istnieje w systemie, zostanie utworzony automatycznie. |
userId | string | Identyfikator istniejącego użytkownika w systemie. |
sessionId | string | Identyfikator istniejącej sesji rozmowy w systemie. |
referenceId | string | Opcjonalny identyfikator referencyjny (maks. 256 znaków) do dopasowania z rekordami systemów zewnętrznych (CRM, zamówienie, zgłoszenie itp.). Jeśli podany, musi być unikalny w obrębie wysyłki masowej. |
payload | object | Ładunek szablonu dla konkretnego odbiorcy (opcjonalny). Jeśli isMerge: true, jest scalany z defaultPayload. |
isMerge | boolean | Zastępuje zachowanie scalania dla tego odbiorcy (opcjonalne). Jeśli pominięto, używane jest defaultPayload.isMerge. |
Struktura działania
| Pole | Typ | Opis |
|---|---|---|
action.key | string | "assign-to-user" przypisuje rozmowę do konkretnego agenta; "assign-to-workgroup" przypisuje ją do grupy roboczej. |
action.value | string | Identyfikator docelowego użytkownika lub grupy roboczej. |
Struktura ładunku szablonu
defaultPayload i payload konkretnego odbiorcy mają tę samą strukturę. W przypadku wiadomości szablonowych należy podać type: "template".
{
"type": "template",
"template": {
"templateName": "order_confirmation",
"languageCode": "tr-TR",
"variables": []
},
"isMerge": true
}
| Pole | Typ | Wymagany | Opis |
|---|---|---|---|
type | string | Tak | Typ ładunku. Dla wiadomości szablonowych: "template" |
template.templateName | string | Tak* | Nazwa szablonu zarejestrowanego w Meta. W ładunkach odbiorców jest opcjonalna, gdy używane jest isMerge: true (dziedziczona z ładunku domyślnego). |
template.languageCode | string | Nie | Kod języka szablonu (np. "tr", "en", "tr-TR", "en-US"). Musi dokładnie odpowiadać językowi zarejestrowanemu w Meta. |
template.variables | array | Nie | Lista zmiennych stosowanych do komponentów szablonu. Szczegóły poniżej. |
isMerge | boolean | Nie | true: ładunek odbiorcy jest głęboko scalany z defaultPayload. false lub pominięte: ładunek odbiorcy całkowicie zastępuje defaultPayload. |
- Jeśli
defaultPayload.isMerge: truei odbiorca podaje własnypayload, stosowane jest głębokie scalanie. - Przy głębokim scalaniu odbiorca może podać tylko
variables;templateNameilanguageCodesą dziedziczone z ładunku domyślnego. - Pole
isMergeodbiorcy zastępujedefaultPayload.isMerge. - Jeśli odbiorca nie podaje
payload, zawsze używany jestdefaultPayload.
Struktura zmiennych
Każdy element tablicy variables odpowiada komponentowi szablonu. Typ komponentu (type) może wystąpić w tablicy tylko raz.
| type | Opis | parameters | cards |
|---|---|---|---|
"HEADER" | Komponent nagłówka szablonu. Zmienna tekstowa lub adres URL multimediów (obraz, wideo, dokument) | Tak | — |
"BODY" | Zmienne tekstu treści szablonu | Tak | — |
"BUTTONS" | Zmienne dynamicznego sufiksu URL dla przycisków | Tak | — |
"CAROUSEL" | Komponenty kart dla szablonów karuzeli | — | Tak |
Formaty parametrów
Pole parameters można podać w trzech różnych formatach:
// Format 1: Tablica (według indeksu) — dla symboli zastępczych takich jak {{1}}, {{2}}, {{3}}
"parameters": ["value1", "value2", "value3"]
// Format 2: Obiekt (klucze numeryczne) — alternatywna reprezentacja dla {{1}}, {{2}}
"parameters": { "1": "value1", "2": "value2" }
// Format 3: Obiekt (klucze nazwane) — dla symboli zastępczych takich jak {{name}}, {{amount}}
"parameters": { "name": "John", "amount": "150 USD" }
- Jeśli Twój szablon Meta używa symboli zastępczych takich jak
{{1}},{{2}}, użyj formatu tablicy lub obiektu z kluczami numerycznymi. - Jeśli Twój szablon używa nazwanych symboli zastępczych, takich jak
{{firstName}}lub{{orderTotal}}, użyj formatu obiektu z kluczami nazwanymi. - Przy użyciu tablic kolejność ma znaczenie: pierwszy element odpowiada
{{1}}, drugi{{2}}i tak dalej.
Komponent HEADER
Użyj komponentu HEADER, gdy nagłówek szablonu zawiera multimedia (obraz, wideo, dokument) lub tekst dynamiczny.
// Nagłówek multimedialny (adres URL obrazu)
{
"type": "HEADER",
"parameters": ["https://example.com/product-image.jpg"]
}
// Zmienna nagłówka tekstowego
{
"type": "HEADER",
"parameters": ["Special Campaign"]
}
Komponent BODY
Służy do dynamicznych zmiennych tekstowych w treści szablonu.
// Format tablicy — gdy szablon używa {{1}}, {{2}}, {{3}}
{
"type": "BODY",
"parameters": ["John", "ORD-12345", "150.00 USD"]
}
// Format nazwany — gdy szablon używa {{name}}, {{orderAmount}}
{
"type": "BODY",
"parameters": {
"name": "John",
"orderAmount": "150.00 USD"
}
}
Komponent BUTTONS
Służy do przycisków z dynamicznymi sufiksami URL. Jeśli szablon zawiera wiele przycisków URL, kolejno indeksowane są tylko przyciski ze zmiennymi (przyciski bez zmiennych oraz przyciski FLOW są pomijane).
// Zmienna sufiksu pojedynczego przycisku URL
{
"type": "BUTTONS",
"parameters": ["tracking/ORD-12345"]
}
// Zmienne sufiksów wielu przycisków URL (pierwszy przycisk URL, drugi przycisk URL)
{
"type": "BUTTONS",
"parameters": ["tracking/ORD-12345", "cancel/ORD-12345"]
}
Komponent CAROUSEL
W szablonach karuzeli zmienne komponentów definiuje się osobno dla każdej karty.
{
"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ługość tablicy cards musi dokładnie odpowiadać liczbie kart zdefiniowanych w szablonie.
Przykłady
1. Prosty szablon — bez zmiennych, ta sama treść dla wszystkich odbiorców
To najprostszy sposób wysłania statycznego szablonu bez zmiennych do wielu odbiorców.
{
"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" }
]
}'
- Odbiorcy podani przez
usernamesą tworzeni automatycznie, jeśli jeszcze nie istnieją w systemie - Wszyscy odbiorcy używają tego samego
defaultPayload; nie są wymagane żadne dane specyficzne dla odbiorcy - Gdy
isMergenie jest podane, każdy odbiorca bezpośrednio używadefaultPayload
2. Szablon ze wspólnymi zmiennymi treści
Ten sam szablon jest wysyłany do wszystkich odbiorców z identycznymi wartościami zmiennych. Szablon zawiera symbole zastępcze takie jak {{1}} i {{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" }]
}
- W tym przykładzie treść szablonu może brzmieć: "Skorzystaj ze zniżki
{{1}}w naszej kampanii! Oferta ważna do{{2}}." parameters[0]zastępuje{{1}}, aparameters[1]zastępuje{{2}}
3. Spersonalizowany szablon — zmienne dla każdego odbiorcy z isMerge
Dla każdego odbiorcy używane są inne wartości zmiennych. Po ustawieniu isMerge: true w defaultPayload odbiorcy muszą podać tylko variables; templateName i languageCode są dziedziczone z ładunku domyślnego.
W tym przykładzie szablon zawiera zarówno nagłówek multimedialny, jak i spersonalizowane zmienne treści.
{
"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"]
}
]
}
}
}
]
}
- Dzięki
isMerge: truetemplateNamenie musi być powtarzane w ładunku każdego odbiorcy - Tablica
variableskażdego odbiorcy jest całkowicie niezależna - Adres URL multimediów nagłówka musi być publicznie dostępny
- Jeśli w ładunku odbiorcy pominięto
type, dziedziczone jestdefaultPayload.type
4. Zmienna przycisku URL
Użyj komponentu BUTTONS, gdy szablon zawiera przycisk z dynamicznym sufiksem URL, na przykład numer przesyłki dołączony do bazowego adresu 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"]
}
]
}
}
}
]
}
- Parametry
BUTTONSsą dopasowywane według kolejności przycisków zawierających zmienne - Przyciski FLOW i przyciski bez zmiennych są pomijane; indeksowanie dotyczy tylko dynamicznych przycisków URL
- Jeśli adres URL przycisku szablonu to
https://example.com/track/{{1}}, toparameters[0]zastępuje{{1}}
5. Zaplanowana wysyłka
Zaplanuj wysłanie wiadomości w przyszłości. scheduleAt należy podać jako znacznik czasu 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" }
}
]
}
}
}
]
}
scheduleAtnależy podać w strefie czasowej UTC (np. dla godziny 10:00 czasu tureckiego użyj07:00:00.000Z)- W tym przykładzie użyto formatu parametrów nazwanych; szablon powinien zawierać symbole zastępcze takie jak
{{name}}i{{discountRate}} - Dzięki
actionrozmowy utworzone przez wysłanie wiadomości są automatycznie przypisywane do wskazanej grupy roboczej
Odpowiedź
Pomyślne żądanie zwraca bulkOperationId, którego można użyć do śledzenia procesu wysyłki:
{
"bulkOperationId": "abc123xyz789"
}
Odpowiedzi z błędami
| Status | Opis |
|---|---|
recipients field is required | Nie wysłano pola recipients |
Channel not found | Nie znaleziono zweryfikowanego kanału pasującego do channelUsername i connectorBrand |
Channel is not verified | Dopasowany kanał istnieje, ale nie został jeszcze zweryfikowany |
zod-schema-error | Pole w treści żądania nie przeszło walidacji schematu (brak wymaganego pola, nieprawidłowy typ, nieobsługiwana wartość, więcej niż jeden identyfikator u odbiorcy lub brak payload). Komunikat wskazuje pole, np. recipients.0.referenceId: referenceId must be unique |
Zwrócony bulkOperationId można wykorzystać w poniższych endpointach do sprawdzania statystyk dostarczania i zatrzymywania wysyłki.
Show — status i statystyki operacji masowej
Pobiera operację masową wraz z jej aktualnym statusem i licznikami dostarczania jej elementów, pod kluczem bulkOperation.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/show.js
Parametry żądania
| Parametr | Typ | Wymagany | Opis |
|---|---|---|---|
bulkOperationId | string | Tak | Identyfikator operacji masowej do śledzenia (zwrócony z 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"
}'
Odpowiedź
{
"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"
}
}
Pola Show
Pola znajdują się w bulkOperation.
| Pole | Typ | Opis |
|---|---|---|
status | string | Status operacji masowej: preparing, scheduled, pending, running, stopping, stopped, completed, failed |
progress.total | number | Łączna liczba elementów |
progress.pending | number | Elementy nadal oczekujące w kolejce |
progress.succeeded | number | Elementy pomyślnie przekazane do wysyłki |
progress.failed | number | Elementy, w których wystąpił błąd dostarczania |
progress.cancelled | number | Elementy anulowane przez stop |
progress.unknown | number | Elementy, których wyniku nie udało się ustalić |
result.outcome | string | Wynik końcowy po zakończeniu operacji masowej: success, partial, all-failed, cancelled, unknown |
result.hasErrors | boolean | true, jeśli co najmniej jeden element się nie powiódł |
scheduleAt | string | Zaplanowany czas wysyłki (tylko dla zaplanowanych operacji masowych) |
startedAt, completedAt | string | Kiedy wysyłka się rozpoczęła i zakończyła |
progress.succeeded oznacza, że wiadomość została pomyślnie przekazana przez system. Nie gwarantuje, że Meta dostarczyła wiadomość do odbiorcy. Kolejne aktualizacje statusu generowane przez Meta (takie jak delivered, read lub failed) nie wpływają na ten licznik i nie są tu odzwierciedlane.
- endpoint show: pokazuje status dostarczania elementów (
pending,succeeded,failed,cancelled,unknown) - endpoint message-stats: pokazuje rzeczywisty status wiadomości (
pending,sending,sent,delivered,read,erroritd.) - Element może mieć status
succeeded, a wiadomość może jeszcze nie zostać dostarczona ani przeczytana
Identyfikator referencyjny
referenceId to opcjonalne pole, którego możesz używać do dopasowywania elementów wysyłki do identyfikatora z własnego systemu w celach śledzenia (np. numer zamówienia, identyfikator zgłoszenia). Jest zwracany w każdym elemencie jako payload.referenceId.
Jeśli zostanie podany, musi być unikalny w obrębie wysyłki masowej (maks. 256 znaków).
- Użycie nie jest wymagane
- Nie może być zduplikowany w tej samej operacji masowej
- Może być ponownie użyty w różnych operacjach masowych
Message Stats — status wiadomości WhatsApp
Pobiera statystyki statusu wiadomości dla operacji masowej. W odróżnieniu od endpointu show pokazuje rzeczywisty message.status wysłanych wiadomości zamiast statusu elementu.
Możliwe statusy wiadomości: 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
Parametry żądania
| Parametr | Typ | Wymagany | Opis |
|---|---|---|---|
bulkOperationId | string | Tak | Identyfikator operacji masowej do sprawdzenia |
{
"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"
}'
Odpowiedź
{
"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
}
Pola Message Stats
| Pole | Typ | Opis |
|---|---|---|
pending | number | Wiadomości jeszcze niewysłane |
sending | number | Wiadomości aktualnie wysyłane |
sent | number | Wiadomości przekazane do WhatsApp, jeszcze niedostarczone |
delivered | number | Wiadomości dostarczone na telefon odbiorcy |
read | number | Wiadomości przeczytane przez odbiorcę |
deleted | number | Usunięte wiadomości |
warning | number | Wiadomości z ostrzeżeniami |
error | number | Wiadomości z błędami |
unknown | number | Wiadomości o nieznanym statusie |
not-sended | number | Wiadomości, których nie udało się wysłać |
no-message | number | Elementy bez wiadomości (nadal w kolejce, nieudane lub anulowane) |
total | number | Łączna liczba elementów |
- Wysoka wartość
no-message, gdy operacja masowa ma statusrunning, oznacza, że wysyłka nadal trwa - Wartość
deliveredpokazuje pomyślnie dostarczone wiadomości - Wartość
readmożna wykorzystać do pomiaru zaangażowania w kampanię - Możesz okresowo odpytywać ten endpoint, aby śledzić wysyłkę w czasie rzeczywistym
Struktura Options — paginacja, filtrowanie i sortowanie
Parametr options używany w endpointach list i list-with-messages zapewnia standardową strukturę paginacji, filtrowania i sortowania.
Pola Options
| Pole | Typ | Wymagany | Opis |
|---|---|---|---|
pagination | object | Nie | Ustawienia paginacji |
filtering | object | Nie | Kryteria filtrowania |
sorting | object | Nie | Ustawienia sortowania (np. {"position": 1}) |
Struktura paginacji
Jeśli pagination nie zostanie wysłane, zwracana jest pierwsza strona z maksymalnie 50 elementami. Jeśli zostanie wysłane, currentPage jest wymagane.
| Pole | Typ | Domyślnie | Opis |
|---|---|---|---|
currentPage | number | — | Numer strony do pobrania (wymagany, gdy wysyłane jest pagination) |
pageItems | number | 50 | Liczba elementów na stronę (maksimum: 50) |
Struktura filtrowania
Filtrowanie odbywa się w formacie zapytań MongoDB według pól elementu, z nazwami pól dokładnie takimi, jak w odpowiedzi (np. status, payload.referenceId, result.messageId). W endpoincie list-with-messages można też filtrować według pól wiadomości (np. message.status).
// Filtrowanie według statusu elementu
{
"options": {
"filtering": {
"status": "succeeded"
}
}
}
// Filtrowanie według referenceId
{
"options": {
"filtering": {
"payload.referenceId": "ORDER-12345"
}
}
}
// Filtrowanie według statusu wiadomości (tylko list-with-messages)
{
"options": {
"filtering": {
"message.status": "delivered"
}
}
}
// Filtrowanie według wielu statusów za pomocą $in (operator MongoDB)
{
"options": {
"filtering": {
"message.status": {
"$in": ["delivered", "read"]
}
}
}
}
// Wykluczenie wybranych statusów za pomocą $nin (operator MongoDB)
{
"options": {
"filtering": {
"message.status": {
"$nin": ["error", "not-sended"]
}
}
}
}
// Lista elementów bez wiadomości (tylko list-with-messages)
{
"options": {
"filtering": {
"message": {
"$exists": false
}
}
}
}
Struktura sortowania
Sortowanie odbywa się w formacie sortowania MongoDB. 1 oznacza rosnąco, -1 malejąco. position to pozycja odbiorcy w tablicy recipients żądania (licząc od 0).
// Sortowanie w kolejności odbiorców przesłanych w żądaniu
{
"options": {
"sorting": {
"position": 1
}
}
}
// Sortowanie według wielu pól
{
"options": {
"sorting": {
"status": 1,
"position": 1
}
}
}
Przykład połączonego użycia
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 2,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
},
"sorting": {
"position": 1
}
}
}
Ten przykład wyświetla drugą stronę dostarczonych wiadomości w kolejności odbiorców.
- Połącz
filteringipagination, aby tworzyć precyzyjne zapytania - Odpowiedź zawiera
options.pagination.totalCountioptions.pagination.totalPagesdo nawigacji - Filtr
message.statusdziała tylko w endpoincielist-with-messages
Items — szczegóły i lista elementów
Wyświetla wszystkie elementy wysyłki operacji masowej. Każdy element odpowiada jednej pozycji tablicy recipients.
List — lista elementów
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation-items/list.js
Parametry żądania
| Parametr | Typ | Wymagany | Opis |
|---|---|---|---|
bulkOperationId | string | Tak | Identyfikator operacji masowej do wyświetlenia |
options | object | Nie | Opcje paginacji, filtrowania i sortowania. Szczegóły w sekcji Struktura Options. |
Żądanie — podstawowe użycie
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
Żądanie — filtrowanie według konkretnego statusu
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"status": "failed"
}
}
}
Wyświetla tylko nieudane elementy wysyłki, z przyczyną w error.
Odpowiedź
{
"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 — lista ze szczegółami wiadomości
Ma te same funkcje co endpoint list (paginacja, filtrowanie, sortowanie). Różnica: każdy element zawiera też powiązane obiekty message i session, jeśli istnieją. Dzięki temu w jednym zapytaniu zobaczysz status wiadomości (delivered, read, error itd.) oraz ładunek.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation-items/list-with-messages.js
Żądanie — podstawowe użycie
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
Żądanie — filtrowanie według statusu wiadomości
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
}
}
}
Ten przykład pobiera tylko wiadomości o statusie "delivered".
Żądanie — lista nieudanych wiadomości
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "error"
}
}
}
Służy do przeglądania wiadomości, w których wystąpiły błędy dostarczania.
Odpowiedź
{
"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": {}
}
}
Pola elementu
| Pole | Typ | Opis |
|---|---|---|
_id | string | Identyfikator elementu |
bulkOperationId | string | Identyfikator operacji masowej, do której należy element |
position | number | Pozycja odbiorcy w tablicy recipients żądania, licząc od 0 |
payload | object | Odbiorca dokładnie w takiej postaci, w jakiej został wysłany w żądaniu (username / userId / sessionId, referenceId, payload, isMerge) |
status | string | Status elementu: pending, succeeded, failed, cancelled, unknown |
error | object | Tylko w elementach failed: code, message i retryable |
result.userId | string | Identyfikator użytkownika-odbiorcy |
result.sessionId | string | Identyfikator sesji rozmowy |
result.messageId | string | Identyfikator wysłanej wiadomości (brak, jeśli nie wysłano wiadomości) |
completedAt | string | Kiedy element został przetworzony |
message | object | Szczegóły wiadomości (tylko w list-with-messages) |
session | object | Szczegóły rozmowy (tylko w list-with-messages) |
Porównanie List i List-With-Messages
| Cecha | list | list-with-messages |
|---|---|---|
| Paginacja | Tak | Tak |
| Filtrowanie | Tak (tylko pola elementu) | Tak (pola elementu i wiadomości) |
| Message / Session | Nie | Tak (jeśli istnieją) |
| Wydajność | Szybko | Średnio (wykonuje JOIN) |
| Filtr message.status | Niedostępny | Dostępny |
- list: szybkie wyświetlanie wszystkich elementów, filtrowanie według referenceId, sprawdzanie statusów elementów
- list-with-messages: podgląd statusów wiadomości WhatsApp (delivered, read), sprawdzanie ładunków wiadomości
- Przykłady filtrowania:
{"status": "failed"}— nieudane elementy wysyłki{"payload.referenceId": "ORDER-123"}— konkretny identyfikator referencyjny{"message.status": "delivered"}— dostarczone wiadomości (tylko list-with-messages){"message.status": "read"}— przeczytane wiadomości (tylko list-with-messages){"message.status": "error"}— wiadomości z błędami (tylko list-with-messages){"message.status": {"$in": ["delivered", "read"]}}— wiadomości dostarczone lub przeczytane (tylko list-with-messages){"message.status": {"$nin": ["error", "not-sended"]}}— wiadomości z wyłączeniem błędów i niewysłanych (tylko list-with-messages){"message": {"$exists": false}}— elementy bez wiadomości (tylko list-with-messages){"status": {"$in": ["succeeded", "pending"]}}— elementy zakończone powodzeniem lub oczekujące
- Endpoint
listjest szybszy; preferuj go do ogólnego sprawdzania statusów - Używaj
list-with-messages, gdy potrzebne są szczegóły wiadomości - Maksymalna liczba elementów na stronę (pageItems) to 50; domyślnie 50, jeśli nie podano
- Filtr
message.statusdziała tylko wlist-with-messages - Elementy bez
result.messageIdnie mają obiektumessage
Stop — anulowanie wysyłki
Zatrzymuje trwającą wysyłkę operacji masowej. Wszystkie elementy pending otrzymują status cancelled, a operacja masowa przechodzi w stan stopped. Elementy już przetworzone jako succeeded lub failed nie są zmieniane. Zaplanowaną operację masową można też zatrzymać przed czasem scheduleAt.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/stop.js
Tej operacji nie można cofnąć. Zatrzymanej wysyłki nie można wznowić.
Parametry żądania
| Parametr | Typ | Wymagany | Opis |
|---|---|---|---|
bulkOperationId | string | Tak | Identyfikator operacji masowej do zatrzymania |
{
"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"
}'
Odpowiedź
W przypadku pomyślnego żądania treść odpowiedzi jest pusta. Kod HTTP 200 oznacza, że operacja zakończyła się powodzeniem.
{}
- Zatrzymać można tylko operacje masowe utworzone za pomocą tego API
- Po zatrzymaniu wysyłki możesz użyć endpointu
show, aby sprawdzić liczbę anulowanych elementów (bulkOperation.progress.cancelled) - Jeśli nie znaleziono operacji masowej, API zwraca błąd:
Bulk operation not found.