Appearance
Inbound — Cliente escribe al ISP
Caso: cliente de Semtec con número +504 9xxx-xxxx escribe "Mi internet no anda" por WhatsApp al número oficial del ISP.
Secuencia
Ejemplo de payload en Kafka
Evento en whatsapp-inbound-events:
json
{
"company_id": "691d590df0be71c6062c60d1",
"conversation_id": "6620ab1c…",
"meta_message_id": "wamid.HBgL…",
"direction": "inbound",
"wa_id": "50499887766",
"contact_name": "Juan Pérez",
"content": "Mi internet no anda",
"timestamp": "2026-04-21T14:02:11Z"
}Puntos de fallo tolerados
- Webhook duplicado (Meta retransmite): índice único en
meta_message_id→ insert falla, gateway responde 200 igualmente. - Kafka caído: el webhook responde 500 y Meta reintenta durante 24h. No se pierde.
- Chatwoot caído: el mensaje queda en el CRM; el consumer del bridge retoma cuando vuelve. No bloquea al cliente.
Identificación del cliente
wa_id (el número sin +) es la clave. El integration-api mantiene un contact_link en Postgres que mapea wa_id → chatwoot_contact_id. Si no existe:
- Busca en Chatwoot por
phone_number→ si existe, linkea. - Si no existe, crea un contacto mínimo en Chatwoot con nombre de WhatsApp.
- El CRM resuelve el
contact_idpor separado contra su propia colección.
Qué ve el agente
Dos bandejas idénticas en contenido:
- CRM → Tab WhatsApp del contacto: timeline en vivo con burbuja inbound.
- Chatwoot → Conversations: mismo mensaje, misma hora.
Ambos son tiempo real: el CRM por SSE (Redis), Chatwoot por ActionCable.
Siguiente: Outbound desde el CRM.