20 tipi a cui iscriversi + webhook.test (non iscrivibile). Un endpoint con una lista di events esplicita riceve SOLO quei tipi; lista vuota/omessa = tutti (quelli nuovi entrano da soli). Il data di ciascuno:
| Tipo | Sottoscrivibile | Descrizione |
|---|---|---|
message.received | ✓ | Un cliente ti ha scritto. data.message = oggetto messaggio di WhatsApp (testo/immagine/audio/…); data.contacts[] identifica il mittente. |
message.echo | ✓ | 🌟 Il punto di forza di Coexistence: un messaggio che il TITOLARE ha mandato DAL TELEFONO, con il suo contenuto. origin='device' (non consuma il piano). from = il tuo numero aziendale. |
message.status | ✓ | Conferma di un messaggio che hai mandato tramite /v1. origin (api|device) distingue il tuo invio da quello fatto a mano dal telefono. Una conferma 'device' NON ha dietro un tuo messaggio — è previsto. Dal 29/09/2026 arriva anche quando Meta rifiuta il NOSTRO invio dopo il 202: status 'failed', stage 'send' (campo opzionale), failureCode (lo stesso catalogo di lastErrorCode) e messageId = il tuo msg_… (Meta non gli ha mai assegnato un wamid). Una sola volta per messaggio. |
connection.created | ✓ | Si è collegato un numero nuovo (pannello od onboarding ospitato). Il tuo externalId viaggia nella busta → attiva il cliente finale nel tuo sistema. |
connection.status_changed | ✓ | È cambiato lo stato di una connessione (es. status='disconnected'). Manda un avviso o metti in pausa gli invii a quel numero. |
connection.usage_threshold_reached | ✓ | Il limite di UN numero (il suo monthlyMessageLimit) ha raggiunto il 70/90/100%. Viene emesso UNA volta per (numero, periodo, soglia). Quello commerciale: avvisa quel cliente finale o alzagli il tetto. |
usage.threshold_reached | ✓ | La quota dell'ACCOUNT (somma di tutti i numeri) ha raggiunto una soglia. Esiste solo con un piano su misura con quota concordata: i piani pubblici non hanno tetto e non lo emettono. connection arriva a null, sequence 0. |
history.synced | ✓ | (Coexistence) riepilogo di ogni blocco della cronologia che Meta sincronizza al collegamento: quante conversazioni e quanti messaggi, la fase e l'avanzamento (progress 100 = Meta ha finito). shared:false = il titolare non ha condiviso la sua cronologia nell'app. I messaggi arrivano in history.batch solo se si è scelto di riceverli prima di collegare. |
history.batch | ✓ | (Coexistence) i messaggi della cronologia —fino a 6 mesi, entrambe le parti, senza gruppi—, se il titolare ha scelto di riceverla prima di collegare. Fino a 500 per evento, nel formato di Meta (message), con contact e direction. Deduplica per batchId: un blocco può arrivare due volte. Passa da una coda separata che non rallenta gli eventi in tempo reale. Con il tuo 2xx lo cancelliamo; altrimenti, dopo 7 giorni. |
history.completed | ✓ | (Coexistence) non resta più niente della cronologia di quel numero da consegnare: quanti messaggi sono stati consegnati (via webhook o via API), quanti sono scaduti e quanti non è stato possibile salvare. Arriva una volta. |
history.dropped | ✓ | (Coexistence) non siamo riusciti a salvare la cronologia di quel numero per consegnartela (reason: storage_limit, o disabled). Quello già salvato viene consegnato comunque. La cronologia resta sul telefono. Arriva una volta. |
template.status_changed | ✓ | È cambiato lo stato di un modello su Meta (approvato, rifiutato, in pausa, disattivato, qualità o categoria). Porta il nuovo stato e il motivo del rifiuto tradotto. Arriva tramite una sincronizzazione periodica: con qualche minuto di ritardo. |
template.draft_submitted | ✓ | Il tuo cliente finale ha proposto un modello da un link di proposta. La bozza NON è su Meta: arriva a Meta solo quando la approvi. |
account.trial_warning | ✓ | La prova gratuita dell'account finisce presto (data.days = 7, 3 o 1). connection=null. |
account.trial_expired | ✓ | La prova gratuita è finita: l'invio viene bloccato. La ricezione si interrompe 30 giorni dopo il blocco, con un avviso 7 giorni prima. connection=null. |
subscription.activated | ✓ | (Fatturazione) il primo pagamento è stato confermato e l'account del cliente del rivenditore è diventato attivo. connection=null. Reagisci attivando il suo servizio. |
subscription.cancelled | ✓ | (Fatturazione) disdetta dell'abbonamento. Continua a funzionare fino ad accessUntil; poi l'invio viene bloccato, e la ricezione si interrompe 30 giorni dopo il blocco (con un avviso 7 giorni prima). connection=null. |
billing.payment_failed | ✓ | (Fatturazione) un addebito ricorrente non è andato a buon fine. Entra in avviso/periodo di tolleranza (non interrompe ancora niente). Sollecita il tuo cliente PRIMA dell'interruzione. connection=null. |
billing.payment_recovered | ✓ | (Fatturazione) il pagamento è stato regolarizzato e l'account si è riattivato da solo. connection=null. |
billing.amount_updated | ✓ | (Fatturazione) è cambiato l'importo del tuo prossimo rinnovo. Puoi mostrare l'importo al tuo cliente prima che venga addebitato. connection=null. ⚠ Con la tariffa fissa il cambiamento dipende dal PIANO o dal tasso di cambio: overageArs e overageMessages arrivano a 0 (solo un piano su misura con quota concordata li muove). |
webhook.test | — | L'evento del pulsante 'Prova' del pannello. NON è sottoscrivibile: viene consegnato SEMPRE a quell'endpoint (anche se ha un elenco di eventi esplicito) per verificare connettività + firma. connection=null, data.test=true. Non trattarlo mai come traffico reale. |
message.received — data
{
"message": {
"id": "wamid.HBgL…",
"from": "5493511234567",
"type": "text",
"text": {
"body": "hola"
}
},
"contacts": [
{
"wa_id": "5493511234567",
"profile": {
"name": "Ana"
}
}
]
}message.echo — data
{
"origin": "device",
"message": {
"id": "wamid.HBgL…",
"from": "5493516516690",
"to": "5493511234567",
"type": "text",
"timestamp": "1754531482",
"text": {
"body": "te confirmo el turno para mañana 10hs"
}
}
}message.status — data
{
"messageId": "wamid.HBgL…",
"status": "read",
"origin": "device",
"recipient": "5493511234567",
"timestamp": "2026-08-06T00:31:25.000Z"
}connection.created — data
{
"status": "connected"
}connection.status_changed — data
{
"status": "disconnected",
"previousStatus": "connected"
}connection.usage_threshold_reached — data
{
"scope": "connection",
"threshold": 90,
"used": 900,
"limit": 1000,
"period": "2026-08",
"connection": {
"id": "conn_4eede070e5a84d1590bdce2ea1d837bc",
"label": "Farmacia López",
"externalId": "farmacia-lopez"
}
}usage.threshold_reached — data
{
"scope": "account",
"threshold": 90,
"used": 22610,
"limit": 25000,
"period": "2026-08"
}history.synced — data
{
"conversations": 34,
"messages": 512,
"shared": true,
"phase": 0,
"chunkOrder": 1,
"progress": 55
}history.batch — data
{
"batchId": "hb_3c1f0a9b8e7d4c2b9a1f0e3d2c1b0a9f",
"seq": 1,
"phase": 1,
"chunkOrder": 3,
"progress": 40,
"count": 2,
"expiresAt": "2026-10-11T03:00:00.000Z",
"messages": [
{
"contact": "5493511234567",
"direction": "in",
"message": {
"id": "wamid.HBgL…",
"from": "5493511234567",
"timestamp": "1739230970",
"type": "text",
"text": {
"body": "¿Tienen turno el lunes?"
},
"history_context": {
"status": "READ"
}
}
},
{
"contact": "5493511234567",
"direction": "out",
"message": {
"id": "wamid.HBgM…",
"from": "5493510000000",
"timestamp": "1739231001",
"type": "text",
"text": {
"body": "Sí, a las 10."
},
"history_context": {
"status": "DELIVERED"
}
}
}
]
}history.completed — data
{
"batches": 12,
"delivered": 5480,
"deliveredByWebhook": 5480,
"deliveredByApi": 0,
"expired": 0,
"dropped": 0
}history.dropped — data
{
"reason": "storage_limit",
"messages": 500
}template.status_changed — data
{
"template": {
"name": "turno_confirmado",
"language": "es_AR"
},
"event": "message_template_status_update",
"status": "APPROVED",
"category": "UTILITY",
"qualityScore": null,
"reason": null,
"rejection": null
}template.draft_submitted — data
{
"draft": {
"id": "tpl_…",
"name": "promo_octubre",
"language": "es_AR",
"suggestedCategory": "MARKETING"
},
"proposedVia": {
"linkId": "onb_…",
"label": "Farmacia Centro"
},
"clientNotes": null,
"precheck": {
"warnings": []
}
}account.trial_warning — data
{
"days": 3,
"trialEndsAt": "2026-09-13T00:00:00.000Z"
}account.trial_expired — data
{
"trialEndsAt": "2026-09-13T00:00:00.000Z"
}subscription.activated — data
{
"planCode": "growth",
"periodEnd": "2026-09-13T00:00:00.000Z"
}subscription.cancelled — data
{
"accessUntil": "2026-09-13T00:00:00.000Z"
}billing.payment_failed — data
{
"paymentId": "123456789",
"amount": 59000,
"currency": "ARS"
}billing.payment_recovered — data
{
"planCode": "growth",
"paymentId": "123456789"
}billing.amount_updated — data
{
"totalArs": 52500,
"baseArs": 52500,
"overageArs": 0,
"overageMessages": 0
}webhook.test — data
{
"type": "test",
"test": true,
"message": "WAIA Connect test event — your endpoint is reachable and verifying signatures. This is NOT real traffic."
}