Passa al contenuto principale

UC-009 — Conversazione Bidirezionale

CampoValore
IDUC-009
ObiettivoGestire conversazioni bidirezionali con i clienti
CanaleWhatsApp / RCS
Complessità⭐⭐⭐ Avanzato
Tempo stimato20 minuti
API coinvoltePOST /api/partner-gateway/v1/webhooks/delivery-status, GET /api/partner-gateway/v1/inbox/conversations, GET /api/partner-gateway/v1/inbox/conversations/{chatId}/messages, POST /api/partner-gateway/v1/inbox/conversations/reply, PATCH /api/partner-gateway/v1/inbox/conversations/{chatId}/read, PATCH /api/partner-gateway/v1/inbox/conversations/{chatId}/archive

Scenari reali​

  • TechStore — Chat di assistenza clienti: Un cliente scrive su WhatsApp per chiedere informazioni su un ordine; il sistema riceve il messaggio, lo assegna a un operatore e risponde con lo stato della spedizione.
  • Studio Dentistico Bianchi — Conferma prenotazione con risposta: Dopo l'invio di un promemoria appuntamento, il paziente conferma o chiede di spostare la visita rispondendo al messaggio.
  • FashionOutlet — Raccolta feedback post-vendita: Un sondaggio post-acquisto chiede al cliente di rispondere con un voto da 1 a 5; il sistema raccoglie e cataloga le risposte automaticamente.

Prerequisiti​

Prima di iniziare, assicurati di avere:

Flusso di interazione​

Guida passo-passo​

Step 1 — Configurare il webhook per i messaggi inbound​

Per prima cosa registra un webhook per ricevere i messaggi in arrivo. Nonostante il nome, il webhook delivery-status riceve tutti gli eventi del tuo account: DELIVERY, READ e INBOUND. Vedi la guida Webhooks per la configurazione completa.

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

Risposta: 201 Created

{
"companyId": 189,
"callbackUrl": "https://api.techstore.it/webhooks/qlara"
}
Un webhook per account

Ogni account ha un solo callback URL, condiviso da SMS, RCS e WhatsApp. Se un webhook è già configurato, la chiamata risponde 409 Conflict e lascia invariato quello esistente: verificalo con GET /webhooks/delivery-status e cambia l'URL con PUT sullo stesso path. L'URL deve essere HTTPS sulla porta 443 o 8443 e raggiungibile pubblicamente, altrimenti la chiamata risponde 400.

Step 2 — Ricevere un messaggio inbound​

Quando un cliente invia un messaggio, il tuo endpoint riceve un payload come questo. Gli eventi INBOUND esistono solo per RCS e WhatsApp.

Inbound TEXT:

{
"eventType": "INBOUND",
"channel": "WHATSAPP",
"messageId": "msg-wa-in-001",
"source": "+393471234567",
"destination": "+393209998877",
"receivedDate": "2026-04-09T11:15:22+02:00",
"messageType": "TEXT",
"text": "Buongiorno, vorrei sapere lo stato del mio ordine ORD-2026-1584"
}

Inbound IMAGE:

{
"eventType": "INBOUND",
"channel": "WHATSAPP",
"messageId": "msg-wa-in-002",
"source": "+393471234567",
"destination": "+393209998877",
"receivedDate": "2026-04-09T11:16:05+02:00",
"messageType": "IMAGE",
"mediaKey": "b394ab72/efd4987c/39b4879f6fed01f0d622453be1488c93"
}
CampoDescrizione
eventTypeSempre INBOUND per un messaggio scritto dall'utente finale
channelWHATSAPP o RCS
messageIdIdentificativo del messaggio nella conversazione
sourceNumero di telefono dell'utente finale
destinationIl tuo numero WhatsApp (WhatsApp) o l'id del tuo agente (RCS)
receivedDateMomento di ricezione del messaggio. Gli eventi INBOUND non hanno eventDate
messageTypeTEXT per i messaggi di testo; i messaggi media (es. IMAGE) portano un mediaKey
textTesto del messaggio
mediaKeyChiave dell'allegato, presente nei messaggi media

I campi nulli vengono omessi dal payload, quindi un messaggio di testo non ha mediaKey.

Scaricare i media

Per scaricare un file media allegato, usa GET /api/files/{mediaKey}?expireMinutes=180. La risposta contiene un URL pre-firmato temporaneo. Vedi UC-026: Download Media da Messaggi Inbound.

Step 3 — Elencare le conversazioni​

Recupera le conversazioni, tenendo solo quelle con messaggi non letti:

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/inbox/conversations?unreadOnly=true" \
-H "X-Api-Key: YOUR_API_KEY"

Risposta:

[
{
"id": 1042,
"hasUnreadMessages": true,
"userName": "Marco Bianchi",
"phoneNumber": "+393471234567",
"unreadCount": 2,
"lastMessageText": "Buongiorno, vorrei sapere lo stato del mio ordine ORD-2026-1584",
"lastMessageDate": "2026-04-09 09:15:22.041+0000",
"socialMedia": "WHATSAPP",
"companyProfileName": "TechStore Italia",
"companyPhoneNumber": "+393209998877",
"whatsappWindowExpire": "2026-04-10 09:15:22.041+0000"
}
]

Step 4 — Ottenere i messaggi della conversazione​

Recupera il thread completo di una conversazione:

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/inbox/conversations/1042/messages" \
-H "X-Api-Key: YOUR_API_KEY"

Risposta:

{
"profile": {
"userName": "Marco Bianchi",
"profilePicture": null,
"additionalInfo": "+393471234567"
},
"messages": [
{
"id": 5001,
"text": "Buongiorno, vorrei sapere lo stato del mio ordine ORD-2026-1584",
"isRead": false,
"isUserReply": true,
"createdAt": "2026-04-09 09:15:22.041+0000",
"attachments": [],
"status": "DELIVERED"
}
]
}

isUserReply: true indica un messaggio scritto dal contatto, false una tua risposta. Un chatId inesistente o che non appartiene al tuo account riceve 404.

Step 5 — Rispondere alla conversazione​

Invia una risposta all'interno della conversazione esistente:

curl -X POST "https://api.qlara.ai/api/partner-gateway/v1/inbox/conversations/reply" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chatId": 1042,
"message": "Buongiorno Marco! Il suo ordine ORD-2026-1584 è in fase di spedizione. Riceverà il tracking entro oggi pomeriggio."
}'

Risposta: 202 Accepted

chatId è obbligatorio. Puoi inviare anche replyTo (l'id del messaggio che stai citando) e attachments (una lista di {"mediaId": …} dalla tua libreria media). La risposta parte sul canale della conversazione; segui la consegna tramite l'evento webhook DELIVERY.

Finestra di 24 ore

Su WhatsApp le risposte free-form sono possibili solo entro 24 ore dall'ultimo messaggio del cliente. Controlla il campo whatsappWindowExpire della conversazione. Fuori dalla finestra la risposta può comunque essere accettata (202) ma non viene consegnata: l'evento DELIVERY riporta statusCode: 12 (conversation closed). Dopo la scadenza, usa un template approvato da Meta. Vedi la guida WhatsApp.

Step 6 — Segnare come letta e archiviare​

Dopo aver gestito la richiesta, segna la conversazione come letta:

curl -X PATCH "https://api.qlara.ai/api/partner-gateway/v1/inbox/conversations/1042/read" \
-H "X-Api-Key: YOUR_API_KEY"

Risposta: 204 No Content

Quando la conversazione è conclusa, archiviala:

curl -X PATCH "https://api.qlara.ai/api/partner-gateway/v1/inbox/conversations/1042/archive" \
-H "X-Api-Key: YOUR_API_KEY"

Risposta: 204 No Content

Ripristino

Una conversazione archiviata può essere ripristinata in qualsiasi momento con PATCH /conversations/{chatId}/unarchive. Se il contatto scrive di nuovo, di norma la conversazione torna da sola nell'inbox attiva.

Parametri di filtro delle conversazioni​

ParametroTipoDescrizione
channelIdsstringID dei canali separati da virgola (es. WHATSAPP-123,RCS-456)
dateFromstringData ISO: solo le conversazioni aggiornate dopo questa data
orderBystringCampo di ordinamento con prefisso +/- (es. -lastMessageDate)
sectionstringSezione dell'inbox, per stato di assegnazione (es. solo le conversazioni assegnate a te o quelle non assegnate)
unreadOnlybooleanSe true, restituisce solo le conversazioni con messaggi non letti

Paginazione dei messaggi​

Per i thread lunghi usa i parametri idFrom (id messaggio maggiore o uguale) e idTo (id messaggio minore o uguale):

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/inbox/conversations/1042/messages?idFrom=5000&idTo=5050" \
-H "X-Api-Key: YOUR_API_KEY"
Dietro le quinte

Quando un cliente invia un messaggio, il carrier (Meta per WhatsApp, Google per RCS) lo recapita alla piattaforma Qlara, che:

  1. Crea o aggiorna la conversazione -- Se il contatto ha già una conversazione aperta sullo stesso canale, il messaggio viene aggiunto al thread esistente. Altrimenti ne viene creata una nuova.
  2. Ti avvisa via webhook -- Il payload INBOUND viene inviato al callback URL registrato. Il tuo server deve rispondere con un qualsiasi 2xx entro 5 secondi. Le consegne fallite vengono ritentate, quindi lo stesso evento può arrivare più di una volta: deduplica su eventType + messageId.
  3. Gestisce la finestra -- Su WhatsApp la piattaforma sposta automaticamente in avanti la scadenza della finestra di 24 ore ogni volta che il cliente scrive.
  4. Instrada la risposta -- Quando invii una risposta con POST /conversations/reply, la piattaforma la invia automaticamente sullo stesso canale della conversazione originale.

Risultato atteso​

AspettoDettaglio
Azione completataMessaggio inbound ricevuto, risposta inviata, conversazione archiviata
Canale usatoWhatsApp / RCS
Conferma di consegnaVia webhook (statusCode: 3) entro 5-60 secondi

Errori comuni​

ProblemaCausa probabileSoluzione
HTTP 401API Key mancante o non validaControlla l'header X-Api-Key
HTTP 409 su POST /webhooks/delivery-statusUn webhook è già configurato per l'accountVerificalo con GET /webhooks/delivery-status; cambia l'URL con PUT sullo stesso path
HTTP 400 su POST /webhooks/delivery-statusIl callback URL non è un URL HTTPS pubblico sulla porta 443 o 8443Usa un URL HTTPS raggiungibile pubblicamente, senza credenziali né fragment
HTTP 400 sulla rispostaBody malformato o chatId mancanteInvia chatId (obbligatorio) e message
HTTP 404 — Conversazione non trovataIl chatId non esiste o non appartiene al tuo accountOttieni un chatId valido da GET /inbox/conversations
Risposta accettata ma non consegnataLa finestra WhatsApp di 24 ore è chiusa (evento DELIVERY con statusCode: 12)Controlla whatsappWindowExpire; usa invece un template approvato da Meta
Nessun webhook INBOUND ricevutoWebhook non configurato, oppure endpoint irraggiungibile o che non risponde 2xx entro 5 secondiVerifica la registrazione con GET /webhooks/delivery-status e controlla il tuo endpoint

Prossimi passi​