Webhook e Notifiche di Consegna
Ci sono due modi per tracciare la consegna dei messaggi: polling e webhook. Scegli l'approccio più adatto al tuo caso d'uso.
Polling
Interroga lo stato di consegna su richiesta:
GET /messages/status/{customerMessageId}?channel=SMS
channel è obbligatorio: SMS, RCS o WHATSAPP. Oppure controlla più messaggi dello stesso canale contemporaneamente:
GET /messages/status?channel=SMS&ids=id1,id2,id3
Entrambe restituiscono il deliveryStatus del messaggio (DELIVERED, UNDELIVERABLE, EXPIRED, ...): la tabella Delivery Statuses elenca tutti i valori.
Quando usare il polling:
- Volume di messaggi ridotto
- Controlli di stato occasionali
- Integrazioni semplici che non necessitano di un endpoint pubblico
Webhook
Registra un URL di callback HTTPS per ricevere aggiornamenti sullo stato di consegna in tempo reale, non appena il carrier li segnala.
Configura un webhook
POST /webhooks/delivery-status
Fornisci il tuo URL di callback come {"callbackUrl": "https://..."}. Lo stesso URL riceve gli eventi di SMS, RCS e WhatsApp. L'API invierà richieste HTTP POST a questo URL quando arriva una ricevuta di consegna, quando un destinatario legge un messaggio RCS o WhatsApp e quando un utente finale ti scrive.
Gestisci il tuo webhook
| Azione | Endpoint | Risposta |
|---|---|---|
| Ottieni webhook attuale | GET /webhooks/delivery-status | 200 con companyId e callbackUrl, 404 se assente |
| Crea webhook | POST /webhooks/delivery-status | 201 con companyId e callbackUrl, 409 se ne esiste già uno |
| Aggiorna URL webhook | PUT /webhooks/delivery-status | 200 con companyId e callbackUrl, 404 se assente |
| Revoca webhook | DELETE /webhooks/delivery-status | 204 senza corpo, 404 se assente |
È consentito un solo webhook di stato consegna attivo per account. Se ne esiste già uno, la POST risponde 409 Conflict e lo lascia invariato: cambia l'URL con PUT, oppure elimina prima il webhook con DELETE.
Payload del webhook
Quando arriva una ricevuta di consegna, l'API invia una richiesta POST al tuo URL di callback. Il corpo è JSON (Content-Type: application/json) e i campi senza valore vengono omessi.
Esempio di notifica di consegna (SMS):
{
"eventType": "DELIVERY",
"channel": "SMS",
"messageId": "order-12345",
"destination": "+393401234567",
"statusCode": 3,
"description": "delivered",
"eventDate": "2026-04-09T11:30:05+02:00",
"price": 0.035,
"totalParts": 1,
"numPart": 1
}
messageId è l'id del messaggio che hai inviato, lo stesso valore che l'API di polling chiama customerMessageId. Un SMS produce un evento per ogni parte (numPart di totalParts). Gli eventi DELIVERY di RCS e WhatsApp hanno gli stessi campi, senza totalParts e numPart.
Esempio di notifica di lettura (solo WhatsApp/RCS):
{
"eventType": "READ",
"channel": "WHATSAPP",
"messageId": "e76614d1-4ac1-4d94-89f0-d07f1b5a190c",
"destination": "+393401234567",
"eventDate": "2026-04-09T11:31:15+02:00"
}
Un evento READ non ha statusCode: un messaggio letto resta DELIVERED.
Esempio di messaggio in arrivo (solo WhatsApp/RCS):
{
"eventType": "INBOUND",
"channel": "WHATSAPP",
"messageId": "b7e2c9a4-3f1d-4c6e-8a5b-0d9f2e7c4a18",
"source": "+393401234567",
"destination": "+393409876543",
"receivedDate": "2026-04-09T11:35:00+02:00",
"messageType": "TEXT",
"text": "Sì, confermo l'appuntamento"
}
source è il numero dell'utente finale e destination il tuo numero WhatsApp (su RCS, l'id del tuo agente). messageId identifica il messaggio in arrivo nella conversazione. I messaggi multimediali includono anche un mediaKey.
Lo statusCode di un evento DELIVERY, con la sua description:
| Codice di stato | Descrizione | Canali | Significato |
|---|---|---|---|
| 1 | accepted | SMS | Consegnato al carrier, nessuna ricevuta ancora. Mai inviato come evento. |
| 2 | rejected | SMS | Il carrier ha rifiutato il messaggio. |
| 3 | delivered | SMS, RCS, WhatsApp | Il messaggio ha raggiunto il telefono. |
| 4 | expired | SMS, RCS, WhatsApp | Non consegnato entro il periodo di validità. |
| 5 | deleted | SMS | Annullato prima della consegna. |
| 6 | undeliverable | SMS | La destinazione non può riceverlo (numero irraggiungibile o non valido). |
| 9 | general error | RCS, WhatsApp | Consegna fallita. |
| 10 | disabled | RCS, WhatsApp | Il destinatario ha il canale disattivato. |
| 11 | unsupported | RCS, WhatsApp | Il dispositivo o il numero non supporta il canale. |
| 12 | conversation closed | La finestra di assistenza di 24 ore era chiusa. | |
| 0 | unknown | SMS, RCS, WhatsApp | Nessuno stato disponibile per il messaggio. Mai inviato come evento. |
Un evento viene inviato solo quando arriva la ricevuta, quindi ogni codice che ricevi è definitivo. Un messaggio ancora in transito risulta ACCEPTED su SMS e UNKNOWN su RCS e WhatsApp quando lo interroghi in polling, e non produce eventi. I codici corrispondono ai valori di deliveryStatus dell'API di polling: vedi Delivery Statuses.
simulation: true valida una richiesta di invio senza inviare il messaggio, quindi non produce alcuna callback webhook. Per testare il tuo handler dall'inizio alla fine, invia un messaggio reale a un numero di tua proprietà.
Best practice
- Usa HTTPS su un host pubblico -- L'URL di callback viene validato al momento della registrazione. Deve usare
httpssulla porta 443 (quella predefinita) o 8443, non deve contenere credenziali né frammenti#, e il suo host deve risolvere solo a indirizzi pubblicamente raggiungibili. Indirizzi di loopback, privati, link-local, carrier-grade-NAT e unique-local vengono rifiutati, così come gli host che non risolvono. Un URL che non supera uno di questi controlli viene rifiutato con400. - Rispondi velocemente -- Rispondi con un qualsiasi
2xxentro 5 secondi (3 secondi per la connessione). Elabora il payload in modo asincrono se necessario. - Gestisci i retry -- Se il tuo endpoint non è raggiungibile o non risponde
2xx, il sistema ritenta: al massimo 5 tentativi in tutto, a distanza di almeno 5 minuti per gli SMS e di almeno 10 minuti per RCS e WhatsApp, e solo per i messaggi inviati negli ultimi 10 giorni. Gli eventi possono arrivare più di una volta e in ordine sparso, quindi rendi la tua elaborazione idempotente, usando come chiaveeventType+messageId(+numPartper gli SMS). - Valida il payload -- Le callback non hanno un header di firma. Tratta il corpo come input non fidato e verifica che il
messageIddi un evento DELIVERY o READ appartenga a un messaggio che hai inviato. - Monitora i fallimenti -- Se il tuo endpoint webhook fallisce costantemente, controlla i log del server e assicurati che l'URL sia accessibile. Gli eventi che esauriscono i tentativi non vengono più inviati: recupera quegli stati in polling.
Scegliere tra polling e webhook
| Aspetto | Polling | Webhook |
|---|---|---|
| Latenza | Dipende dalla frequenza di polling | Quasi in tempo reale |
| Complessità | Semplici richieste GET | Richiede un endpoint HTTPS pubblico |
| Scalabilità | Aumenta le chiamate API a scala | Push-based, nessuna chiamata API extra |
| Ideale per | Volume ridotto, controlli occasionali | Volume elevato, dashboard in tempo reale |
Consulta il Riferimento API Webhook e il Riferimento API Stato Consegna Messaggi per la documentazione completa degli endpoint.