Canal WhatsApp
A partir de la v3.5.0 Queria expone una abstraccion de canal para que los bots empresariales puedan recibir y responder mensajes en plataformas de mensajeria externas. La primera implementacion disponible es Twilio for WhatsApp.
La abstraccion esta disenada para acoger en versiones siguientes Telegram, SMS, Slack sin refactor del core.
Lado usuario
Para la guia de usuario (emparejamiento, comandos, ejemplos) ver Chat WhatsApp.
Modelo operativo V1
| Aspecto | V1 |
|---|---|
| Provider | Twilio (only) |
| Canal | WhatsApp (only) |
| Numero en prod | Numero Meta-approved compartido propiedad de Queria |
| Numero en dev | Sandbox Twilio (whatsapp:+14155238886) |
| Modelo tenant | Cuenta Twilio compartida, fromAddress opcionalmente tenant-specifico |
| Inbound | Solo texto (imagenes/audio rechazados con mensaje cortes) |
| Outbound | Solo respuestas a inbound (no notificaciones proactivas en V1) |
| Pairing | Codigo via web app, comando /pair <CODIGO> desde WhatsApp |
| Rate limit | 10 mensajes inbound / 60s por numero |
Arquitectura
WhatsApp (usuario)
| 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 (usuario)El canvas CHAT que se ejecuta sobre el mensaje inbound es el mismo de la web app, con el flag sys.channel = 'whatsapp' propagado. Los componentes LLM pueden leerlo y adaptar la salida (ej. lenguaje mas compacto, omision de bloques tabulares).
Configuracion global (SYSTEM_ADMIN)
Variables .env requeridas:
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=********
TWILIO_DEFAULT_FROM=whatsapp:+14155238886 # sandbox en dev
TWILIO_WEBHOOK_URL=https://admin.queria.pro/api/webhooks/twilio
# Pairing
CHANNEL_PAIR_CODE_TTL_MS=600000 # 10 minutos
CHANNEL_PAIR_RATE_LIMIT=3 # max 3 codigos/hora por usuario
# Inbound rate limit
CHANNEL_INBOUND_RPS_BUCKET=10 # mensajes
CHANNEL_INBOUND_RPS_WINDOW=60 # segundosEn el panel provider Twilio:
- Messaging > WhatsApp Senders > Sandbox (dev) o Numero aprobado (prod).
- Webhook URL =
https://admin.queria.pro/api/webhooks/twiliocon metodoPOST. - Genera
AUTH_TOKENy configuralo en.env(nunca commitear).
Configuracion por tenant
Panel admin > DSL y Pipelines > Canal WhatsApp.
| Campo | Default | Configurable por |
|---|---|---|
| Enabled | false | SYSTEM_ADMIN |
| fromAddress | Default Queria | SYSTEM_ADMIN |
| Canvas pipeline | whatsapp-default | COMPANY_ADMIN (seleccion) |
| Auto-provision webhook | true | SYSTEM_ADMIN |
Para asignar un numero dedicado a un tenant (Meta-approved):
- Compra el numero en Twilio Console.
- Inserta
whatsapp:+<numero>en el campofromAddressdel tenant. - El backend llama Twilio
IncomingPhoneNumbersAPI para apuntarSmsUrlal webhook Queria. - Un cron diario refresca esta configuracion (TTL 30 dias).
Solo SYSTEM_ADMIN puede escribir fromAddress
COMPANY_ADMIN ve el numero en solo lectura en la ficha empresa. Los end users ven el numero en su perfil para saber a quien enviar mensajes.
Emparejamiento de usuarios
Un usuario hace pairing una sola vez desde su perfil (ver Chat WhatsApp - lado usuario).
Internamente:
ChannelPairCode-- tabla de codigos generados (8 chars, alfabeto 32 chars, TTL 10 min).ChannelBinding-- fila final para(channel, address)-> User. Globalmente unica.WebhookDedup-- dedup porproviderMessageIdpara evitar doble procesamiento en retries Twilio.
Desde el panel admin DSL y Pipelines > Canal WhatsApp > Bindings:
- Tabla de todos los emparejamientos del tenant (usuario, numero, ultimo mensaje, total mensajes).
- Filtros por usuario, rango fecha, estado.
- Posibilidad de forzar unbind con
/stoplado admin (ej. empleado saliente).
Comandos gestionados
Interceptados antes de la ejecucion del canvas:
| Comando | Efecto backend |
|---|---|
/pair <CODIGO> | Lookup ChannelPairCode, validacion TTL/usado, creacion ChannelBinding |
/reset | Cierra la Conversation activa (closedAt = now()), el siguiente mensaje abre una nueva |
/stop | Borra ChannelBinding. Liberado el numero. Mensajes siguientes rechazados con "no reconocido" |
/help | Responde con lista de comandos |
Todo lo que no es comando pasa al canvas.
Output formatting
El TwilioChannelAdapter post-procesa la respuesta del canvas:
- Convierte Markdown estandar a markdown WhatsApp-flavored (
*bold*,_italic_,~strike~,`para code). - Anade un footer fuentes:
*Fuentes:* 1) Contrato Mantenimiento 2026.pdf 2) Anexo Tecnico A.docx - Divide hard a 1500 caracteres por chunk (limite Twilio).
- Envia en secuencia via
messages.create.
Logging y monitoring
Cada mensaje inbound/outbound genera registros en:
ChannelMessageLog(Postgres) --providerMessageId,direction,latencyMs,statusCode.IngestionCallLogpara fallos Twilio (ej. numero sin opt-in).- Metrica Prometheus (si enabled):
queria_channel_messages_total{provider,channel,direction,status}.
Pagina admin Canales > Monitoring: graficos de volumen, latencia, tasa de error, top usuarios por mensajes.
Privacidad y conformidad
- Los mensajes inbound son cifrados E2E por WhatsApp hasta el gateway Twilio. De Twilio a Queria viaja HTTPS.
- Las respuestas estan sujetas a la ventana 24h customer service de Meta: pasadas las 24h desde la ultima interaccion, hace falta un template HSM (V2).
/stopes el derecho opt-out del usuario. CancelaChannelBinding. El historialConversationqueda salvo solicitud explicita de eliminacion (GDPR right to erasure).- Los datos Twilio (Account SID, Auth Token) se guardan cifrados en env vars; el panel UI nunca los expone en claro.
Limites y roadmap
V1:
- Provider Twilio only. Telegram/SMS/Slack soportados a nivel adapter, no implementados.
- Solo texto inbound.
- Solo conversaciones iniciadas por el usuario (no push proactivo).
- Solo una active conversation por (User, channel).
V2 (roadmap):
- Templates HSM para mensajes proactivos.
- Multi-tenant credentials Twilio (cuenta separada por tenant).
- Telegram adapter como segundo provider.
- Multimedia inbound (imagenes a un sink de documentos).
Troubleshooting
"Codigo expirado" -- el usuario espero mas de 10 minutos. Genera uno nuevo.
"Numero ya emparejado" -- el usuario target debe hacer /stop antes de re-vincularse.
Webhook 403 -- verifica TWILIO_AUTH_TOKEN. Las firmas HMAC-SHA1 deben coincidir.
Mensaje no respondido -- comprueba:
WebhookDedup(es duplicado?).- Rate limit (>10 msg/60s?).
- Error canvas (ver
IngestionCallLog).
"Por ahora solo acepto mensajes de texto" -- el usuario envio media. V1 es text-only.
Queria v3.5.0 -- Channels (Twilio WhatsApp V1)