Skip to content

Canali WhatsApp

A partire dalla v3.5.0 Queria espone un'astrazione di canale per consentire ai bot aziendali di ricevere e rispondere a messaggi su piattaforme di messaging esterne. La prima implementazione disponibile e Twilio for WhatsApp.

L'astrazione e progettata per accogliere in versioni successive Telegram, SMS, Slack senza refactor del core.

Lato utente

Per la guida utente (abbinamento numero, comandi, esempi d'uso) vedi Chat WhatsApp.

Modello operativo V1

AspettoV1
ProviderTwilio (only)
CanaleWhatsApp (only)
Numero in prodNumero Meta-approvato shared, di proprieta Queria
Numero in devSandbox Twilio (whatsapp:+14155238886)
Modello tenantAccount Twilio condiviso, fromAddress opzionalmente tenant-specifico
InboundSolo testo (immagini/audio rifiutati con messaggio cortese)
OutboundSolo risposte a inbound (no notifiche proattive in V1)
PairingCodice via web app, comando /pair <CODICE> da WhatsApp
Rate limit10 messaggi inbound / 60s per numero

Architettura

WhatsApp (utente)
    | inbound (Twilio webhook)
    v
+------------------+        +------------------+        +------------------+
| Twilio Webhook   |   ---> | Channel Inbound  |   ---> | runCanvasChat    |
| Verify signature |        | Service          |        | (canvas CHAT     |
| Dedup            |        | - Pair commands  |        |  whatsapp-default)|
| Rate limit       |        | - Resolve user   |        +------------------+
+------------------+        | - Active conv    |               |
                            +------------------+               | response text
                                                               v
                                                       +------------------+
                                                       | TwilioChannel    |
                                                       | Adapter.send     |
                                                       | - Format WA MD   |
                                                       | - Split 1500 ch  |
                                                       | - REST send      |
                                                       +------------------+
                                                               |
                                                               v
                                                          WhatsApp (utente)

Il canvas CHAT che viene eseguito sul messaggio inbound e lo stesso usato per la web app, con il flag sys.channel = 'whatsapp' propagato. I componenti LLM possono leggerlo e adattare l'output (es. linguaggio piu compatto, omissione di blocchi tabellari).

Configurazione globale (SYSTEM_ADMIN)

Variabili .env richieste:

bash
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=********
TWILIO_DEFAULT_FROM=whatsapp:+14155238886    # sandbox in dev
TWILIO_WEBHOOK_URL=https://admin.queria.pro/api/webhooks/twilio

# Pairing
CHANNEL_PAIR_CODE_TTL_MS=600000   # 10 minuti
CHANNEL_PAIR_RATE_LIMIT=3         # max 3 codici/ora per utente

# Inbound rate limit
CHANNEL_INBOUND_RPS_BUCKET=10     # messaggi
CHANNEL_INBOUND_RPS_WINDOW=60     # secondi

Configurare nel pannello provider Twilio:

  1. Messaging > WhatsApp Senders > Sandbox (dev) o Numero approvato (prod).
  2. Webhook URL = https://admin.queria.pro/api/webhooks/twilio con metodo POST.
  3. Genera AUTH_TOKEN e configuralo nel .env (mai committare).

Configurazione per tenant

Pannello admin > DSL e Pipeline > Canali WhatsApp.

CampoDefaultConfigurabile da
EnabledfalseSYSTEM_ADMIN
fromAddressDefault QueriaSYSTEM_ADMIN
Canvas pipelinewhatsapp-defaultCOMPANY_ADMIN (selezione)
Auto-provision webhooktrueSYSTEM_ADMIN

Per assegnare un numero dedicato a un tenant (Meta-approvato):

  1. Acquista il numero su Twilio Console.
  2. Inserisci whatsapp:+<numero> nel campo fromAddress del tenant.
  3. Il backend chiama Twilio IncomingPhoneNumbers API per puntare SmsUrl al webhook Queria.
  4. Una cron giornaliera rinfresca questa configurazione (TTL 30 giorni).

Solo SYSTEM_ADMIN puo scrivere fromAddress

COMPANY_ADMIN vede il numero in sola lettura nella scheda azienda. Gli end user vedono il numero nel proprio profilo per sapere a chi mandare i messaggi.

Pairing utenti

Un utente esegue il pairing una volta sola dal proprio profilo (vedi Chat WhatsApp - lato utente).

Internamente:

  • ChannelPairCode -- tabella codici generati (8 char, alfabeto 32 chars, TTL 10 min).
  • ChannelBinding -- riga finale per (channel, address) -> User. Globalmente unica.
  • WebhookDedup -- dedup per providerMessageId per evitare doppi processi su retry Twilio.

Dal pannello admin DSL e Pipeline > Canali WhatsApp > Bindings:

  • Tabella di tutti gli abbinamenti del tenant (utente, numero, ultimo messaggio, conteggio messaggi totali).
  • Filtri per utente, range data, stato.
  • Possibilita di forzare unbind per /stop lato admin (es. dipendente uscito).

Comandi gestiti

Vengono intercettati prima dell'esecuzione del canvas:

ComandoEffetto backend
/pair <CODICE>Lookup ChannelPairCode, validazione TTL/usato, creazione ChannelBinding
/resetChiude la Conversation attiva (closedAt = now()), il messaggio successivo apre una nuova
/stopCancella ChannelBinding. Liberato il numero. Messaggi successivi rifiutati con "non riconosciuto"
/helpRisponde con elenco comandi

Tutto cio che non e un comando passa al canvas.

Output formatting

Il TwilioChannelAdapter post-processa la risposta del canvas:

  1. Converte Markdown standard in WhatsApp-flavored markdown (*bold*, _italic_, ~strike~, ` per code).
  2. Aggiunge un footer fonti:
    *Fonti:*
    1) Contratto Manutenzione 2026.pdf
    2) Allegato Tecnico A.docx
  3. Suddivide hard a 1500 caratteri per chunk (limite Twilio).
  4. Invia in sequenza via messages.create.

Logging e monitoring

Ogni messaggio inbound/outbound genera record in:

  • ChannelMessageLog (Postgres) -- providerMessageId, direction, latencyMs, statusCode.
  • IngestionCallLog per i fallimenti Twilio (es. numero non opt-in).
  • Metrica Prometheus (se enabled): queria_channel_messages_total{provider,channel,direction,status}.

Pagina admin Canali > Monitoring: grafici di volume, latenza, tasso di errore, top utenti per messaggi.

Privacy e conformita

  • I messaggi inbound sono cifrati E2E da WhatsApp fino al gateway Twilio. Da Twilio a Queria viaggia HTTPS.
  • Le risposte sono soggette alla finestra 24h customer service di Meta: oltre 24h dall'ultima interazione, serve un template HSM (V2).
  • /stop e il diritto all'opt-out lato utente. Cancella ChannelBinding. La cronologia Conversation resta a meno di esplicita richiesta di rimozione (GDPR right to erasure).
  • I dati Twilio (Account SID, Auth Token) sono conservati cifrati nelle env vars; il pannello UI non li espone in chiaro.

Limiti e roadmap

V1:

  • Provider Twilio only. Telegram/SMS/Slack supportati a livello di adapter, non implementati.
  • Solo testo inbound.
  • Solo conversazioni avviate dall'utente (no push proattivo).
  • Solo un'active conversation per (User, channel).

V2 (roadmap):

  • Template HSM per messaggi proattivi.
  • Multi-tenant credentials Twilio (account separato per tenant).
  • Telegram adapter come secondo provider.
  • Multimedia inbound (immagini su un sink documenti).

Troubleshooting

"Codice scaduto" -- l'utente ha aspettato piu di 10 minuti. Generane uno nuovo.

"Numero gia abbinato" -- l'utente target deve fare /stop prima di ri-abbinarsi.

Webhook 403 -- verifica TWILIO_AUTH_TOKEN. Le firme HMAC-SHA1 devono coincidere.

Messaggio non risposto -- controlla:

  1. WebhookDedup (e' uno duplicato?).
  2. Rate limit (>10 msg/60s?).
  3. Errore canvas (vedi IngestionCallLog).

"Per ora accetto solo messaggi testuali" -- l'utente ha inviato media. V1 e text-only.


Queria v3.5.0 -- Channels (Twilio WhatsApp V1)

Queria - Document Intelligence con Cog-RAG