Passa al contenuto principale

UC-004 — Verifica Stato di Consegna

CampoValore
IDUC-004
ObiettivoVerificare lo stato di consegna dei messaggi con polling e webhook
CanaleMulti-canale (SMS, RCS, WhatsApp)
ComplessitàBase
Tempo stimato15 minuti
API coinvolteGET /api/partner-gateway/v1/messages/status/{customerMessageId}, GET /api/partner-gateway/v1/messages/status

Scenari reali​

  • Dashboard OTP — Verifica invii: BancaSicura monitora in tempo reale se i codici OTP vengono consegnati entro 5 secondi, attivando un canale alternativo in caso di fallimento.
  • Report consegna campagna: MarketingPro genera un report di fine campagna SMS con percentuali di consegna, errori e tempi medi.
  • Monitoring real-time: TechStore integra lo status check nel proprio CRM per mostrare un badge "Consegnato" o "In attesa" accanto a ogni comunicazione inviata.

Polling vs Webhook​

CaratteristicaPollingWebhook
DirezioneIl tuo server chiama l'APIL'API chiama il tuo server
LatenzaDipende dall'intervallo di pollingTempo reale
Carico APIProporzionale al numero di chiamateUna chiamata per evento
ComplessitàBassa (basta un loop)Media (serve endpoint pubblico)
Ideale perVerifiche puntuali, debug, piccoli volumiProduzione, alti volumi, real-time
Quale scegliere?

Usa il polling per test, debug e verifiche manuali. Usa i webhook in produzione per ricevere notifiche in tempo reale senza sovraccaricare l'API. Vedi la guida Webhook per la configurazione.

Step 1 — Invia un messaggio (prerequisito)​

Per verificare lo stato, devi prima aver inviato un messaggio e aver salvato il messageId. Esempio rapido con SMS:

curl -s -X POST https://api.qlara.ai/api/message-server/sms/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393471234567",
"sender": "BancaSicura",
"body": "Il tuo codice OTP e: 847293. Valido per 5 minuti.",
"enableNotification": true
}'

Response​

{
"messageId": "d1e2f3a4-b5c6-7890-d1e2-f3a4b5c67890",
"simulation": false,
"results": {
"sms": {
"accepted": true,
"unicode": false,
"parts": 1,
"reasons": []
}
}
}
Dietro le quinte — Timeline degli stati

Dopo l'invio, il messaggio attraversa questi stati in sequenza:

  1. In transito — Il gateway ha accettato il messaggio e lo ha inoltrato, ma non è ancora tornata alcuna ricevuta. Lo stato è ACCEPTED su SMS e UNKNOWN su RCS e WhatsApp, che non hanno uno stato intermedio proprio.
  2. Stato finale — Arriva la ricevuta dell'operatore o della piattaforma e lo stato non cambia più:
    • SMS: DELIVERED, oppure un fallimento: REJECTED, UNDELIVERABLE, EXPIRED (non consegnato entro la finestra di validità) o DELETED.
    • RCS: DELIVERED, oppure un fallimento: ERROR, DISABLED, UNSUPPORTED o EXPIRED.
    • WhatsApp: come RCS, più CONVERSATION_CLOSED.
  3. Lettura (solo RCS/WhatsApp) — La lettura non è uno stato: il messaggio resta DELIVERED. Su WhatsApp l'ora di lettura viene valorizzata in readDate; su RCS e WhatsApp il webhook invia anche un evento READ.

La transizione da ACCEPTED/UNKNOWN a DELIVERED avviene tipicamente in 1-5 secondi per SMS, 0.5-2 secondi per RCS/WhatsApp.

Step 2 — Polling singolo​

Interroga lo stato di un singolo messaggio usando il messageId come path parameter e il channel come query parameter.

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/messages/status/d1e2f3a4-b5c6-7890-d1e2-f3a4b5c67890?channel=SMS" \
-H "X-Api-Key: YOUR_API_KEY"

Response — DELIVERED​

{
"customerMessageId": "d1e2f3a4-b5c6-7890-d1e2-f3a4b5c67890",
"channel": "SMS",
"destination": "+393471234567",
"deliveryStatus": "DELIVERED",
"deliveryStatusDescription": "delivered",
"sendDate": "2026-04-09T15:00:00+02:00",
"deliveryDate": "2026-04-09T15:00:03+02:00",
"readDate": null
}

Response — UNDELIVERABLE​

{
"customerMessageId": "d1e2f3a4-b5c6-7890-d1e2-f3a4b5c67890",
"channel": "SMS",
"destination": "+393471234567",
"deliveryStatus": "UNDELIVERABLE",
"deliveryStatusDescription": "undeliverable",
"sendDate": "2026-04-09T15:00:00+02:00",
"deliveryDate": null,
"readDate": null
}
Dietro le quinte — Tabella completa degli status
StatusCodice webhookdeliveryStatusDescriptionCanaleDescrizione
ACCEPTED1acceptedSMSAffidato all'operatore, nessuna ricevuta ancora. Non finale
REJECTED2rejectedSMSL'operatore ha rifiutato il messaggio. Finale
DELIVERED3deliveredSMS, RCS, WhatsAppMessaggio consegnato al dispositivo. Finale
EXPIRED4expiredSMS, RCS, WhatsAppNon consegnato entro la finestra di validità. Finale
DELETED5deletedSMSAnnullato prima della consegna. Finale
UNDELIVERABLE6undeliverableSMSLa destinazione non può riceverlo (numero irraggiungibile o non valido). Finale
ERROR9general errorRCS, WhatsAppConsegna fallita. Finale
DISABLED10disabledRCS, WhatsAppIl destinatario ha il canale disattivato. Finale
UNSUPPORTED11unsupportedRCS, WhatsAppIl dispositivo o il numero non supporta il canale. Finale
CONVERSATION_CLOSED12conversation closedWhatsAppLa finestra di assistenza clienti di 24 ore era chiusa. Finale
UNKNOWN0unknownSMS, RCS, WhatsAppNessuno stato registrato per il messaggio. Su RCS e WhatsApp, lo stato normale mentre è in transito

Note sui codici webhook: Il webhook di delivery status invia in statusCode gli stessi codici numerici di questa tabella e in description la descrizione in minuscolo. Nell'API di status polling, il campo deliveryStatus è il nome nella prima colonna. Il webhook parte quando arriva la ricevuta dell'operatore o della piattaforma, quindi non invia mai ACCEPTED (1) né UNKNOWN (0).

Step 3 — Polling batch​

Per verificare lo stato di più messaggi in una sola chiamata, usa l'endpoint batch. Tutti gli ID devono appartenere allo stesso canale.

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/messages/status?channel=SMS&ids=d1e2f3a4-b5c6-7890-d1e2-f3a4b5c67890,a1b2c3d4-e5f6-7890-abcd-ef1234567890,f47ac10b-58cc-4372-a567-0e02b2c3d479" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Batch status​

[
{
"customerMessageId": "d1e2f3a4-b5c6-7890-d1e2-f3a4b5c67890",
"channel": "SMS",
"destination": "+393471234567",
"deliveryStatus": "DELIVERED",
"deliveryStatusDescription": "delivered",
"sendDate": "2026-04-09T15:00:00+02:00",
"deliveryDate": "2026-04-09T15:00:03+02:00",
"readDate": null
},
{
"customerMessageId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel": "SMS",
"destination": "+393481234567",
"deliveryStatus": "DELIVERED",
"deliveryStatusDescription": "delivered",
"sendDate": "2026-04-09T15:00:01+02:00",
"deliveryDate": "2026-04-09T15:00:04+02:00",
"readDate": null
},
{
"customerMessageId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"channel": "SMS",
"destination": "+393491234567",
"deliveryStatus": "UNDELIVERABLE",
"deliveryStatusDescription": "undeliverable",
"sendDate": "2026-04-09T15:00:01+02:00",
"deliveryDate": null,
"readDate": null
}
]
ID non trovati

Gli ID che non corrispondono a nessun messaggio vengono silenziosamente omessi dalla response. Se invii 3 ID e ricevi solo 2 risultati, il terzo non e stato trovato.

Dietro le quinte — Limiti e best practice del batch
  • Limite ID: Puoi inviare fino a diverse centinaia di ID in una singola chiamata. Per volumi superiori, suddividi in più richieste.
  • Stesso canale: Tutti gli ID devono appartenere allo stesso canale (SMS, RCS o WHATSAPP). Per canali misti, esegui chiamate separate.
  • Ordine risultati: I risultati non sono ordinati. Usa customerMessageId per fare il match con i tuoi record.
  • Polling interval: Per verifiche automatiche, usa un intervallo di almeno 5 secondi tra una chiamata e l'altra. Per volumi elevati, passa ai webhook.

Esempio: polling loop con retry​

Uno script bash che verifica lo stato di un SMS ogni 3 secondi, con timeout di 30 secondi. Si ferma su DELIVERED o su un fallimento finale SMS; gli stati di fallimento dipendono dal canale, quindi per RCS usa ERROR|DISABLED|UNSUPPORTED|EXPIRED e per WhatsApp aggiungi CONVERSATION_CLOSED:

#!/bin/bash
MESSAGE_ID="d1e2f3a4-b5c6-7890-d1e2-f3a4b5c67890"
API_KEY="YOUR_API_KEY"
MAX_ATTEMPTS=10
ATTEMPT=0

while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
ATTEMPT=$((ATTEMPT + 1))
echo "Tentativo $ATTEMPT/$MAX_ATTEMPTS..."

STATUS=$(curl -s -X GET \
"https://api.qlara.ai/api/partner-gateway/v1/messages/status/${MESSAGE_ID}?channel=SMS" \
-H "X-Api-Key: ${API_KEY}" | jq -r '.deliveryStatus')

echo "Status: $STATUS"

case "$STATUS" in
DELIVERED)
echo "Messaggio consegnato!"
exit 0
;;
REJECTED|UNDELIVERABLE|EXPIRED|DELETED) # fallimenti finali SMS
echo "Errore di consegna: $STATUS"
exit 1
;;
esac

sleep 3
done

echo "Timeout: stato finale non raggiunto"
exit 2

Confronto canali​

CampoSMSRCSWhatsApp
deliveryStatusACCEPTED, REJECTED, DELIVERED, EXPIRED, DELETED, UNDELIVERABLE, UNKNOWNDELIVERED, EXPIRED, ERROR, DISABLED, UNSUPPORTED, UNKNOWNDELIVERED, EXPIRED, ERROR, DISABLED, UNSUPPORTED, CONVERSATION_CLOSED, UNKNOWN
Stato in transitoACCEPTEDUNKNOWNUNKNOWN
readDateSempre nullSempre nullPresente se letto
Latenza tipica DELIVERED1-5 secondi0.5-2 secondi0.5-2 secondi
Webhook READNon disponibileDisponibileDisponibile

Errori comuni​

404 — Messaggio non trovato​

{}

Soluzione: Verifica che il customerMessageId sia corretto e che il parametro channel corrisponda al canale usato per l'invio. I messaggi molto vecchi potrebbero non essere più disponibili.

Canale errato nel parametro channel​

Se invii un messaggio via SMS ma interroghi lo stato con channel=RCS, riceverai un 404 anche se il messaggio esiste. Assicurati che il canale nella query corrisponda a quello usato nell'invio.

Status ACCEPTED o UNKNOWN persistente​

Finché non arriva la ricevuta, un messaggio risulta ACCEPTED su SMS e UNKNOWN su RCS e WhatsApp. Cosa significa un'attesa lunga dipende dal canale:

  • RCS e WhatsApp: UNKNOWN è il normale stato in transito, non un problema di routing. Questi canali non hanno uno stato intermedio, quindi il messaggio resta UNKNOWN finché non diventa DELIVERED o fallisce, e può volerci un po' (per esempio se il telefono del destinatario è spento).
  • SMS: se lo status resta ACCEPTED per più di 60 secondi, l'operatore non ha ancora restituito la ricevuta. Verifica:
    • Il numero del destinatario è valido e raggiungibile
    • L'operatore del destinatario è supportato
    • Non ci sono problemi di rete in corso

Risultato atteso​

StepAzioneRisultato
1POST /sms/send (o RCS/WhatsApp)messageId salvato
2GET /messages/status/{id}?channel=SMSdeliveryStatus: "DELIVERED"
3GET /messages/status?channel=SMS&ids=id1,id2,id3Array di status per ogni messaggio

Prossimi passi​