Passa al contenuto principale

UC-008 — Tracking della Consegna con Webhooks

CampoValore
IDUC-008
ObiettivoRegistrare un webhook, ricevere callback di delivery/read/inbound e gestire il ciclo di vita
CanaleTutti (SMS, RCS, WhatsApp)
Complessità⭐⭐ Intermedio
Tempo stimato20 minuti
API coinvoltePOST /api/partner-gateway/v1/webhooks/delivery-status, GET /webhooks/delivery-status, PUT /webhooks/delivery-status, DELETE /webhooks/delivery-status

Scenari reali

  • LogisticaExpress — Dashboard real-time: Il pannello operativo mostra in tempo reale lo stato di migliaia di notifiche di spedizione. Ogni webhook aggiorna il contatore di consegnati/falliti.
  • AssicuraPlus — SLA monitoring: Il sistema misura il tempo tra invio e consegna per ogni canale, generando alert se il tempo supera la soglia contrattuale di 60 secondi.
  • FarmaOnline — Audit log: Ogni evento di delivery, lettura e risposta viene registrato nel database per compliance normativa e analisi post-campagna.

Flusso webhook

Il diagramma illustra il ciclo completo: registri il webhook, invii un messaggio, il carrier consegna, e la tua app riceve la notifica in tempo reale.

Step 1 — Registra il webhook

Registra il tuo endpoint HTTPS per ricevere le notifiche di delivery.

curl -X POST https://lora-api.agiletelecom.com/api/partner-gateway/v1/webhooks/delivery-status \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"callbackUrl": "https://api.logisticaexpress.it/webhooks/delivery"
}'

Response — Webhook registrato

{
"id": "wh-7f8a9b0c",
"callbackUrl": "https://api.logisticaexpress.it/webhooks/delivery",
"status": "ACTIVE",
"createdAt": "2026-04-09T09:00:00Z"
}

:::info Un solo webhook attivo E consentito un solo webhook di delivery-status per account. Crearne uno nuovo sostituisce automaticamente la configurazione precedente. :::

Verifica la configurazione attuale

curl -X GET https://lora-api.agiletelecom.com/api/partner-gateway/v1/webhooks/delivery-status \
-H "X-Api-Key: YOUR_API_KEY"
{
"id": "wh-7f8a9b0c",
"callbackUrl": "https://api.logisticaexpress.it/webhooks/delivery",
"status": "ACTIVE",
"createdAt": "2026-04-09T09:00:00Z"
}

Step 2 — Invia un messaggio di test

Invia un messaggio con simulation: true per testare il flusso senza costi reali.

curl -X POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42
},
"placeholders": {
"nome": "Giulia"
},
"enableNotification": true,
"simulation": true,
"messageId": "test-webhook-001"
}'

Response — Messaggio di test accettato

{
"messageId": "test-webhook-001",
"simulation": true,
"results": {
"whatsapp": {
"accepted": true
},
"rcs": null,
"sms": null
}
}

:::tip Test locale con ngrok Per testare i webhook in locale, usa ngrok per esporre il tuo server: ngrok http 3000. Registra la URL HTTPS generata come callback. :::

Step 3 — Ricevi le callback

Il sistema invia POST request al tuo callbackUrl per ogni cambio di stato. Ecco i payload per i tre principali tipi di evento.

Payload DELIVERY

Notifica di consegna (o mancata consegna) del messaggio:

{
"eventType": "DELIVERY",
"messageId": "test-webhook-001",
"customerMessageId": "test-webhook-001",
"destination": "+393401234567",
"statusCode": 3,
"description": "Message delivered",
"channel": "WHATSAPP",
"timestamp": "2026-04-09T10:30:00Z"
}

Payload READ (solo WhatsApp/RCS)

Notifica di lettura — il destinatario ha aperto il messaggio:

{
"eventType": "READ",
"messageId": "test-webhook-001",
"destination": "+393401234567",
"channel": "WHATSAPP",
"timestamp": "2026-04-09T10:31:15Z"
}

Payload INBOUND

Il destinatario ha risposto al messaggio:

{
"eventType": "INBOUND",
"source": "+393401234567",
"destination": "+393209998877",
"text": "Si, confermo l'appuntamento di giovedi alle 15:30",
"channel": "WHATSAPP",
"messageType": "TEXT",
"timestamp": "2026-04-09T10:32:00Z"
}

Codici di stato

statusCodeSignificato
3Consegnato
6Non recapitabile
8Scaduto

Step 4 — Aggiorna il webhook

Modifica la URL di callback senza eliminare e ricreare la configurazione.

curl -X PUT https://lora-api.agiletelecom.com/api/partner-gateway/v1/webhooks/delivery-status \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"callbackUrl": "https://api.logisticaexpress.it/webhooks/v2/delivery"
}'

Response — Webhook aggiornato

{
"id": "wh-7f8a9b0c",
"callbackUrl": "https://api.logisticaexpress.it/webhooks/v2/delivery",
"status": "ACTIVE",
"updatedAt": "2026-04-09T11:00:00Z"
}

Step 5 — Revoca il webhook

Quando non hai più bisogno delle notifiche in tempo reale, elimina la configurazione.

curl -X DELETE https://lora-api.agiletelecom.com/api/partner-gateway/v1/webhooks/delivery-status \
-H "X-Api-Key: YOUR_API_KEY"

Response — Webhook eliminato

{
"deleted": true
}

Dopo la revoca, le notifiche di delivery non verranno più inviate. Potrai comunque consultare lo stato dei messaggi tramite polling.

Esempio — Webhook handler Node.js

webhook-handler.js
const express = require('express');
const app = express();
app.use(express.json());

app.post('/webhooks/delivery', (req, res) => {
const { eventType, messageId, statusCode, channel, destination } = req.body;

switch (eventType) {
case 'DELIVERY':
if (statusCode === 3) {
console.log(`[DELIVERED] ${messageId} via ${channel} a ${destination}`);
// Aggiorna il database: segna il messaggio come consegnato
// db.messages.update(messageId, { status: 'delivered', channel });
} else if (statusCode === 6) {
console.log(`[FAILED] ${messageId} via ${channel} a ${destination}`);
// Gestisci il fallimento: riprova o notifica l'operatore
// alertService.notify(`Messaggio ${messageId} non recapitabile`);
} else if (statusCode === 8) {
console.log(`[EXPIRED] ${messageId} via ${channel}`);
// Il messaggio e scaduto prima della consegna
}
break;

case 'READ':
console.log(`[READ] ${messageId} letto dal destinatario`);
// db.messages.update(messageId, { readAt: req.body.timestamp });
break;

case 'INBOUND':
console.log(`[INBOUND] Da ${req.body.source}: ${req.body.text}`);
// Processa la risposta: auto-reply, inoltra al CRM, ecc.
// crmService.createTicket(req.body.source, req.body.text);
break;

default:
console.log(`[UNKNOWN] Evento non gestito: ${eventType}`);
}

// Rispondi sempre velocemente - elabora in modo asincrono se necessario
res.sendStatus(200);
});

app.listen(3000, () => {
console.log('Webhook handler in ascolto sulla porta 3000');
});

Polling vs Webhook

AspettoPollingWebhook
LatenzaDipende dalla frequenza di pollingQuasi real-time
ComplessitàSemplice (solo richieste GET)Richiede endpoint HTTPS pubblico
ScalabilitaAumenta le chiamate API a volume altoPush-based, nessuna chiamata extra
Costi APIOgni poll consuma una chiamataNessun consumo aggiuntivo
AffidabilitaNessun rischio di perdita eventiRichiede gestione retry e idempotenza
Ideale perBasso volume, controlli ad-hocAlto volume, dashboard real-time
Dietro le quinte — Meccanismo di delivery dei webhook

Il sistema di webhook funziona con un modello at-least-once delivery:

  1. Registrazione: Quando registri un webhook, il sistema verifica che la URL sia raggiungibile con un test ping. Se il ping fallisce, la registrazione viene comunque accettata ma riceverai un warning.
  2. Dispatch: Ad ogni cambio di stato del messaggio (accettato, consegnato, letto, fallito), il sistema accoda un evento per il tuo webhook.
  3. Retry: Se la tua callback URL risponde con un codice diverso da 2xx, il sistema ritenta fino a 5 volte con backoff esponenziale (1s, 5s, 30s, 2min, 10min).
  4. Circuit breaker: Se il tuo endpoint fallisce per oltre 50 chiamate consecutive, il webhook viene temporaneamente disattivato e riattivato dopo 30 minuti.
  5. Ordinamento: Gli eventi sono inviati in ordine cronologico per singolo messaggio, ma eventi di messaggi diversi possono arrivare in ordine sparso.

Best practices

  1. Usa HTTPS — La callback URL deve usare HTTPS per la sicurezza dei dati in transito.
  2. Rispondi rapidamente — Restituisci 200 OK entro pochi secondi. Elabora il payload in modo asincrono se serve.
  3. Gestisci i retry — Il sistema ritenta in caso di errore. Rendi l'elaborazione idempotente usando il messageId come chiave.
  4. Valida la sorgente — Verifica che le richieste webhook provengano effettivamente da Qlara Platform API.
  5. Monitora i fallimenti — Se il tuo endpoint fallisce costantemente, il circuit breaker lo disattivera temporaneamente.

Risultato atteso

StepAzioneRisultato
1POST /webhooks/delivery-statusWebhook registrato con stato ACTIVE
2POST /whatsapp/send con simulation: trueMessaggio di test accettato
3Callback ricevutaPayload DELIVERY, READ o INBOUND
4PUT /webhooks/delivery-statusURL di callback aggiornata
5DELETE /webhooks/delivery-statusWebhook revocato, notifiche interrotte

Prossimi passi