Volver al portafolio

IA aplicada · Automatización

Agente de WhatsApp que califica y enruta leads a un CRM

Problema

Un retailer de pisos y revestimientos recibía consultas por WhatsApp fuera de horario y de forma desordenada: leads perdidos, datos incompletos y asignación manual entre asesores de dos ciudades.

Arquitectura

  1. WhatsApp Cloud API
  2. n8n (self-hosted)
  3. Gemini via OpenRouter
  4. CRM: contact + deal
  5. Advisor assignment

In progress → Qualified · VIP · Not qualified · Abandoned | Reminders · Session timeout · After-hours

Solución

  • Agente con Gemini sobre n8n que califica al lead conversando, un dato por mensaje (nombre, ciudad, tipo de proyecto, presupuesto, correo).
  • Clasificación por presupuesto y asignación automática al asesor de la ciudad con menos negocios abiertos, sincronizada con el CRM.
  • Flujo fuera de horario, recordatorios de seguimiento, recontacto por timeout y manejo de clientes recurrentes.
  • Plataforma multi-cliente operada con Claude Code controlando n8n por MCP, con workflows versionados y rollback.

Decisiones de diseño

  • Un solo dato por mensaje: la conversación se siente natural y se evitan respuestas ambiguas.
  • Si no se detecta la ciudad, el negocio queda con el administrador en vez de adivinar un asesor.
  • Cada script de reparación corre primero en dry-run; los workflows se archivan en lugar de borrarse, para poder volver atrás.
  • Los secretos se separan por cliente y la plataforma nunca asume una URL de producción por defecto.

Desafíos técnicos

  • Un deploy desde PowerShell 5.1 corrompió el encoding UTF-8 y rompió las regex con acentos: ahora hay sanity check antes y después de cada despliegue.
  • Un endpoint del CRM ignoraba en silencio los filtros vacíos y devolvía todos los registros, vinculando negocios a contactos ajenos: se corrigió verificando el teléfono y se aplicó el patrón en todos los workflows.
  • Auditoría y reparación con scripts que corren primero en dry-run y luego con --apply; reglas operativas nacidas de incidentes reales.

Patrón destacado

// Never trust results[0]: a CRM list call with an empty filter
// silently returns EVERY record, linking deals to the wrong contact.
const last10 = (p) => String(p).replace(/\D/g, "").slice(-10);

function findContactByPhone(results, phone) {
  const wanted = last10(phone);
  if (wanted.length < 10) return null; // refuse empty/short filters
  return results.find((c) => c.phones.some((p) => last10(p) === wanted)) ?? null;
}

Resultados

  • En producción desde junio de 2026, con mantenimiento activo.
  • Auditoría de 443 ejecuciones sin leads perdidos: los 15 teléfonos con mensajes quedaron guardados.
  • Workflow principal de ~130 nodos y asignación balanceada entre 4 asesores.

n8n, Gemini, OpenRouter, WhatsApp Cloud API, Bitrix24, MCP, AWS EC2