Documentazione dell’API Bulk Template Message — v2
Questa API permette di inviare messaggi template a più destinatari contemporaneamente tramite il canale WhatsApp.
L’invio dei messaggi viene elaborato in modo asincrono; la richiesta API restituisce subito un bulkOperationId, mentre i messaggi vengono messi in coda ed elaborati in background.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/send.js
Ogni endpoint di questo documento è una custom function. Il corpo della risposta HTTP contiene i campi propri della funzione (_id, title, pathString…) e la risposta effettiva dell’endpoint in result. Gli esempi di risposta di questo documento mostrano il contenuto di result:
{
"_id": "function_id",
"title": "Show",
"pathString": "/bulk-message-api-app/api/v2/bulk-operation/show.js",
"result": {
"bulkOperation": { "_id": "abc123xyz789", "status": "running" }
}
}
Migrazione dalla v1
La v2 funziona in parallelo alla v1, quindi è possibile migrare con i propri tempi. Gli endpoint v1 (/api/bulk-message/…, /api/bulk-message-records/…) verranno dismessi; le nuove integrazioni devono usare la v2.
- Passare i percorsi degli endpoint alla v2:
…/api/bulk-message/…diventa…/api/v2/bulk-operation/…e…/api/bulk-message-records/…diventa…/api/v2/bulk-operation-items/…. Il corpo della richiestasendnon cambia; una singola richiesta ora accetta fino a 100.000 destinatari invece di 5.000. - Inviare
bulkOperationIdinvece dibulkMessageIdnelle richieste. - Sostituire
stats.jsconshow.js. - Leggere le risposte con i nuovi nomi dei campi indicati nella tabella seguente.
Gli endpoint v2 conoscono solo le operazioni in blocco create con il send della v2. Per seguire un messaggio in blocco creato con la v1 prima del passaggio, continuare a usare gli endpoint v1.
Endpoint
| v1 | v2 | Cosa cambia nella risposta |
|---|---|---|
bulk-message/send.js | v2/bulk-operation/send.js | { bulkMessageId } diventa { bulkOperationId } |
bulk-message/stats.js | v2/bulk-operation/show.js | { bulkMessage, stats } diventa { bulkOperation } |
bulk-message/message-stats.js | v2/bulk-operation/message-stats.js | I contatori sono al livello principale invece che sotto messageStats |
bulk-message/stop.js | v2/bulk-operation/stop.js | Niente |
bulk-message-records/list.js | v2/bulk-operation-items/list.js | bulkMessageRecords diventa bulkOperationItems |
bulk-message-records/list-with-messages.js | v2/bulk-operation-items/list-with-messages.js | Come list, e ogni elemento contiene anche session |
Nomi dei campi
| 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 (messaggio in blocco) | bulkOperation (operazione in blocco) |
bulkMessageRecord (record) | bulkOperationItem (elemento) |
bulkMessageId nelle richieste, nella risposta di send e nei record | bulkOperationId |
username / userId / sessionId del record così come inviati | payload.username / payload.userId / payload.sessionId |
referenceId del record | payload.referenceId |
payload del record (il payload del template del destinatario) | payload.payload |
userId, sessionId, messageId del record dopo l’invio | result.userId, result.sessionId, result.messageId |
stato del record success | succeeded |
errorMessage sui record non riusciti | error.message, accanto a error.code e error.retryable |
| — | position (l’indice del destinatario in recipients) |
filtro {"status": "success"} | {"status": "succeeded"} |
filtro {"referenceId": "…"} | {"payload.referenceId": "…"} |
errori di send schema-error, invalidRequest | zod-schema-error, con il percorso del campo non valido nel messaggio |
Funzionalità principali
- Invio di messaggi template in blocco a 1–100.000 destinatari in una singola richiesta
- Variabili personalizzate per ogni destinatario (HEADER, BODY, BUTTONS, CAROUSEL)
defaultPayloadcondiviso da tutti i destinatari, con unione delpayloadspecifico di ciascun destinatario (isMerge)- Invio programmato (
scheduleAt) - Indicazione dei destinatari tramite
username(numero di telefono),userIdosessionId - Invio di più messaggi allo stesso utente all’interno di una singola richiesta in blocco
referenceIdfacoltativo per collegare i record a sistemi esterni- Assegnazione automatica delle conversazioni a un utente o a un gruppo di lavoro dopo l’invio (
action)
Questa API può inviare solo template approvati da Meta.
Il nome del template e il codice lingua devono corrispondere esattamente al template registrato in Meta Business Manager.
Parametri della richiesta
Parametri di primo livello
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
channelUsername | string | Sì | Numero del canale WhatsApp usato per inviare il messaggio (ad es. "908506669933") |
connectorBrand | string | Sì | Marca del connettore del canale. Valore attualmente supportato: "whatsapp" |
title | string | No | Titolo della campagna. Usato per la visualizzazione nella dashboard. Predefinito: "-" |
scheduleAt | string (ISO 8601) | No | Data e ora di invio programmato (ad es. "2026-06-10T10:00:00.000Z"). Se omesso, i messaggi vengono inviati subito. |
defaultPayload | object | Condizionale* | Payload predefinito del template applicato a tutti i destinatari. Obbligatorio se un destinatario non fornisce un proprio payload. |
recipients | array | Sì | Elenco dei destinatari. Minimo 1, massimo 100.000 destinatari. |
action | object | No | Azione applicata alla conversazione dopo l’invio. assign-to-user o assign-to-workgroup. |
*Se ogni destinatario fornisce un proprio payload, defaultPayload è facoltativo.
Struttura del destinatario
Per ogni destinatario deve essere indicato esattamente uno tra username, userId e sessionId. Non si possono usare più identificativi insieme e ometterli tutti provoca un errore.
Per inviare più messaggi allo stesso utente all’interno di una singola richiesta in blocco, aggiungere lo stesso identificativo più volte all’elenco dei destinatari.
| Campo | Tipo | Descrizione |
|---|---|---|
username | string | Numero di telefono del destinatario (ad es. "905554443322"). Se l’utente non esiste nel sistema, viene creato automaticamente. |
userId | string | ID di un utente esistente nel sistema. |
sessionId | string | ID di una sessione di conversazione esistente nel sistema. |
referenceId | string | ID di riferimento facoltativo (massimo 256 caratteri) per il collegamento con i record di sistemi esterni (CRM, ordine, ticket e così via). Se indicato, deve essere univoco all’interno dell’invio in blocco. |
payload | object | Payload del template specifico del destinatario (facoltativo). Se isMerge: true, viene unito a defaultPayload. |
isMerge | boolean | Sostituisce il comportamento di unione per questo destinatario (facoltativo). Se omesso, viene usato defaultPayload.isMerge. |
Struttura dell’azione
| Campo | Tipo | Descrizione |
|---|---|---|
action.key | string | "assign-to-user" assegna la conversazione a un operatore specifico; "assign-to-workgroup" la assegna a un gruppo di lavoro. |
action.value | string | ID dell’utente o del gruppo di lavoro di destinazione. |
Struttura del payload del template
defaultPayload e il payload specifico del destinatario hanno la stessa struttura. Per i messaggi template deve essere indicato type: "template".
{
"type": "template",
"template": {
"templateName": "order_confirmation",
"languageCode": "tr-TR",
"variables": []
},
"isMerge": true
}
| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
type | string | Sì | Tipo di payload. Per i messaggi template: "template" |
template.templateName | string | Sì* | Nome del template registrato in Meta. Facoltativo nei payload dei destinatari quando si usa isMerge: true (viene ereditato dal payload predefinito). |
template.languageCode | string | No | Codice lingua del template (ad es. "tr", "en", "tr-TR", "en-US"). Deve corrispondere esattamente alla lingua registrata in Meta. |
template.variables | array | No | Elenco delle variabili applicate ai componenti del template. Dettagli più avanti. |
isMerge | boolean | No | true: il payload del destinatario viene unito in profondità a defaultPayload. false oppure omesso: il payload del destinatario sostituisce completamente defaultPayload. |
- Se
defaultPayload.isMerge: truee il destinatario fornisce un propriopayload, viene applicata un’unione in profondità. - Con l’unione in profondità, il destinatario può fornire solo
variables;templateNameelanguageCodevengono ereditati dal payload predefinito. - Il campo
isMergedel destinatario sostituiscedefaultPayload.isMerge. - Se un destinatario non fornisce un
payload, viene sempre usatodefaultPayload.
Struttura delle variabili
Ogni elemento dell’array variables corrisponde a un componente del template. Un tipo di componente (type) può comparire una sola volta nell’array.
| type | Descrizione | parameters | cards |
|---|---|---|---|
"HEADER" | Componente di intestazione del template. Variabile di testo o URL multimediale (immagine, video, documento) | Sì | — |
"BODY" | Variabili di testo del corpo del template | Sì | — |
"BUTTONS" | Variabili del suffisso URL dinamico per i pulsanti | Sì | — |
"CAROUSEL" | Componenti delle schede per i template a carosello | — | Sì |
Formati dei parametri
Il campo parameters può essere indicato in tre formati diversi:
// 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" }
- Se il tuo template Meta usa segnaposto come
{{1}},{{2}}, usa il formato array oppure il formato oggetto con chiavi numeriche. - Se il tuo template usa segnaposto con nome come
{{firstName}}o{{orderTotal}}, usa il formato oggetto con chiavi nominali. - Con gli array l’ordine conta: il primo elemento corrisponde a
{{1}}, il secondo a{{2}}e così via.
Componente HEADER
Usa il componente HEADER quando l’intestazione del template contiene un contenuto multimediale (immagine, video, documento) o testo dinamico.
// Media header (image URL)
{
"type": "HEADER",
"parameters": ["https://example.com/product-image.jpg"]
}
// Text header variable
{
"type": "HEADER",
"parameters": ["Special Campaign"]
}
Componente BODY
Serve per le variabili di testo dinamiche nel corpo del template.
// 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"
}
}
Componente BUTTONS
Serve per i pulsanti con suffissi URL dinamici. Se il template contiene più pulsanti URL, vengono indicizzati in sequenza solo i pulsanti con variabili (i pulsanti senza variabili o i pulsanti FLOW vengono ignorati).
// 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"]
}
Componente CAROUSEL
Per i template a carosello, le variabili dei componenti sono definite separatamente per ogni scheda.
{
"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"]
}
]
}
]
}
La lunghezza dell’array cards deve corrispondere esattamente al numero di schede definite nel template.
Esempi
1. Template semplice — nessuna variabile, stesso contenuto per tutti i destinatari
È il modo più semplice per inviare a più destinatari un template statico senza variabili.
{
"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" }
]
}'
- I destinatari indicati tramite
usernamevengono creati automaticamente se non esistono già nel sistema - Tutti i destinatari usano lo stesso
defaultPayload; non servono dati specifici per destinatario - Quando
isMergenon è indicato, ogni destinatario usa direttamentedefaultPayload
2. Template con variabili del corpo condivise
Lo stesso template viene inviato a tutti i destinatari con valori di variabile identici. Il template contiene segnaposto come {{1}} e {{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" }]
}
- In questo esempio, il corpo del template potrebbe contenere un testo come: "Approfitta di uno sconto del
{{1}}nella nostra campagna! Offerta valida fino al{{2}}." parameters[0]sostituisce{{1}}, mentreparameters[1]sostituisce{{2}}
3. Template personalizzato — variabili per destinatario con isMerge
Per ogni destinatario si usano valori di variabile diversi. Impostando isMerge: true in defaultPayload, i destinatari devono fornire solo variables; templateName e languageCode vengono ereditati dal payload predefinito.
In questo esempio, il template include sia un’intestazione multimediale sia variabili personalizzate nel corpo.
{
"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"]
}
]
}
}
}
]
}
- Grazie a
isMerge: true,templateNamenon deve essere ripetuto nel payload di ogni destinatario - L’array
variablesdi ogni destinatario è del tutto indipendente - L’URL del contenuto multimediale dell’intestazione deve essere accessibile pubblicamente
- Se
typeè omesso nel payload del destinatario, viene ereditatodefaultPayload.type
4. Variabile di un pulsante URL
Usa il componente BUTTONS quando il template contiene un pulsante con un suffisso URL dinamico. Ad esempio, un numero di tracciamento aggiunto all’URL di base 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"]
}
]
}
}
}
]
}
- I parametri di
BUTTONSvengono associati in base all’ordine dei pulsanti che contengono variabili - I pulsanti FLOW e i pulsanti senza variabili vengono ignorati; l’indicizzazione riguarda solo i pulsanti URL dinamici
- Se l’URL del pulsante del template è
https://example.com/track/{{1}},parameters[0]sostituisce{{1}}
5. Invio programmato
Programma l’invio di un messaggio a una data e un’ora future. scheduleAt deve essere indicato come timestamp UTC 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" }
}
]
}
}
}
]
}
scheduleAtdeve essere indicato nel fuso orario UTC (ad es., per le 10:00 ora della Turchia, usa07:00:00.000Z)- Questo esempio usa il formato con parametri nominali; il template deve contenere segnaposto come
{{name}}e{{discountRate}} - Con
action, le conversazioni create dall’invio del messaggio vengono assegnate automaticamente al gruppo di lavoro indicato
Risposta
Una richiesta riuscita restituisce un bulkOperationId, utilizzabile per seguire il processo di invio:
{
"bulkOperationId": "abc123xyz789"
}
Risposte di errore
| Stato | Descrizione |
|---|---|
recipients field is required | Il campo recipients non è stato inviato |
Channel not found | Non è stato trovato alcun canale verificato corrispondente a channelUsername e connectorBrand |
Channel is not verified | Il canale corrispondente esiste ma non è ancora stato verificato |
zod-schema-error | Un campo del corpo della richiesta non ha superato la validazione dello schema (campo obbligatorio mancante, tipo errato, valore non supportato, più di un identificatore su un destinatario o payload mancante). Il messaggio indica il campo, ad es. recipients.0.referenceId: referenceId must be unique |
Il bulkOperationId restituito può essere usato con gli endpoint seguenti per consultare le statistiche di invio e interrompere il processo di invio.
Show — stato e statistiche dell’operazione in blocco
Recupera l’operazione in blocco con il suo stato attuale e i contatori di invio dei suoi elementi, sotto la chiave bulkOperation.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/show.js
Parametri della richiesta
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
bulkOperationId | string | Sì | ID dell’operazione in blocco da seguire (restituito da 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"
}'
Risposta
{
"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"
}
}
Campi di show
I campi si trovano sotto bulkOperation.
| Campo | Tipo | Descrizione |
|---|---|---|
status | string | Stato dell’operazione in blocco: preparing, scheduled, pending, running, stopping, stopped, completed, failed |
progress.total | number | Numero totale di elementi |
progress.pending | number | Elementi ancora in attesa nella coda |
progress.succeeded | number | Elementi elaborati con successo per l’invio |
progress.failed | number | Elementi che hanno incontrato un errore di invio |
progress.cancelled | number | Elementi annullati da stop |
progress.unknown | number | Elementi il cui risultato non è stato possibile determinare |
result.outcome | string | Esito finale al termine dell’operazione in blocco: success, partial, all-failed, cancelled, unknown |
result.hasErrors | boolean | true se almeno un elemento non è riuscito |
scheduleAt | string | Orario di invio programmato (solo per le operazioni in blocco programmate) |
startedAt, completedAt | string | Quando l’invio è iniziato e terminato |
progress.succeeded indica che il messaggio è stato consegnato con successo dal sistema. Non garantisce che Meta abbia recapitato il messaggio al destinatario. Gli aggiornamenti di stato successivi generati da Meta (come delivered, read o failed) non incidono su questo contatore e non vengono riportati qui.
- Endpoint show: mostra lo stato di invio degli elementi (
pending,succeeded,failed,cancelled,unknown) - Endpoint message-stats: mostra lo stato effettivo del messaggio (
pending,sending,sent,delivered,read,errore così via) - Un elemento può essere
succeededanche se il messaggio non è ancora stato recapitato o letto
ID di riferimento
Il referenceId è un campo facoltativo che consente di associare gli elementi di invio a un ID del proprio sistema a fini di tracciamento (ad es. numero d’ordine, ID del ticket). Viene restituito su ogni elemento come payload.referenceId.
Se indicato, deve essere univoco all’interno dell’invio in blocco (massimo 256 caratteri).
- Non è obbligatorio
- Non può essere duplicato all’interno della stessa operazione in blocco
- Può essere riutilizzato in operazioni in blocco diverse
Message Stats — stato dei messaggi WhatsApp
Recupera le statistiche sullo stato dei messaggi di un’operazione in blocco. A differenza dell’endpoint show, mostra il message.status effettivo dei messaggi inviati invece dello stato degli elementi.
Stati possibili del messaggio: 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
Parametri della richiesta
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
bulkOperationId | string | Sì | ID dell’operazione in blocco da consultare |
{
"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"
}'
Risposta
{
"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
}
Campi di Message Stats
| Campo | Tipo | Descrizione |
|---|---|---|
pending | number | Messaggi non ancora inviati |
sending | number | Messaggi in corso di invio |
sent | number | Messaggi consegnati a WhatsApp, non ancora recapitati |
delivered | number | Messaggi recapitati al telefono del destinatario |
read | number | Messaggi letti dal destinatario |
deleted | number | Messaggi eliminati |
warning | number | Messaggi con avvisi |
error | number | Messaggi con errori |
unknown | number | Messaggi con stato sconosciuto |
not-sended | number | Messaggi che non è stato possibile inviare |
no-message | number | Elementi senza messaggio (ancora in coda, non riusciti o annullati) |
total | number | Numero totale di elementi |
- Un valore alto di
no-messagementre l’operazione in blocco èrunningindica che l’invio è ancora in corso - Il valore di
deliveredindica i messaggi recapitati con successo - Il valore di
readpuò servire a misurare il coinvolgimento della campagna - Puoi interrogare periodicamente questo endpoint per un monitoraggio in tempo reale
Struttura di options — paginazione, filtri e ordinamento
Il parametro options usato negli endpoint list e list-with-messages offre una struttura standard per paginazione, filtri e ordinamento.
Campi di options
| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
pagination | object | No | Impostazioni di paginazione |
filtering | object | No | Criteri di filtro |
sorting | object | No | Impostazioni di ordinamento (ad es. {"position": 1}) |
Struttura della paginazione
Se pagination non viene inviato, viene restituita la prima pagina con un massimo di 50 elementi. Se viene inviato, currentPage è obbligatorio.
| Campo | Tipo | Predefinito | Descrizione |
|---|---|---|---|
currentPage | number | — | Numero della pagina da recuperare (obbligatorio quando si invia pagination) |
pageItems | number | 50 | Numero di elementi per pagina (massimo: 50) |
Struttura dei filtri
Il filtro si basa sul formato di query di MongoDB applicato ai campi degli elementi, con i nomi dei campi esattamente come compaiono nella risposta (ad es. status, payload.referenceId, result.messageId). Nell’endpoint list-with-messages si può filtrare anche per campi del messaggio (ad es. 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
}
}
}
}
Struttura dell’ordinamento
L’ordinamento si basa sul formato di ordinamento di MongoDB. 1 indica ordine crescente, -1 ordine decrescente. position è l’ordine del destinatario nell’array recipients della richiesta (a partire da 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
}
}
}
Esempio di uso combinato
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 2,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
},
"sorting": {
"position": 1
}
}
}
Questo esempio elenca la seconda pagina dei messaggi recapitati, nell’ordine dei destinatari.
- Combina
filteringepaginationper query mirate - La risposta include
options.pagination.totalCounteoptions.pagination.totalPagesper la navigazione - Il filtro
message.statusfunziona solo nell’endpointlist-with-messages
Items — dettagli ed elenco degli elementi
Elenca tutti gli elementi di invio di un’operazione in blocco. Ogni elemento corrisponde a una voce dell’array recipients.
List — elenco degli elementi
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation-items/list.js
Parametri della richiesta
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
bulkOperationId | string | Sì | ID dell’operazione in blocco da elencare |
options | object | No | Opzioni di paginazione, filtro e ordinamento. Per i dettagli vedi Struttura di options. |
Richiesta — uso di base
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
Richiesta — filtro per stato specifico
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"status": "failed"
}
}
}
Elenca solo gli elementi di invio non riusciti, con il motivo in error.
Risposta
{
"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 — elenco con dettagli dei messaggi
Ha le stesse funzionalità dell’endpoint list (paginazione, filtri, ordinamento). La differenza: ogni elemento contiene anche gli oggetti message e session corrispondenti, quando esistono. Così è possibile vedere lo stato del messaggio (delivered, read, error e così via) e il payload in un’unica query.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation-items/list-with-messages.js
Richiesta — uso di base
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
}
}
}
Richiesta — filtro per stato del messaggio
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "delivered"
}
}
}
Questo esempio recupera solo i messaggi con stato "delivered".
Richiesta — elenco dei messaggi non riusciti
{
"bulkOperationId": "abc123xyz789",
"options": {
"pagination": {
"currentPage": 1,
"pageItems": 50
},
"filtering": {
"message.status": "error"
}
}
}
Serve a esaminare i messaggi che hanno incontrato errori di invio.
Risposta
{
"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": {}
}
}
Campi dell’elemento
| Campo | Tipo | Descrizione |
|---|---|---|
_id | string | ID dell’elemento |
bulkOperationId | string | ID dell’operazione in blocco a cui appartiene l’elemento |
position | number | Ordine del destinatario nell’array recipients della richiesta, a partire da 0 |
payload | object | Il destinatario esattamente come è stato inviato nella richiesta (username / userId / sessionId, referenceId, payload, isMerge) |
status | string | Stato dell’elemento: pending, succeeded, failed, cancelled, unknown |
error | object | Solo sugli elementi failed: code, message e retryable |
result.userId | string | ID utente del destinatario |
result.sessionId | string | ID della sessione di conversazione |
result.messageId | string | ID del messaggio inviato (assente se non è stato inviato alcun messaggio) |
completedAt | string | Quando l’elemento è stato elaborato |
message | object | Dettagli del messaggio (solo in list-with-messages) |
session | object | Dettagli della conversazione (solo in list-with-messages) |
Confronto tra List e List-With-Messages
| Caratteristica | list | list-with-messages |
|---|---|---|
| Paginazione | Sì | Sì |
| Filtri | Sì (solo campi dell’elemento) | Sì (campi dell’elemento e del messaggio) |
| Message / Session | No | Sì (se esistono) |
| Prestazioni | Veloce | Medie (esegue un JOIN) |
| Filtro message.status | Non disponibile | Disponibile |
- list: elenca rapidamente tutti gli elementi, filtra per referenceId, controlla lo stato degli elementi
- list-with-messages: consulta lo stato dei messaggi WhatsApp (delivered, read), esamina i payload dei messaggi
- Esempi di filtro:
{"status": "failed"}— elementi di invio non riusciti{"payload.referenceId": "ORDER-123"}— un ID di riferimento specifico{"message.status": "delivered"}— messaggi recapitati (solo list-with-messages){"message.status": "read"}— messaggi letti (solo list-with-messages){"message.status": "error"}— messaggi con errori (solo list-with-messages){"message.status": {"$in": ["delivered", "read"]}}— messaggi recapitati o letti (solo list-with-messages){"message.status": {"$nin": ["error", "not-sended"]}}— messaggi esclusi quelli con errori e non inviati (solo list-with-messages){"message": {"$exists": false}}— elementi senza messaggio (solo list-with-messages){"status": {"$in": ["succeeded", "pending"]}}— elementi riusciti o in sospeso
- L’endpoint
listè più veloce; preferiscilo per i controlli generali sullo stato - Usa
list-with-messagesquando servono i dettagli dei messaggi - Il numero massimo di elementi per pagina (pageItems) è 50; se non specificato, il valore predefinito è 50
- Il filtro
message.statusfunziona solo inlist-with-messages - Gli elementi senza
result.messageIdnon hanno l’oggettomessage
Stop — annullare l’invio
Interrompe l’invio in corso di un’operazione in blocco. Tutti gli elementi pending passano allo stato cancelled e l’operazione in blocco diventa stopped. Gli elementi già elaborati come succeeded o failed non vengono modificati. Un’operazione in blocco programmata può essere interrotta anche prima del suo orario scheduleAt.
POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/v2/bulk-operation/stop.js
Questa azione non può essere annullata. Un invio interrotto non può essere ripreso.
Parametri della richiesta
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
bulkOperationId | string | Sì | ID dell’operazione in blocco da interrompere |
{
"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"
}'
Risposta
Per una richiesta riuscita, il corpo della risposta è vuoto. Uno stato HTTP 200 indica che l’operazione si è conclusa con successo.
{}
- Si possono interrompere solo le operazioni in blocco create tramite questa API
- Dopo aver interrotto un invio, è possibile usare l’endpoint
showper verificare il numero di elementi annullati (bulkOperation.progress.cancelled) - Se l’operazione in blocco non viene trovata, l’API restituisce l’errore:
Bulk operation not found.