Voltar ao blog

15 Erros Comuns ao Configurar Chatbot e Como Resolver

Guia de troubleshooting para os problemas mais frequentes em chatbots: webhooks, timeouts, encoding, rate limits e mais.

RS
Richard Sakaguchi Solution Architect
15 Erros Comuns ao Configurar Chatbot e Como Resolver

Configurou o chatbot e nao funciona? Este guia cobre os 15 erros mais comuns e como resolver cada um.

1. Webhook Nao Recebe Mensagens

Sintoma: Voce envia mensagem pro bot mas o webhook nao recebe nada.

Causas comuns:

1.1 URL nao e HTTPS

A maioria das plataformas exige HTTPS. HTTP simples nao funciona.

Solucao:

# Instalar certbot (Let's Encrypt)
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d seudominio.com

1.2 Firewall bloqueando

Verificar:

# Testar se porta esta aberta
curl -I https://seusite.com/webhook

# Ver regras de firewall
sudo ufw status

Solucao:

sudo ufw allow 443
sudo ufw allow 80

1.3 Verificacao do webhook falhou

Meta, Telegram e outras plataformas fazem GET de verificacao antes de enviar mensagens.

Debug:

app.get('/webhook', (req, res) => {
  console.log('Query params:', req.query);  // Debug
  // ... resto do codigo
});

2. Mensagem Enviada Mas Nao Entregue

Sintoma: API retorna sucesso mas mensagem nao chega.

2.1 Numero em formato errado

Errado:

(11) 99999-9999
11999999999
+55 11 99999-9999

Correto:

5511999999999

Funcao de normalizacao:

function normalizePhone(phone) {
  // Remove tudo que nao e numero
  let clean = phone.replace(/\D/g, '');

  // Adiciona 55 se nao tem
  if (!clean.startsWith('55')) {
    clean = '55' + clean;
  }

  // Remove 9 extra se tiver 14 digitos
  if (clean.length === 14 && clean[4] === '9') {
    clean = clean.slice(0, 4) + clean.slice(5);
  }

  return clean;
}

2.2 Numero nao tem WhatsApp

Verificar antes de enviar:

async function checkWhatsAppNumber(phone) {
  const url = `https://graph.facebook.com/v18.0/${phoneNumberId}/contacts`;

  const response = await axios.post(url, {
    blocking: 'wait',
    contacts: [phone],
    force_check: true
  }, {
    headers: { Authorization: `Bearer ${token}` }
  });

  return response.data.contacts[0].status === 'valid';
}

3. Timeout no Webhook

Sintoma: Plataforma marca webhook como falho.

3.1 Processamento muito demorado

Webhook precisa responder em 20 segundos (Meta) ou 10 segundos (Telegram).

Solucao - Responder primeiro, processar depois:

app.post('/webhook', async (req, res) => {
  // Responde IMEDIATAMENTE
  res.sendStatus(200);

  // Processa em background
  setImmediate(async () => {
    try {
      await processMessage(req.body);
    } catch (error) {
      console.error('Erro no processamento:', error);
    }
  });
});

Solucao com fila (recomendado para producao):

const Queue = require('bull');
const messageQueue = new Queue('messages', 'redis://localhost:6379');

app.post('/webhook', (req, res) => {
  res.sendStatus(200);
  messageQueue.add(req.body);
});

messageQueue.process(async (job) => {
  await processMessage(job.data);
});

4. Caracteres Estranhos na Mensagem

Sintoma: Acentos viram simbolos estranhos.

4.1 Encoding errado

Headers corretos:

res.set('Content-Type', 'application/json; charset=utf-8');

Body parser configurado:

app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));

4.2 Banco de dados sem UTF-8

MySQL:

ALTER DATABASE seu_banco CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE mensagens CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Conexao:

const connection = mysql.createConnection({
  charset: 'utf8mb4'
});

5. Rate Limit Excedido

Sintoma: Erro 429 ou mensagens nao enviadas.

5.1 Enviando rapido demais

Implementar rate limiting:

const Bottleneck = require('bottleneck');

const limiter = new Bottleneck({
  reservoir: 80,           // 80 requisicoes
  reservoirRefreshAmount: 80,
  reservoirRefreshInterval: 1000,  // por segundo
  maxConcurrent: 10
});

async function sendMessageSafe(to, text) {
  return limiter.schedule(() => sendMessage(to, text));
}

5.2 Muitas conexoes simultaneas

Pool de conexoes:

const https = require('https');

const agent = new https.Agent({
  keepAlive: true,
  maxSockets: 50,
  maxFreeSockets: 10
});

axios.create({
  httpsAgent: agent
});

6. Mensagens Duplicadas

Sintoma: Bot responde duas ou mais vezes.

6.1 Webhook chamado multiplas vezes

Plataformas reenviam se nao recebem 200 OK rapido.

Solucao - Idempotencia:

const processedMessages = new Set();

app.post('/webhook', (req, res) => {
  res.sendStatus(200);  // Responde rapido

  const messageId = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]?.id;

  if (!messageId || processedMessages.has(messageId)) {
    return;  // Ja processou ou invalido
  }

  processedMessages.add(messageId);

  // Limpar cache antigo (evitar memory leak)
  if (processedMessages.size > 10000) {
    const toDelete = [...processedMessages].slice(0, 5000);
    toDelete.forEach(id => processedMessages.delete(id));
  }

  processMessage(req.body);
});

Com Redis (producao):

const redis = require('redis');
const client = redis.createClient();

async function isProcessed(messageId) {
  const exists = await client.exists(`msg:${messageId}`);
  if (exists) return true;

  await client.setEx(`msg:${messageId}`, 3600, '1');  // Expira em 1h
  return false;
}

7. Bot Nao Responde Mensagens de Grupo

Sintoma: Funciona no privado, falha em grupos.

7.1 Falta permissao de grupo

Telegram - BotFather:

/setprivacy -> Disable

7.2 Mensagem nao e direta

Verificar se e mencao ou resposta:

// Telegram
if (message.chat.type !== 'private') {
  // Grupo - verificar se foi mencionado
  const botUsername = 'seu_bot';
  if (!message.text?.includes(`@${botUsername}`)) {
    return;  // Ignorar mensagens nao direcionadas
  }
}

8. Sessao Perdida (Estado do Usuario)

Sintoma: Bot esquece contexto da conversa.

8.1 Estado em memoria

Se o servidor reinicia, perde tudo.

Solucao - Persistir estado:

// Redis
const sessions = {};

async function getSession(userId) {
  let session = await redis.get(`session:${userId}`);
  return session ? JSON.parse(session) : { step: 'inicio' };
}

async function setSession(userId, data) {
  await redis.setEx(`session:${userId}`, 86400, JSON.stringify(data));  // 24h
}

// Uso
app.post('/webhook', async (req, res) => {
  const userId = getUserId(req.body);
  const session = await getSession(userId);

  const newSession = await processWithSession(req.body, session);
  await setSession(userId, newSession);

  res.sendStatus(200);
});

9. Erro de Assinatura/Token

Sintoma: Erro 401 ou 403.

9.1 Token expirado

Tokens temporarios da Meta expiram em 24h.

Solucao: Criar System User e gerar token permanente.

9.2 Assinatura invalida (Telegram)

Verificar assinatura:

const crypto = require('crypto');

function verifyTelegramSignature(body, signature) {
  const secret = crypto
    .createHash('sha256')
    .update(BOT_TOKEN)
    .digest();

  const checkHash = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(body))
    .digest('hex');

  return checkHash === signature;
}

10. Imagens/Arquivos Nao Enviam

Sintoma: Texto funciona, midia falha.

10.1 URL nao e publica

A URL da midia precisa ser acessivel publicamente.

Verificar:

curl -I https://seusite.com/imagem.jpg
# Deve retornar 200 OK

10.2 Formato nao suportado

WhatsApp aceita:

  • Imagem: JPG, PNG (max 5MB)
  • Video: MP4 (max 16MB)
  • Audio: OGG, MP3 (max 16MB)
  • Documento: PDF, DOC, etc (max 100MB)

Se URL nao funciona, faça upload primeiro:

async function uploadMedia(filePath, type) {
  const form = new FormData();
  form.append('file', fs.createReadStream(filePath));
  form.append('messaging_product', 'whatsapp');
  form.append('type', type);

  const response = await axios.post(
    `https://graph.facebook.com/v18.0/${phoneNumberId}/media`,
    form,
    {
      headers: {
        ...form.getHeaders(),
        Authorization: `Bearer ${token}`
      }
    }
  );

  return response.data.id;  // media_id
}

// Enviar usando media_id
async function sendImageById(to, mediaId, caption) {
  return axios.post(url, {
    messaging_product: 'whatsapp',
    to: to,
    type: 'image',
    image: {
      id: mediaId,
      caption: caption
    }
  }, { headers });
}

11. Mensagem Marcada Como Spam

Sintoma: Conta bloqueada ou limitada.

11.1 Enviando sem consentimento

Sempre use opt-in explicito.

11.2 Muitas mensagens de marketing

Mantenha proporcao: 80% utilitarias, 20% marketing.

11.3 Template rejeitado

Nao use linguagem promocional excessiva nos templates.

12. Latencia Alta

Sintoma: Demora segundos pra responder.

12.1 Consultas ao banco lentas

Adicionar indices:

CREATE INDEX idx_user_id ON messages(user_id);
CREATE INDEX idx_created_at ON messages(created_at);

12.2 API externa lenta

Cache respostas:

const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 300 });  // 5 min

async function getProductInfo(productId) {
  const cached = cache.get(`product:${productId}`);
  if (cached) return cached;

  const data = await fetchFromAPI(productId);
  cache.set(`product:${productId}`, data);
  return data;
}

13. Bot Para de Funcionar Sozinho

Sintoma: Funciona por horas/dias e para.

13.1 Memory leak

Monitorar memoria:

setInterval(() => {
  const used = process.memoryUsage();
  console.log(`Heap: ${Math.round(used.heapUsed / 1024 / 1024)}MB`);
}, 60000);

13.2 Conexoes nao fechadas

Fechar conexoes:

// Database
pool.on('error', (err) => {
  console.error('Database error:', err);
});

// HTTP
const agent = new https.Agent({
  keepAlive: true,
  timeout: 30000
});

13.3 Usar process manager

# PM2
npm install -g pm2
pm2 start app.js --name "chatbot"
pm2 save
pm2 startup

14. Logs Confusos

Sintoma: Nao consegue debugar problemas.

14.1 Estruturar logs

const winston = require('winston');

const logger = winston.createLogger({
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

// Uso
logger.info('Mensagem recebida', {
  userId: message.from,
  type: message.type,
  timestamp: new Date()
});

logger.error('Erro ao enviar', {
  error: error.message,
  stack: error.stack,
  to: recipient
});

15. Teste Local Dificil

Sintoma: Precisa deploy pra testar.

15.1 Usar ngrok

# Instalar
npm install -g ngrok

# Expor porta local
ngrok http 3000

# Copiar URL https e configurar no webhook

15.2 Simulador de webhook

// test/webhook.test.js
const request = require('supertest');
const app = require('../src/app');

describe('Webhook', () => {
  it('deve processar mensagem de texto', async () => {
    const payload = {
      object: 'whatsapp_business_account',
      entry: [{
        changes: [{
          field: 'messages',
          value: {
            messages: [{
              from: '5511999999999',
              type: 'text',
              text: { body: 'Oi' }
            }],
            metadata: { phone_number_id: '123' }
          }
        }]
      }]
    };

    const res = await request(app)
      .post('/webhook')
      .send(payload);

    expect(res.status).toBe(200);
  });
});

Checklist de Debug

Quando algo nao funciona:

  1. Verificar logs do servidor
  2. Testar webhook com curl/Postman
  3. Verificar formato do payload
  4. Confirmar credenciais/tokens
  5. Testar com ngrok localmente
  6. Verificar rate limits
  7. Checar status da plataforma (status.fb.com)

Sakaguchi IA - Inteligencia Artificial para Empresas Brasileiras

Sakaguchi IA

Precisa colocar isso em produção?

Engenharia de software, IA aplicada e cibersegurança para empresas que operam de verdade. Fale com nosso time.

Falar com a equipe