WhatsApp + Telegram · código abierto · v1.7.8

Ningún lead se queda esperando

Un agente atiende en WhatsApp, califica y pasa el lead al colaborador que lleva más tiempo disponible, por Telegram, con todo lo que necesita para llamar.

La instalación en el servidor requiere un técnico: consulta Implementación en la VPS.

Banner de atende-leads: ningún lead esperando, el agente atiende en WhatsApp y avisa por Telegram a quien está disponible
En resumen

atende-leads es un sistema de atención de leads (clientes potenciales) por WhatsApp, pensado para pequeños negocios como una tienda, una escuela, una inmobiliaria o un prestador de servicios. Un agente responde las dudas, pregunta qué busca la persona y asigna una puntuación al lead: caliente, tibio o frío. Cuando pide hablar con alguien o muestra interés en comprar, el sistema avisa por Telegram al colaborador que lleva más tiempo disponible, con los datos y un botón para llamar. Para usarlo, necesitas un servidor (VPS) con Docker, un dominio, un número de WhatsApp exclusivo para la atención y un bot de Telegram.

Qué es

El agente atiende, el equipo cierra

El agente se encarga de la primera conversación. Cuando hay una posibilidad de venta o alguien necesita ayuda, el lead pasa a una persona del equipo, cuando le toca, y nadie queda olvidado en la fila.

De WhatsApp al colaborador disponible: agente en WhatsApp, califica y asigna una puntuación, colaborador disponible, alerta en el grupo, panel del equipo, cierre

💬 Agente en WhatsApp

Responde las preguntas frecuentes, muestra el precio solo de lo que está registrado, pregunta el nombre, qué busca y para cuándo, y asigna la puntuación del lead (caliente, tibio o frío). Funciona con Evolution API.

🙋 Llama a una persona en el momento justo

En 3 casos: el lead lo pide, el agente nota que hace falta (queja, problema, dos veces "no entendí") o ve una posibilidad de venta (precio, "quiero comprar", pago).

📨 Oferta por Telegram

Llega en privado al colaborador que lleva más tiempo disponible: nombre, teléfono, puntuación, interés, resumen y últimos mensajes, con los botones ✅ Asumir (Assumir) · ↪️ Pasar (Passar) · 📞 Llamar (Ligar) · 💬 WhatsApp.

🚨 Alerta en el grupo

Si no hay respuesta en 2 min, la oferta pasa a la siguiente persona. Si un lead caliente no tiene responsable en 2 min (normal: 5) o no hay nadie disponible, se envía una alerta al grupo, y quien toque primero Asumir (Assumir) se queda con el lead.

📌 Panel fijo del equipo

Un mensaje fijado en el grupo, EQUIPE AGORA, muestra quién está disponible (Livre), atendiendo, ocupado (Ocupado) o fuera (Fora), y la fila de leads en espera. Se actualiza con cada cambio.

✅ Cierre con resultado

Venta (Vendeu; valor) · Devolver llamada (Retornar; fecha) · En negociación (Negociando) · Sin interés (Sem interesse; motivo) · No válido (Inválido), con una nota de texto o audio (el audio se convierte a texto solo si WHISPER_CMD está configurado en .env). El colaborador vuelve al final de la fila de disponibles.

🖥️ Tres paneles web

Lead: chat, burbuja para el sitio y página «mi atención». Equipo: /equipe. Gestor: /gestor, con vista en vivo, hoy, leads, registros y exportación CSV.

🔒 LGPD

El lead puede enviar PARAR o apagar meus dados. El grupo del equipo nunca recibe el teléfono ni el texto del lead: solo el nombre, el motivo, la puntuación y los tiempos.

🧠 Cerebro basado en reglas

Por defecto, el agente funciona con reglas, sin costo y sin API. Opcionalmente, puedes usar Ollama local o un endpoint compatible con OpenAI del propio negocio, con retorno a las reglas si falla.

Cómo funciona

Del «hola» en WhatsApp al cierre

Cada lead sigue el mismo camino. El sistema guarda todo en una base de datos SQLite en tu servidor.

Lead en WhatsApp o en el sitio→ El agente responde y califica→ Disparador→ Oferta a quien lleva más tiempo disponible→ Alerta 🚨 si nadie la asume→ El colaborador asume y llama→ Cierra con un resultado
1

Los 3 disparadores

Pide hablar con alguien ("atendente", "me liga"), posibilidad de venta ("quanto custa", "quero comprar", "orçamento") o necesita atención ("problema", "reclamação", "cancelar").

2

El orden de la fila

Los colaboradores disponibles forman una fila según la hora en que quedaron libres. Quien cierra una atención vuelve al final de la fila. Un lead que vuelve dentro de 30 días se ofrece primero a quien lo atendió.

3

Plazos

Oferta: 2 min. Alerta: 2 min para lead caliente, 5 min para uno normal. Recordatorio de atención detenida: 30 min. Todo se puede ajustar en los registros.

El proceso, de principio a fin

13 pasos, desde quien instala hasta quien vende

Quién realiza cada paso:

🧠 el dueño o gestor⚙️ el sistema🤖 el agente
1

Instalar en la VPS 🧠 dueño

El script pregunta el nombre, el dominio y Telegram; genera secretos, el .env y el dados/negocio.json; inicia Docker. Al final muestra el token del gestor: guárdalo, es la contraseña de /gestor. Más detalles en Implementación en la VPS.

./instalar-vps.sh
2

Conectar WhatsApp 🧠 dueño

Abre un túnel hasta la VPS, entra al panel de Evolution en http://localhost:8081/manager, crea la instancia y lee el código QR con el número de atención. Usa un número exclusivo para esto.

ssh -L 8081:127.0.0.1:8081 usuario@vps
3

Registrar 🧠 gestor

En /gestor → Registros: equipo (nombre, teléfono, código), productos con palabras y precio, preguntas frecuentes, horarios y plazos.

4

El equipo entra al bot 🧠 equipo

Cada colaborador envía /entrar <código> en privado al bot y toca 🟢 Libre. El código de cada persona es el que imprimió el instalador (en la prueba local, el de negocio.json, como ana-1234).

/entrar <código>
5

Llega el lead ⚙️ sistema

Por WhatsApp o por la burbuja de chat del sitio. Para poner la burbuja en tu sitio, pega esta línea antes de </body> en las páginas:

<script src="https://<domínio>/widget.js" async></script>
6

El agente atiende 🤖 agente

Responde las preguntas frecuentes, informa el precio registrado, califica y asigna una puntuación.

7

Disparador ⚙️ sistema

Pide hablar con alguien, necesita atención o hay una posibilidad de venta: abre el caso y envía una línea breve al grupo, sin teléfono.

8

Oferta ⚙️ sistema

Se envía en privado a quien lleva más tiempo disponible, con datos y botones. Si no responde en 2 min, pasa a la siguiente persona.

9

Alerta 🚨 ⚙️ sistema

Mensaje en el grupo cuando vence el plazo o no hay nadie disponible. Quien toque primero Asumir (Assumir) se queda con el lead.

10

El colaborador asume 🧠 equipo

Llama (📞), responde por WhatsApp (💬) o responde en el propio bot, contestando (reply) a la tarjeta de atención.

11

Cierra con el resultado 🧠 equipo · ⚙️ sistema

El colaborador elige el resultado; el sistema guarda el historial, programa la devolución de llamada y devuelve al colaborador a la fila.

12

El gestor hace seguimiento 🧠 gestor

En /gestor: vista en vivo, hoy, leads y exportación CSV.

13

Copia de seguridad diaria ⚙️ cron

Una copia diaria de la base de datos y los registros, mediante el cron único que instala instalar-vps.sh, guardada en /opt/atende-leads-backups/.

docker compose exec -T atende ./atende backup ...
Requisitos

Qué necesitas

Para probarlo en tu computadora, basta con Python 3. Para usarlo de verdad, con WhatsApp y Telegram, necesitas lo demás.

🐍 Python 3

Solo la biblioteca estándar: no hace falta pip install para ejecutarlo. Para ejecutar las pruebas, pytest.

python3 --version

🐳 VPS con Docker

Un servidor Linux con Docker y Docker Compose. La aplicación escucha solo en 127.0.0.1:8080.

docker compose version

🌐 Dominio con HTTPS

Un proxy inverso (Caddy o Nginx) desde tu dominio hacia 127.0.0.1:8080. Los webhooks necesitan HTTPS.

📱 Número de WhatsApp

Un número exclusivo para la atención, conectado mediante Evolution API. Puede iniciarse en el mismo compose (perfil evolution).

✈️ Bot de Telegram

Crea el bot con @BotFather y agrégalo al grupo del equipo como administrador para que fije el panel.

👥 El equipo

Cada colaborador necesita Telegram y un código personal, que sirve para /entrar y para el panel /equipe.

📖 Palabras que aparecen en esta guía

  • Lead: persona que se puso en contacto y puede convertirse en cliente.
  • FAQ: lista de preguntas frecuentes con respuestas preparadas que usa el agente.
  • Caso: solicitud de atención humana abierta para un lead.
  • VPS: servidor alquilado en internet, donde el sistema permanece activo todo el tiempo.
  • Evolution API: programa que conecta un número de WhatsApp al sistema (no es la API oficial de Meta). Cada número conectado es una instancia; Baileys es el modo de conexión mediante código QR.
  • SQLite: base de datos en un solo archivo (dados/leads.db), sin un servidor aparte.
  • Ollama: programa que ejecuta modelos de IA en la propia computadora o servidor; aquí es opcional.
  • Perfil de compose: grupo de servicios de docker-compose.yml que solo se inicia cuando se solicita, como --profile evolution.
  • Webhook: dirección de tu sistema que WhatsApp (Evolution) y Telegram llaman cuando llega un mensaje.
  • Proxy inverso: programa (Caddy o Nginx) que recibe el acceso a través de tu dominio con HTTPS y lo reenvía al sistema.
  • Cron: programador de tareas de Linux que ejecuta un comando todos los días a la misma hora.
  • Token del gestor: contraseña del panel /gestor; en las llamadas a la API va en el encabezado X-Token.
Guía de uso · paso a paso

Prueba en tu computadora en 5 minutos

Sin WhatsApp ni Telegram configurados, las integraciones quedan desactivadas y los paneles web funcionan. Es la forma más rápida de ver el sistema.

1

Descarga el proyecto

Clona el repositorio y entra en la carpeta.

git clone https://github.com/inematds/atende-leads.git
cd atende-leads
2

Inicia el servidor

La primera vez, el sistema copia exemplos/negocio.json a la carpeta de datos. Si el puerto 8080 está ocupado en tu computadora, usa otro (por ejemplo, --porta 8090) y cambia las direcciones en los pasos siguientes.

./atende serve --porta 8080 --dados dados
3

Abre las tres pantallas

Chat del lead en http://localhost:8080/, equipo en /equipe (se ingresa con el código del colaborador) y gestor en /gestor (se ingresa con el token_gestor de dados/negocio.json).

# en el ejemplo, el token del gestor es TROQUE-ESTE-TOKEN y el código de Ana es ana-1234
grep -E '"token_gestor"|"codigo"' dados/negocio.json
4

Registra tu negocio

Desde /gestor → Registros, o editando dados/negocio.json. El agente solo menciona precios que estén aquí. El archivo incluye datos de ejemplo (la colaboradora Ana, el «Plan anual» (Plano anual), preguntas frecuentes de una tienda): cámbialos por los tuyos antes de recibir leads reales.

{
  "nome": "Loja Exemplo",
  "equipe": [ { "id": "ana", "nome": "Ana", "telefone": "5541999990010", "codigo": "ana-1234" } ],
  "produtos": [ { "id": "plano-anual", "nome": "Plano anual", "palavras": ["anual", "plano anual"], "preco": "R$ 1.200" } ],
  "prazos": { "oferta_min": 2, "alerta_quente_min": 2, "alerta_normal_min": 5, "lembrete_min": 30 },
  "cerebro": { "tipo": "regras" }
}
5

Prueba con el reloj detenido

Con ATENDE_AGORA, el «ahora» queda fijo y puedes ejecutar las tareas programadas (ofertas vencidas, alertas, recordatorios) cuando quieras. Antes, detén el servidor del paso 2 (Ctrl+C) y ejecuta curl en una segunda terminal, porque serve ocupa la primera.

ATENDE_AGORA=2026-11-09T10:00 ./atende serve --porta 8080 --dados dados
curl -X POST -H "X-Token: TROQUE-ESTE-TOKEN" "http://localhost:8080/api/tarefas/rodar"
6

Ejecuta las pruebas

Son 320 pruebas de contrato. El build y el contenedor Docker solo se usan con TESTAR_DOCKER=1.

python3 -m pytest -q tests/

Comandos del bot en Telegram

En privado con el bot

  • /entrar <código> vincula tu Telegram con tu registro
  • /livre · /ocupado · /fora cambian tu estado
  • /meus tus atenciones · /retornos devoluciones de llamada de hoy
  • /lead <nombre o teléfono> ficha breve
  • /fechar <id> vendeu <valor> (o retornar, negociando, sem, invalido)

En el grupo del equipo

  • /status envía el panel EQUIPE AGORA (solo en el grupo del equipo)
  • Líneas breves para cada caso y alertas 🚨 con el botón ✅ Asumir (Assumir)
  • Nunca se muestra el teléfono ni el texto del lead
Despliegue en la VPS

En línea con Docker

Variables en .env.exemplo. Si faltan las variables de una integración, queda desactivada y el resto funciona (paneles web).

1

Iniciar

Antes de instalar: crea el bot en @BotFather y agrégalo al grupo del equipo. El instalador solicita el token del bot y el ID del grupo (número que empieza con -100). Para encontrar el ID, envía un comando al bot en el grupo, como /start@nome_do_bot (en el modo de privacidad predeterminado, los mensajes comunes no llegan al bot), y abre la dirección de abajo; el chat.id del grupo aparece en la respuesta. Hazlo antes de registrar el webhook (paso 6), porque después getUpdates deja de responder.

curl "https://api.telegram.org/bot<TOKEN>/getUpdates"

En la VPS, como root (o con sudo), con git, python3 y Docker instalados, clona el proyecto y ejecuta el instalador. Este genera el .env y el dados/negocio.json solo para el propietario (umask 077), el token del administrador y los códigos del equipo (aleatorios), asigna la carpeta dados/ al uid 1000 (el contenedor no se ejecuta como root; si no eres root, intenta sudo -n chown y, si no lo consigue, se detiene antes de iniciar y muestra el comando), inicia compose, con o sin Evolution, instala el cron de respaldo e imprime todo al final: guárdalo. Ejecutarlo de nuevo (cambiar el dominio, activar Telegram) no cambia los secretos: reutiliza los que ya están en .env e indica cuáles; solo genera los que faltan (una contraseña nueva de Postgres detendría Evolution, y un TELEGRAM_SEGREDO nuevo haría que el webhook de Telegram respondiera 401). El registro parte del ejemplo (la colaboradora Ana, el "Plan anual", una FAQ de tienda): reemplázalo por tus datos en /gestor → Registros antes de recibir leads. La aplicación escucha solo en 127.0.0.1:8080 y Evolution en 127.0.0.1:8081.

git clone https://github.com/inematds/atende-leads.git /opt/atende-leads
cd /opt/atende-leads
./instalar-vps.sh
# sem o instalador: cp .env.exemplo .env, troque todos os segredos do .env
# e o token_gestor e os códigos em dados/negocio.json (12+ caracteres);
# com a Evolution junto, ponha EVOLUTION_URL=http://evolution-api:8080 no .env;
sudo chown -R 1000:1000 /opt/atende-leads/dados   # o container roda como uid 1000
docker compose up -d --build              # ou, com a Evolution junto:
docker compose --profile evolution up -d --build
2

Los secretos de ejemplo no se exponen en la red

Si negocio.json todavía tiene token_gestor = TROQUE-ESTE-TOKEN o algún código igual al de exemplos/negocio.json, o si una integración está activada con WEBHOOK_SEGREDO/TELEGRAM_SEGREDO vacío, con menos de 16 caracteres o que contiene troque (o con EVOLUTION_API_KEY que contiene troque), el servidor solo acepta iniciarse en 127.0.0.1/localhost. En 0.0.0.0 (como en Docker), lo rechaza con el mensaje "ejecuta ./instalar-vps.sh o cambia los secretos". Solo para pruebas o demostraciones existe ATENDE_PERMITIR_EXEMPLO=1 (nunca en producción).

3

HTTPS

Proxy inverso (Caddy o Nginx) de tu dominio a 127.0.0.1:8080. El instalador ya completa url_publica en negocio.json con el dominio; revísalo. Los límites por IP (5 contraseñas incorrectas por minuto: las incorrectas reciben 429, la correcta siempre pasa; 5 conversaciones nuevas del chat web en 10 min, además de un límite total; 3 solicitudes de atención por web por hora) usan la IP de X-Forwarded-For solo cuando la conexión viene de un proxy confiable: ATENDE_PROXY_CONFIAVEL (CIDRs; el valor predeterminado cubre el loopback y las redes privadas, por donde Caddy en el host llega al contenedor). Vacío = nunca confiar en X-Forwarded-For. Solo puede hacerse cargo de un lead el colaborador a quien se le ofreció o, en una alerta 🚨, quien pulse primero en Asumir.

# Caddyfile
leads.seudominio.com { reverse_proxy 127.0.0.1:8080 }
4

WhatsApp: leer el código QR

El puerto de Evolution solo escucha en 127.0.0.1, así que abre un túnel desde tu computadora y, mientras esté abierto, accede a http://localhost:8081/manager. Inicia sesión con la API Key global (EVOLUTION_API_KEY de .env), haz clic en Instance +, ponle el nombre de EVOLUTION_INSTANCIA (predeterminado loja), el canal Baileys, guarda, abre la instancia y lee el código QR con el WhatsApp del celular (Dispositivos vinculados → Vincular dispositivo).

ssh -L 8081:127.0.0.1:8081 usuario@vps
# sem o manager, pela API, na VPS:
curl -X POST http://127.0.0.1:8081/instance/create -H "apikey: <EVOLUTION_API_KEY>" \
  -H 'Content-Type: application/json' -d '{"instanceName":"loja","integration":"WHATSAPP-BAILEYS","qrcode":true}'
5

Webhook de Evolution

Evento MESSAGES_UPSERT para la dirección de abajo. Con el perfil evolution, compose ya apunta por la red interna; con una instancia de Evolution en otro servidor, completa EVOLUTION_URL en .env y configura allí el webhook. Los mensajes con remoteJid @lid usan el teléfono de remoteJidAlt/senderPn; si no está, aparecen en descartes en /gestor.

https://<domínio>/webhook/evolution/<WEBHOOK_SEGREDO>
6

Webhook de Telegram

Con el bot como administrador en el grupo del equipo (para fijar el panel), registra el webhook. El token y TELEGRAM_SEGREDO están en el .env generado por el instalador (grep TELEGRAM_ .env).

curl "https://api.telegram.org/bot<TOKEN>/setWebhook?url=https://<domínio>/webhook/telegram&secret_token=<TELEGRAM_SEGREDO>"
7

Respaldo diario: un solo cron

instalar-vps.sh ya lo instala en el crontab de root. Se ejecuta dentro del contenedor y copia fuera del volumen de datos, a una carpeta 700 con archivos 600 (el respaldo contiene datos personales), conservando 30 días.

0 3 * * * cd /opt/atende-leads && docker compose exec -T atende ./atende backup --dados /dados --saida /dados/.backup-cron.tar.gz && install -d -m 700 /opt/atende-leads-backups && f=/opt/atende-leads-backups/leads-$(date +\%F).tar.gz && mv /opt/atende-leads/dados/.backup-cron.tar.gz $f && chmod 600 $f && find /opt/atende-leads-backups -name 'leads-*.tar.gz' -mtime +30 -delete # atende-leads-backup
8

Restaurar

Detén el servicio antes: restaurar lo rechaza si el servidor está en funcionamiento.

docker compose stop atende
docker compose run --rm -v /opt/atende-leads-backups:/backups atende \
  ./atende restaurar --dados /dados --arquivo /backups/leads-AAAA-MM-DD.tar.gz
docker compose start atende

Los envíos a Telegram y WhatsApp salen por una bandeja de salida en segundo plano: si una API se bloquea, la atención y /api/saude siguen respondiendo. Por encima de 64 conexiones simultáneas (ATENDE_MAX_CONEXOES), el servidor responde 503, pero /api/saude responde incluso cuando está saturado. Para actualizar: git pull && sudo chown -R 1000:1000 dados && docker compose up -d --build.

Precauciones. Evolution no es la API oficial de WhatsApp: usa un número dedicado y no envíes mensajes masivos a personas que no se hayan comunicado contigo. Los datos de los leads quedan en tu servidor (dados/); el respaldo contiene datos personales, guárdalo con acceso restringido. La instancia de Evolution de compose no guarda copias de los mensajes ni de los contactos (LGPD). Quien tenga el token del administrador puede cambiar la dirección del cerebro en /gestor: por eso CEREBRO_API_KEY solo se envía a un host incluido en CEREBRO_HOSTS_PERMITIDOS en .env (vacío = la clave no se envía).
Pantallas

Cómo se ve en la práctica

Pantallas reales del sistema con datos de ejemplo (una escuela de idiomas ficticia, lunes a las 10 h). Las de Telegram se prepararon con los textos exactos que envió el sistema.

En el celular del lead

Chat web del lead: el agente pregunta qué busca, la urgencia y avisa al equipo
Chat del lead: el agente califica (qué busca y para cuándo) y avisa al equipo.
Página mi atención: Ana te está atendiendo
Página «mi atención»: quién te atiende, botón para hablar ahora y para borrar tus datos.
Panel EQUIPE AGORA fijado en el grupo de Telegram
Panel fijo EQUIPE AGORA en el grupo: estado de cada persona y la fila.

En el Telegram del equipo

Oferta en privado por Telegram con los botones Asumir, Pasar, Llamar y WhatsApp, y la tarjeta de atención con los botones de cierre
En privado: la oferta con datos y botones; después de asumirla, la tarjeta con los botones de cierre.
Grupo del equipo con líneas breves de los casos y dos alertas con el botón Asumir
En el grupo: una línea breve por caso y la alerta 🚨 cuando nadie asume. Sin teléfono.

En los paneles del equipo y del gestor

Panel del equipo: mi estado, ofertas y alertas, mis atenciones
/equipe: estado, ofertas y alertas, atenciones abiertas y devoluciones de llamada de hoy.
Ficha del lead con mensajes, respuesta al lead y formulario de cierre
Ficha del lead: historial, respuesta al lead y cierre con resultado.
Panel del gestor en vivo: equipo ahora, fila y personas atendiendo
/gestor en vivo: equipo, fila con alertas y quién está atendiendo, con transferencia.
Panel del gestor de hoy: leads nuevos, casos, ventas y valor vendido
/gestor hoy: leads nuevos, casos, ventas, valor vendido y cifras por colaborador.
Hoja de ruta

Qué queda fuera de la v1

La versión 1.7.8 hace lo que se describe arriba. Estas ideas quedaron para más adelante.

v1.7.8
HoyAgente basado en reglas, asignación por Telegram, alertas, panel fijo, cierre, tres paneles web, Docker y copia de seguridad. Base generada desde el sitio o un documento (con fuente y evidencia), chat con la base y botón Actualizar.
Próxima
Consulta en línea de la baseEl agente busca en el sitio del negocio en el momento, con caché y cita de la página, cuando la base no responde.
Después
Fuera de la v1Agente de voz automático · responder WhatsApp desde el panel · embudo arrastrable · CRM externo mediante webhook · metas y clasificación · varios números · API oficial de Meta · encuesta de satisfacción.