WhatsApp + Telegram · código aberto · v1.11.8

Nenhum lead fica esperando

Um agente atende no WhatsApp, qualifica e passa o lead para o colaborador livre há mais tempo, pelo Telegram, com tudo o que ele precisa para ligar.

A instalação no servidor pede um técnico: veja Deploy na VPS.

Banner do atende-leads: nenhum lead esperando, o agente atende no WhatsApp e chama quem está livre pelo Telegram
Em resumo

O atende-leads é um sistema de atendimento de leads (clientes em potencial) pelo WhatsApp, feito para pequenos negócios como loja, escola, imobiliária ou prestador de serviço. Um agente responde às dúvidas, pergunta o que a pessoa procura e dá uma nota ao lead: quente, morno ou frio. Quando ela pede uma pessoa ou mostra que quer comprar, o sistema avisa pelo Telegram o colaborador que está livre há mais tempo, com os dados e um botão para ligar. Para usar, você precisa de um servidor (VPS) com Docker, um domínio, um número de WhatsApp só para o atendimento e um bot do Telegram.

O que é

O agente atende, a equipe fecha

O agente cuida da primeira conversa. Quando há chance de venda ou alguém precisa de ajuda, o lead vai para uma pessoa da equipe, na vez certa, e ninguém fica esquecido na fila.

Do WhatsApp ao colaborador livre: agente no WhatsApp, qualifica e dá nota, colaborador livre, alerta no grupo, painel da equipe, fechamento

💬 Agente no WhatsApp

Responde o FAQ, mostra preço só do que está cadastrado, pergunta nome, o que procura e para quando, e dá a nota do lead (quente, morno ou frio). Funciona pela Evolution API.

🙋 Chama um humano na hora certa

Em 3 casos: o lead pede, o agente percebe que precisa (reclamação, problema, dois "não entendi") ou vê chance de venda (preço, "quero comprar", pagamento).

📨 Oferta pelo Telegram

Vai ao colaborador livre há mais tempo, no privado: nome, telefone, nota, interesse, resumo e últimas mensagens, com os botões ✅ Assumir · ↪️ Passar · 📞 Ligar · 💬 WhatsApp.

🚨 Alerta no grupo

Sem resposta em 2 min, a oferta passa ao próximo. Lead quente sem dono em 2 min (normal em 5) ou ninguém livre: alerta no grupo, e o primeiro que tocar em Assumir leva.

📌 Painel fixo da equipe

Uma mensagem fixada no grupo, EQUIPE AGORA, mostra quem está livre, atendendo, ocupado ou fora, e a fila de leads esperando. É editada a cada mudança.

✅ Fechamento com resultado

Vendeu (valor) · Retornar (data) · Negociando · Sem interesse (motivo) · Inválido, com nota em texto ou áudio (o áudio vira texto só com WHISPER_CMD configurado no .env). O colaborador volta ao fim da fila de livres.

🖥️ Três painéis web

Lead: chat, bolha para o site e página "meu atendimento". Equipe: /equipe. Gestor: /gestor, com ao vivo, hoje, leads, cadastros e exportação CSV.

🔒 LGPD

O lead pode mandar PARAR ou apagar meus dados. O grupo da equipe nunca recebe telefone nem texto do lead: só primeiro nome, motivo, nota e tempos.

🧠 Cérebro por regras

Por padrão o agente funciona por regras, sem custo e sem API. Opcional: Ollama local ou um endpoint compatível com OpenAI do próprio negócio, com volta às regras se falhar.

Como funciona

Do "oi" no WhatsApp ao fechamento

Cada lead segue o mesmo caminho. O sistema guarda tudo num banco SQLite no seu servidor.

Lead no WhatsApp ou no site→ Agente responde e qualifica→ Gatilho→ Oferta ao livre há mais tempo→ Alerta 🚨 se ninguém assume→ Colaborador assume e liga→ Fecha com resultado
1

Os 3 gatilhos

Pediu humano ("atendente", "me liga"), chance de venda ("quanto custa", "quero comprar", "orçamento") ou precisa de atenção ("problema", "reclamação", "cancelar").

2

A ordem de vez

Os colaboradores livres ficam em fila pelo horário em que ficaram livres. Quem fecha um atendimento volta ao fim da fila. Lead que volta em até 30 dias é oferecido primeiro a quem o atendeu.

3

Prazos

Oferta: 2 min. Alerta: 2 min para lead quente, 5 min para normal. Lembrete de atendimento parado: 30 min. Tudo ajustável no cadastro.

O processo, do início ao fim

13 passos, de quem instala a quem vende

Quem faz cada passo:

🧠 o dono ou gestor⚙️ o sistema🤖 o agente
1

Instalar na VPS 🧠 dono

O script pergunta nome, domínio e Telegram; gera segredos, o .env e o dados/negocio.json; sobe o Docker. No fim mostra o token do gestor: guarde, é a senha do /gestor. Detalhes em Deploy na VPS.

./instalar-vps.sh
2

Conectar o WhatsApp 🧠 dono

Abra um túnel até a VPS, entre no painel da Evolution em http://localhost:8081/manager, crie a instância e leia o QR Code com o número do atendimento. Use um número só para isso.

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

Cadastrar 🧠 gestor

Em /gestor → Cadastros: equipe (nome, telefone, código), produtos com palavras e preço, FAQ, horários e prazos.

4

A equipe entra no bot 🧠 equipe

Cada colaborador manda /entrar <código> no privado do bot e toca 🟢 Livre. O código de cada um é o que o instalador imprimiu (no teste local, o do negocio.json, como ana-1234).

/entrar <código>
5

O lead chega ⚙️ sistema

Pelo WhatsApp ou pela bolha de chat do site. Para pôr a bolha no seu site, cole esta linha antes do </body> das páginas:

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

O agente atende 🤖 agente

Responde o FAQ, informa o preço cadastrado, qualifica e dá a nota.

7

Gatilho ⚙️ sistema

Pediu humano, precisa de atenção ou chance de venda: abre o chamado e manda uma linha curta ao grupo, sem telefone.

8

Oferta ⚙️ sistema

Vai ao livre há mais tempo, no privado, com dados e botões. 2 min sem resposta: passa ao próximo.

9

Alerta 🚨 ⚙️ sistema

Mensagem no grupo quando estoura o prazo ou não há ninguém livre. O primeiro que tocar em Assumir leva.

10

O colaborador assume 🧠 equipe

Liga (📞), responde pelo WhatsApp (💬) ou responde no próprio bot, respondendo (reply) ao cartão do atendimento.

11

Fecha com o resultado 🧠 equipe · ⚙️ sistema

O colaborador escolhe o resultado; o sistema grava o histórico, agenda o retorno e devolve o colaborador à fila.

12

O gestor acompanha 🧠 gestor

Em /gestor: ao vivo, hoje, leads e exportar CSV.

13

Backup diário ⚙️ cron

Uma cópia do banco e do cadastro por dia, pelo cron único que o instalar-vps.sh instala, guardada em /opt/atende-leads-backups/.

docker compose exec -T atende ./atende backup ...
Pré-requisitos

O que você precisa ter

Para testar no seu computador basta o Python 3. Para usar de verdade, com WhatsApp e Telegram, você precisa do resto.

🐍 Python 3

Só a biblioteca padrão: nada de pip install para rodar. Para rodar os testes, o pytest.

python3 --version

🐳 VPS com Docker

Um servidor Linux com Docker e Docker Compose. O app escuta só em 127.0.0.1:8080.

docker compose version

🌐 Domínio com HTTPS

Um proxy reverso (Caddy ou Nginx) do seu domínio para 127.0.0.1:8080. Os webhooks precisam de HTTPS.

📱 Número de WhatsApp

Um número só para o atendimento, conectado pela Evolution API. Ela pode subir no mesmo compose (perfil evolution).

✈️ Bot do Telegram

Crie o bot no @BotFather e ponha no grupo da equipe como administrador, para ele fixar o painel.

👥 A equipe

Cada colaborador com Telegram e um código pessoal, que serve para o /entrar e para o painel /equipe.

📖 Palavras que aparecem neste guia

  • Lead: pessoa que entrou em contato e pode virar cliente.
  • FAQ: lista de perguntas frequentes com a resposta pronta que o agente usa.
  • Chamado: o pedido de atendimento humano aberto para um lead.
  • VPS: servidor alugado na internet, onde o sistema fica ligado o tempo todo.
  • Evolution API: programa que conecta um número de WhatsApp ao sistema (não é a API oficial da Meta). Cada número conectado nela é uma instância; Baileys é o modo de conexão pelo QR Code.
  • SQLite: banco de dados num arquivo só (dados/leads.db), sem servidor à parte.
  • Ollama: programa que roda modelos de IA no próprio computador ou servidor, opcional aqui.
  • Perfil do compose: grupo de serviços do docker-compose.yml que só sobe quando pedido, como --profile evolution.
  • Webhook: endereço do seu sistema que o WhatsApp (Evolution) e o Telegram chamam quando chega mensagem.
  • Proxy reverso: programa (Caddy ou Nginx) que recebe o acesso pelo seu domínio com HTTPS e repassa ao sistema.
  • Cron: agendador do Linux que roda um comando todo dia na mesma hora.
  • Token do gestor: senha do painel /gestor; nas chamadas à API vai no cabeçalho X-Token.
Guia de uso · passo a passo

Teste no seu computador em 5 minutos

Sem WhatsApp e sem Telegram configurados, as integrações ficam desligadas e os painéis web funcionam. É o jeito mais rápido de ver o sistema.

1

Baixe o projeto

Clone o repositório e entre na pasta.

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

Suba o servidor

Na primeira vez, o sistema copia o exemplos/negocio.json para a pasta de dados. Se a porta 8080 estiver ocupada no seu computador, use outra (por exemplo --porta 8090) e troque nos endereços dos passos seguintes.

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

Abra as três telas

Chat do lead em http://localhost:8080/, equipe em /equipe (entra com o código do colaborador) e gestor em /gestor (entra com o token_gestor do dados/negocio.json).

# no exemplo, o token do gestor é TROQUE-ESTE-TOKEN e o código da Ana é ana-1234
grep -E '"token_gestor"|"codigo"' dados/negocio.json
4

Cadastre o seu negócio

Pelo /gestor → Cadastros, ou editando o dados/negocio.json. O agente só fala preço que estiver aqui. O arquivo vem com dados de exemplo (a colaboradora Ana, o "Plano anual", um FAQ de loja): troque pelos seus antes de receber leads de verdade.

{
  "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

Teste com o relógio parado

Com ATENDE_AGORA o "agora" fica fixo, e você roda as tarefas de tempo (ofertas vencidas, alertas, lembretes) quando quiser. Pare antes o servidor do passo 2 (Ctrl+C) e rode o curl num segundo terminal, porque o serve ocupa o primeiro.

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

Rode os testes

São 320 testes de contrato. O build e o container Docker só entram com TESTAR_DOCKER=1.

python3 -m pytest -q tests/

Comandos do bot no Telegram

No privado do bot

  • /entrar <código> liga o seu Telegram ao seu cadastro
  • /livre · /ocupado · /fora mudam o seu status
  • /meus seus atendimentos · /retornos retornos de hoje
  • /lead <nome ou telefone> ficha curta
  • /fechar <id> vendeu <valor> (ou retornar, negociando, sem, invalido)

No grupo da equipe

  • /status manda o painel EQUIPE AGORA (só no grupo da equipe)
  • Linhas curtas de cada chamado e os alertas 🚨 com o botão ✅ Assumir
  • Nunca telefone nem texto do lead
Deploy na VPS

No ar com Docker

Variáveis em .env.exemplo. Sem as variáveis de uma integração, ela fica desligada e o resto funciona (painéis web).

1

Subir

Antes de instalar: crie o bot no @BotFather e ponha no grupo da equipe. O instalador pede o token do bot e o ID do grupo (número que começa com -100). Para achar o ID, mande no grupo um comando para o bot, como /start@nome_do_bot (no modo de privacidade padrão, mensagem comum não chega ao bot), e abra o endereço abaixo; o chat.id do grupo aparece na resposta. Faça isso antes de registrar o webhook (passo 6), porque depois o getUpdates deixa de responder.

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

Na VPS, como root (ou com sudo), com git, python3 e Docker instalados, clone o projeto e rode o instalador. Ele gera o .env e o dados/negocio.json só para o dono (umask 077), o token do gestor e os códigos da equipe (aleatórios), passa a pasta dados/ ao uid 1000 (o container não roda como root; sem ser root, tenta sudo -n chown e, se não conseguir, para antes de subir e mostra o comando), sobe o compose, com ou sem a Evolution, instala o cron do backup e imprime tudo no fim: guarde. Rodar de novo (mudar o domínio, ligar o Telegram) não troca os segredos: os que já estão no .env são reaproveitados e a saída diz quais; só os que faltam são gerados (uma senha nova do Postgres derrubaria a Evolution, e um TELEGRAM_SEGREDO novo faria o webhook do Telegram dar 401). O cadastro parte do exemplo (a colaboradora Ana, o "Plano anual", um FAQ de loja): troque pelos seus em /gestor → Cadastros antes de receber leads. A aplicação escuta só em 127.0.0.1:8080 e a Evolution em 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

Segredos de exemplo não sobem na rede

Se o negocio.json ainda tem token_gestor = TROQUE-ESTE-TOKEN ou algum código igual ao do exemplos/negocio.json, ou se uma integração está ligada com WEBHOOK_SEGREDO/TELEGRAM_SEGREDO vazio, com menos de 16 caracteres ou contendo troque (ou com EVOLUTION_API_KEY contendo troque), o servidor só aceita subir em 127.0.0.1/localhost. Em 0.0.0.0 (como no Docker) ele recusa com a mensagem "rode ./instalar-vps.sh ou troque os segredos". Só para teste ou demonstração existe ATENDE_PERMITIR_EXEMPLO=1 (nunca em produção).

3

HTTPS

Proxy reverso (Caddy ou Nginx) do seu domínio para 127.0.0.1:8080. O instalador já preenche url_publica no negocio.json com o domínio; confira. Os limites por IP (5 senhas erradas por minuto: as erradas recebem 429, a certa sempre passa; 5 conversas novas do chat web em 10 min, além de um teto no total; 3 pedidos de atendimento pelo web por hora) usam o IP do X-Forwarded-For só quando a conexão vem de um proxy confiável: ATENDE_PROXY_CONFIAVEL (CIDRs; o padrão cobre o loopback e as redes privadas, por onde o Caddy no host chega ao container). Vazio = nunca confiar no X-Forwarded-For. Quem assume um lead é só o colaborador a quem ele foi ofertado ou, em alerta 🚨, quem tocar primeiro em Assumir.

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

WhatsApp: ler o QR Code

A porta da Evolution só escuta em 127.0.0.1, então abra um túnel do seu computador e, com ele aberto, acesse http://localhost:8081/manager. Entre com a API Key global (EVOLUTION_API_KEY do .env), clique em Instance +, dê o nome de EVOLUTION_INSTANCIA (padrão loja), canal Baileys, salve, abra a instância e leia o QR Code pelo WhatsApp do celular (Aparelhos conectados → Conectar aparelho).

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 da Evolution

Evento MESSAGES_UPSERT para o endereço abaixo. Com o perfil evolution, o compose já aponta pela rede interna; com uma Evolution em outro servidor, preencha EVOLUTION_URL no .env e configure o webhook nela. Mensagens com remoteJid @lid usam o telefone de remoteJidAlt/senderPn; sem ele, aparecem em descartes no /gestor.

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

Webhook do Telegram

Com o bot no grupo da equipe como administrador (para fixar o painel), registre o webhook. O token e o TELEGRAM_SEGREDO estão no .env gerado pelo instalador (grep TELEGRAM_ .env).

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

Backup diário: um único cron

O instalar-vps.sh já instala no crontab do root. Roda dentro do container e copia para fora do volume de dados, numa pasta 700 com arquivos 600 (o backup tem dados pessoais), guardando 30 dias.

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

Pare o serviço antes: o restaurar recusa com o servidor no ar.

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

Envios ao Telegram e ao WhatsApp saem por uma caixa de saída em segundo plano: se uma API travar, o atendimento e o /api/saude continuam respondendo. Acima de 64 conexões ao mesmo tempo (ATENDE_MAX_CONEXOES) o servidor responde 503, mas o /api/saude responde mesmo lotado. Para atualizar: git pull && sudo chown -R 1000:1000 dados && docker compose up -d --build.

Cuidados. A Evolution não é a API oficial do WhatsApp: use um número dedicado e não faça disparo em massa para quem não falou com você. Os dados dos leads ficam no seu servidor (dados/); o backup contém dados pessoais, guarde com acesso restrito. A Evolution do compose não guarda cópia das mensagens nem dos contatos (LGPD). Quem tem o token do gestor pode mudar o endereço do cérebro no /gestor: por isso a CEREBRO_API_KEY só vai a um host listado em CEREBRO_HOSTS_PERMITIDOS no .env (vazio = a chave não é enviada).
Telas

Como fica na prática

Telas reais do sistema rodando com dados de exemplo (uma escola de idiomas fictícia, segunda-feira 10h). As do Telegram foram montadas com os textos exatos que o sistema enviou.

No celular do lead

Chat web do lead: o agente pergunta o que procura, a urgência e chama a equipe
Chat do lead: o agente qualifica (o que procura, para quando) e chama a equipe.
Página meu atendimento: Ana está te atendendo
Página "meu atendimento": quem atende, botão para falar agora e para apagar os dados.
Painel EQUIPE AGORA fixado no grupo do Telegram
Painel fixo EQUIPE AGORA no grupo: status de cada um e a fila.

No Telegram da equipe

Oferta no privado do Telegram com os botões Assumir, Passar, Ligar e WhatsApp, e o cartão do atendimento com os botões de fechamento
No privado: a oferta com dados e botões; depois de assumir, o cartão com os botões de fechamento.
Grupo da equipe com as linhas curtas dos chamados e dois alertas com o botão Assumir
No grupo: uma linha curta por chamado e o alerta 🚨 quando ninguém assume. Sem telefone.

No painel da equipe e do gestor

Painel da equipe: meu status, ofertas e alertas, meus atendimentos
/equipe: status, ofertas e alertas, atendimentos abertos e retornos de hoje.
Ficha do lead com mensagens, resposta ao lead e formulário de fechamento
Ficha do lead: histórico, resposta ao lead e fechamento com resultado.
Painel do gestor ao vivo: equipe agora, fila e em atendimento
/gestor ao vivo: equipe, fila com alertas e quem está atendendo, com transferência.
Painel do gestor hoje: leads novos, chamados, vendas e valor vendido
/gestor hoje: leads novos, chamados, vendas, valor vendido e números por colaborador.
Roteiro

O que fica fora da v1

A versão 1.11.8 faz o que está descrito acima. Estas ideias ficaram para depois.

v1.11.8
HojeAgente por regras, roteamento pelo Telegram, alerta, painel fixo, fechamento, três painéis web, Docker e backup. Base gerada do site ou de um documento (com fonte e evidência), chat com a base, botão Atualizar e gestor ao vivo em quatro grupos (robô, espera, atendimento, encerradas) com alerta de cliente sem resposta. Robô discreto (só fala que chamou alguém quando o cliente pede; chance de venda chama a equipe em silêncio), cliente quente em vermelho com bip e cadastro do atendente com aprovação do gestor.
Próxima
Consulta online da baseO agente busca no site do negócio na hora, com cache e citação da página, quando a base não responde.
Depois
Fora da v1Agente de voz automático · responder o WhatsApp pelo painel · funil arrastável · CRM externo por webhook · metas e ranking · vários números · API oficial da Meta · pesquisa de satisfação.