Eventi WhatsApp
Bird registra eventi per i messaggi WhatsApp in entrata e in uscita. Una timeline in uscita mostra cosa è successo dopo che un invio ha restituito 202: accettazione, passaggio a WhatsApp, consegna, lettura o errore. Una timeline in entrata registra quando Bird ha ricevuto il messaggio.
L'envelope dell'evento
Gli eventi di consegna, messaggio in entrata e reazione WhatsApp usano l'envelope webhook standard: un type, un timestamp e un oggetto data specifico per tipo.
Esempio di codice
{
"data": {
"direction": "outbound",
"from": { "phone_number": "+13124495569" },
"metadata": { "session_id": "sess_4821" },
"tags": [{ "name": "flow", "value": "login-otp" }],
"to": { "phone_number": "+14155550100" },
"whatsapp_id": "wam_01ky7qbvswf3fvyaw3az90391c",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b"
},
"timestamp": "2026-07-23T14:51:39.913Z",
"type": "whatsapp.delivered"
}Ogni payload webhook WhatsApp pubblico per un messaggio contiene whatsapp_id, workspace_id, direction, from, to, tags e metadata. whatsapp.reacted è l'eccezione, perché una reazione è un'annotazione su un messaggio e non un messaggio a sé stante; la sezione Reazioni qui sotto ne descrive la struttura. Un indirizzo può includere un phone_number E.164, un ID utente Meta con scope business in bsuid, o entrambi. Un messaggio ricevuto da un utente WhatsApp contiene anche il profilo che pubblica, in username e display_name. tags e metadata sono null quando l'invio non ne conteneva. Un messaggio inviato in risposta contiene anche in_reply_to_message_id su ogni evento in uscita nella sua timeline, da whatsapp.accepted fino a whatsapp.read, whatsapp.failed o whatsapp.rejected, indicando il messaggio a cui risponde.
L'API degli eventi restituisce record di timeline più snelli con un id, type e un timestamp occurred_at. L'ID del messaggio è già nell'URL della richiesta.
Eventi del ciclo di vita
Gli eventi appaiono in ordine cronologico. Un messaggio in uscita può fermarsi a whatsapp.failed o whatsapp.rejected, e il suo evento whatsapp.read compare solo se il destinatario apre il messaggio. Una timeline in entrata inizia con whatsapp.received e può registrare whatsapp.read dopo che il tuo spazio di lavoro segna il messaggio come letto.
| Evento | Significato |
|---|---|
| whatsapp.accepted | Bird ha accettato la richiesta di invio. È ciò che l'202 ha riportato. |
| whatsapp.sent | Bird ha passato il messaggio alla rete WhatsApp. |
| whatsapp.delivered | WhatsApp ha confermato la consegna al dispositivo del destinatario. |
| whatsapp.read | Il destinatario ha aperto il messaggio. |
| whatsapp.failed | Il messaggio non è stato consegnato. error.code indica cosa lo ha bloccato. |
| whatsapp.rejected | Bird ha rifiutato il messaggio prima di inviarlo. Non è stato addebitato. |
| whatsapp.received | Bird ha ricevuto un messaggio in entrata da un contatto. |
I callback delivered o read applicabili possono attivare la quota Meta del prezzo. I payload degli eventi WhatsApp non contengono informazioni sui costi. Rileggi il messaggio con GET /v1/whatsapp/messages/{message_id} per vedere quanto è costato. Vedi Costi e fatturazione.
Segnare un messaggio in entrata come letto registra whatsapp.read nella sua timeline, ma non emette un webhook di conferma di lettura. Il messaggio in entrata mantiene il suo stato received e registra read_at dopo che WhatsApp accetta la conferma.
whatsapp.read non cambia il status del messaggio. Un messaggio consegnato resta delivered; il messaggio registra anche la lettura in read_at.
whatsapp.delivered può essere saltato del tutto. Quando il destinatario ha già la chat aperta sul proprio dispositivo, Meta segnala la lettura senza mai segnalare una consegna, quindi la timeline si presenta come whatsapp.accepted → whatsapp.sent → whatsapp.read senza whatsapp.delivered in mezzo. Considera read come prova di consegna: un consumer che aspetta delivered prima di considerare il messaggio arrivato si bloccherà proprio sui destinatari che lo hanno visto più in fretta, e uno che calcola il tasso di consegna solo da delivered lo sottostima. Il status del messaggio resta sent in questo caso, perché solo una ricevuta di consegna lo fa avanzare.
Un callback di sola lettura può comunque attivare la tariffa Meta applicabile. Bird usa un'unica identità tariffaria tra i percorsi di consegna e lettura; l'evento di consegna mancante non implica un componente Meta gratuito. Vedi Costi e fatturazione.
La lista dei tipi di evento è aperta: nuovi tipi possono essere aggiunti nel tempo, quindi tratta un valore non riconosciuto come un evento futuro anziché come un errore.
Eventi di fallimento
whatsapp.failed e whatsapp.rejected sono terminali. Un rifiuto significa che Bird ha bloccato il messaggio prima di inviarlo a WhatsApp, quindi non è stato addebitato. Le cause includono un destinatario soppresso o che ha negato il consenso, saldo del wallet insufficiente o una destinazione senza prezzo configurato. Un fallimento significa che il messaggio non è stato consegnato, e error.code indica chi lo ha deciso. La maggior parte dei codici riporta il verdetto di WhatsApp, mappato dal codice che ha segnalato. internal_error è l'eccezione: registra l'assenza di una credenziale del mittente utilizzabile oppure tentativi di elaborazione esauriti. Un tentativo di trasporto incerto non dimostra che Meta non abbia mai ricevuto la richiesta. meta_error_code contiene il codice di WhatsApp quando disponibile, e un fallimento internal_error non ne ha per costruzione.
Entrambi gli eventi contengono un oggetto error con un Bird code stabile, un description leggibile, un meta_error_code opzionale e occurred_at. L'oggetto compare nei record API e nei payload webhook solo per questi tipi di evento.
Eventi di reazione
Una reazione emoji annota un messaggio esistente. Non crea un messaggio whatsapp.received. Bird emette whatsapp.reacted quando un contatto aggiunge, modifica o rimuove una reazione, come descritto in Reazioni. Le reazioni inviate dal tuo numero aziendale non emettono quel webhook. Vedi Inviare reazioni per aggiungere, sostituire o rimuovere la tua reazione, e Ricevere reazioni per esempi di webhook e REST API. Le reazioni dei contatti non aprono una finestra di assistenza clienti.
Il log delle reazioni del messaggio a cui si è reagito registra le modifiche sia del contatto che del tuo numero aziendale: aggiunte, sostituzioni e rimozioni.
Un caso non viene registrato da nessuna parte. Bird associa una reazione al suo messaggio tramite un ID provider che conserva per 15 giorni, mentre WhatsApp accetta una reazione su un messaggio fino a 30 giorni di età, quindi una reazione posta su un messaggio più vecchio non può essere associata e non raggiunge né il log né reactions. Un messaggio senza voci non è quindi prova che nessuno vi abbia reagito.
Leggi quel log con GET /v1/whatsapp/messages/{message_id}/reaction-events, dal più recente. Ogni voce indica l'emoji, chi ha effettuato la modifica e un status tra received, sent, failed o rejected; una voce failed o rejected riporta il motivo in error. Ogni voce ha un ID reazione (war_…) e un timestamp occurred_at. Una rimozione ha emoji: null. Le modifiche in sospeso non hanno voce finché il loro esito non è noto. Una reazione non viene mai addebitata, quindi nessun fallimento in questo ambito è di fatturazione. Per sapere cosa è attualmente sul messaggio anziché la cronologia delle modifiche, leggi il suo reactions con GET /v1/whatsapp/messages/{message_id}, che riduce il log a una voce per mittente.
Eventi di soppressione
Oltre al ciclo di vita per messaggio, un evento segnala una modifica alla lista di soppressione dello spazio di lavoro: whatsapp_suppression.created si attiva quando si apre una soppressione. Il payload contiene il suppression_id, il address soppresso in formato E.164, il waba a cui il blocco è limitato (null quando copre l'intero spazio di lavoro, indipendentemente dall'account che invia), il reason e il workspace_id, così il vostro sistema può rilevare nuovi blocchi senza polling. Solo le aperture generano un evento: la chiusura di una soppressione non lo fa ancora, quindi rileggete la lista prima di considerare ancora attivo un blocco replicato:
Esempio di codice
{
"type": "whatsapp_suppression.created",
"timestamp": "2026-08-25T14:52:03.192524705Z",
"data": {
"suppression_id": "was_01krdgeqcxet5s7t44vh8rt9mg",
"address": "+14155550100",
"waba": null,
"reason": "manual",
"workspace_id": "ws_01ky7m21hjffh9s8kq76gyb1xf"
}
}Un opt-out dichiarato dal destinatario stesso è una preferenza anziché una soppressione, e attiva preference.revoked al suo posto.
Leggere gli eventi dalla API
GET /v1/whatsapp/messages/{message_id}/events restituisce la timeline in ordine cronologico. La lista limitata non è paginata. Leggere gli eventi richiede una chiave API con whatsapp:read:
const { data } = await bird.whatsapp.listEvents("wa_abc123");
for (const event of data) console.log(event.type, event.occurred_at);events = client.whatsapp.list_events("wa_abc123")
for event in events.data:
print(event.type, event.occurred_at)events, err := client.Whatsapp.ListEvents(context.Background(), "wam_01krdgeqcxet5s7t44vh8rt9mg", bird.WhatsappListEventsParams{})
if err != nil {
log.Fatal(err)
}
for _, e := range events.Data {
fmt.Println(e.Id, e.Type)
}$events = $bird->whatsapp->listEvents('wamid_01krdgeqcxet5s7t44vh8rt9mg');
foreach ($events->getData() ?? [] as $event) {
echo $event->getType(), ' ', $event->getId(), "\n";
}bird whatsapp list-events <message-id>curl https://us1.platform.bird.com/v1/whatsapp/messages/wam_.../events \
-H "Authorization: Bearer $BIRD_API_KEY"Un messaggio accettato, inviato, consegnato e letto restituisce quattro eventi:
Esempio di codice
{
"data": [
{
"id": "ev_01ky7q6a1fejfbvs0myn41hj41",
"occurred_at": "2026-07-23T14:48:34.71Z",
"type": "whatsapp.accepted"
},
{
"id": "ev_01ky7q6a2denvtd6jg1vqwmg13",
"occurred_at": "2026-07-23T14:48:35.671Z",
"type": "whatsapp.sent"
},
{
"id": "ev_01ky7q6a2zff9r2qm74mmg1g6z",
"occurred_at": "2026-07-23T14:48:36.642Z",
"type": "whatsapp.delivered"
},
{
"id": "ev_01ky7q6c21frssf0vj8h50qysw",
"occurred_at": "2026-07-23T14:48:38.65Z",
"type": "whatsapp.read"
}
]
}Passa type per ottenere un singolo tipo di evento pubblico, ad esempio ?type=whatsapp.failed o ?type=whatsapp.read. Omettilo per la timeline completa.
La stessa timeline è ciò che la pagina log WhatsApp mostra quando apri un messaggio.

Webhook
Iscriviti a whatsapp.accepted, whatsapp.sent, whatsapp.delivered, whatsapp.read, whatsapp.failed, whatsapp.rejected, whatsapp.received e whatsapp.reacted dalla pagina Webhooks o dalle API dei webhook. La guida ai webhook copre endpoint, firme e ripetizioni dei tentativi.
whatsapp.received include il contenuto del messaggio oltre all'envelope descritto sopra, così un endpoint può agire su un messaggio in entrata senza rileggerlo. Un tap su un messaggio interattivo arriva come interactive_reply, e in_reply_to_message_id indica il messaggio a cui risponde:
Esempio di codice
{
"data": {
"direction": "inbound",
"from": {
"display_name": "Alex Rivera",
"phone_number": "+14155550100",
"username": "alexr"
},
"in_reply_to_message_id": "wam_01ky7qbvswf3fvyaw3az90391c",
"interactive_reply": {
"list": {
"description": "Next day to 2 days",
"slug": "priority_express",
"text": "Priority Mail Express"
},
"type": "list"
},
"metadata": null,
"tags": null,
"to": { "phone_number": "+13124495569" },
"whatsapp_id": "wam_01ky8b3xq4gd7pmzn2ka51f7te",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b"
},
"timestamp": "2026-07-23T14:52:04.118Z",
"type": "whatsapp.received"
}Le altre diramazioni di contenuto seguono la stessa struttura a scelta singola: text, image, video, audio, sticker, document, location, contact_cards e unsupported per un tipo che API non modella. GET /v1/whatsapp/messages/{message_id} documenta ciascuna.
Reazioni
whatsapp.reacted si attiva quando un utente WhatsApp reagisce a uno dei tuoi messaggi. È l'unico evento WhatsApp che non fa parte della timeline di consegna di un messaggio: non compare in GET /v1/whatsapp/messages/{message_id}/events, e non c'è nulla per filtrarlo lì.
whatsapp_id indica il messaggio a cui si è reagito, non la reazione, e emoji è la modifica effettuata dall'utente. Un utente che reagisce, cambia emoji e poi ritira la reazione produce tre eventi su quel singolo messaggio. WhatsApp non invia una rimozione tra i primi due, quindi una modifica arriva come un singolo evento con la nuova emoji.
Esempio di codice
{
"data": {
"emoji": "👍",
"from": { "phone_number": "+14155550100" },
"to": { "phone_number": "+13124495569" },
"whatsapp_id": "wam_01ky8b3xq4gd7pmzn2ka51f7te",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b"
},
"timestamp": "2026-07-23T14:52:11.000Z",
"type": "whatsapp.reacted"
}WhatsApp riporta l'ora della reazione al secondo, quindi due di quei tre eventi possono condividere lo stesso timestamp. Ordinarli per quel valore non li ordinerà, e nemmeno l'ordine di consegna, che i tentativi ripetuti rendono inaffidabile. Agisci sulla reazione che ogni evento porta, come la modifica che descrive. Non ricostruire la sequenza dagli eventi né trattare l'ultimo arrivato come la reazione corrente sul messaggio, perché né i timestamp né l'ordine di arrivo lo supportano. Rileggi il messaggio per le reazioni attuali: GET /v1/whatsapp/messages/{message_id} restituisce una voce per mittente in reactions, e il log delle reazioni del messaggio contiene ogni modifica.
emoji è presente e null quando l'utente ha ritirato la propria reazione, quindi un null è la rimozione stessa e non un valore mancante. L'emoji viene consegnata esattamente come WhatsApp l'ha inviata e non è normalizzata, quindi ❤ e ❤️ ti arrivano come stringhe diverse.
Passi successivi
- Ricevere reazioni: gestire i webhook di reazione dei contatti e leggere le reazioni attuali
- Inviare reazioni: aggiungere, sostituire o rimuovere la tua reazione
- Segnare il messaggio come letto: confermare un messaggio in entrata e mostrare la digitazione
- Log WhatsApp: la vista per messaggio che mostra questa timeline
- Inviare messaggi WhatsApp: dove inizia il ciclo di vita di un messaggio
- Guida ai webhook: endpoint, firme, ripetizioni dei tentativi e catalogo completo degli eventi
Risorse correlate
Prosegui con la documentazione, le guide e gli esempi per questo argomento. Le risorse sono in inglese.
Guarda la guidaConnecting WhatsApp to Bird: from buying a number to a live channelComprendi il concettoWhat is the 24-hour customer service window on WhatsApp?Usa lo strumentoWhatsApp message builderEsplora la funzionalitàWhatsApp
Prova l'esercitazione e ottieni un brief di implementazione