Como criar um bot de WhatsApp com a API não oficial (do zero ao menu com botões)
Crie um bot de WhatsApp com a API não oficial: webhook em Node.js, máquina de estados, menu com lista e botões, 'digitando...' e passagem para humano.
Para criar um bot de WhatsApp com a API não oficial, você conecta o número a uma instância da WAME por QR Code, aponta o webhook para o seu servidor e, a cada mensagem recebida, decide a resposta com uma máquina de estados — enviando texto, listas e botões pelos endpoints /message/text, /message/list e /message/button_reply. Sem cadastro de app na Meta, sem template pré-aprovado e sem janela de 24 horas: o bot responde com texto livre, na hora.
Este guia monta um bot de atendimento completo em Node.js, do zero: recebe a mensagem, mostra um menu, segue o fluxo de acordo com a escolha, simula "digitando..." e passa para um humano quando precisa. É um bot de regras — previsível, barato e suficiente para a maior parte do atendimento repetitivo. Se você quer respostas geradas por IA, o chatbot com a API da OpenAI parte da mesma base.
Por que a API não oficial é boa para bots
- Começa em minutos. Crie a instância, leia o QR Code em Aparelhos conectados e o número já está pronto. Prefere não usar QR? Há o código de pareamento.
- Texto livre sempre. Nada de template aprovado para iniciar ou retomar conversa — detalhes em API do WhatsApp sem template.
- Recursos ricos: listas, botões, enquetes, reações, figurinhas, grupos. Veja todos em recursos da API não oficial.
- Hospedada e gerenciada. Diferente de rodar Baileys no seu servidor, a WAME cuida da sessão, da reconexão e da infraestrutura — 99,9% de uptime, suporte 24/7 em português, plataforma no ar desde 2017.
Uma observação honesta: a camada não oficial não é afiliada nem endossada pelo WhatsApp ou pela Meta, e o uso é de responsabilidade de quem opera o número.
Passo 1: conectar e configurar o webhook
Gere o QR Code da instância:
curl -X POST "https://us.api-wa.me/SUA_KEY/instance"Depois de escanear, configure para onde vão os eventos. Use o formato meta, que entrega tudo no envelope da Cloud API:
curl -X PUT "https://us.api-wa.me/SUA_KEY/instance" \
-H "Content-Type: application/json" \
-d '{
"allowWebhook": true,
"allowNumber": "all",
"webhookMessage": "https://seu-servidor.com/webhook/wame",
"webhookFormat": "meta"
}'Em desenvolvimento, exponha a porta local com ngrok ou similar.
Passo 2: receber e extrair a mensagem
O evento chega assim:
{
"object": "wame",
"provider": "whatsapp",
"entry": [{
"changes": [{
"field": "messages",
"value": {
"messages": [{
"from": "5511999999999",
"id": "wamid.XXXX",
"type": "text",
"text": { "body": "oi" }
}]
}
}]
}]
}Um extrator com as guardas que evitam loop e erro:
function extrair(body) {
const msg = body?.entry?.[0]?.changes?.[0]?.value?.messages?.[0];
if (!msg) return null; // status de entrega também chega aqui
// Texto digitado ou escolha de lista/botão.
// Os campos da resposta interativa estão descritos em /docs.
const texto = msg.text?.body ?? msg.interactive?.list_reply?.id
?? msg.interactive?.button_reply?.id;
if (!texto) return null;
return { de: msg.from, id: msg.id, texto: String(texto).trim() };
}Passo 3: a máquina de estados
O erro clássico de bot é um amontoado de if que não sabe em que ponto da conversa o cliente está. A solução é guardar um estado por contato e ter uma função por estado:
const sessoes = new Map(); // em produção: Redis ou banco
const fluxo = {
inicio: async (c) => {
await enviarMenu(c.de);
return 'menu';
},
menu: async (c) => {
switch (c.texto) {
case 'pedido':
await enviarTexto(c.de, 'Me passa o número do pedido, por favor.');
return 'aguardando_pedido';
case 'boleto':
await enviarTexto(c.de, 'Qual o CPF ou CNPJ do cadastro?');
return 'aguardando_documento';
case 'humano':
await enviarTexto(c.de, 'Certo! Já chamo alguém da equipe. 🙋');
await avisarEquipe(c.de);
return 'humano';
default:
await enviarMenu(c.de);
return 'menu';
}
},
aguardando_pedido: async (c) => {
const status = await consultarPedido(c.texto); // seu sistema
await enviarTexto(c.de, status ?? 'Não achei esse pedido. Confere o número?');
return status ? 'inicio' : 'aguardando_pedido';
},
aguardando_documento: async (c) => {
const link = await gerarSegundaVia(c.texto); // seu sistema
await enviarTexto(c.de, link ? `Aqui está: ${link}` : 'Não encontrei esse documento.');
return 'inicio';
},
humano: async () => 'humano', // bot em silêncio até a equipe liberar
};Cada estado recebe a mensagem, faz o que precisa e devolve o próximo estado. Adicionar um fluxo novo é adicionar uma função, sem mexer nas outras.
Passo 4: o menu com lista
Para mais de três opções, a lista é melhor que botões:
const BASE = 'https://us.api-wa.me/SUA_KEY';
async function post(caminho, corpo) {
const r = await fetch(`${BASE}${caminho}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(corpo),
});
if (!r.ok) throw new Error(`${caminho} ${r.status}`);
}
const enviarTexto = (to, text) => post('/message/text', { to, text });
const enviarMenu = (to) =>
post('/message/list', {
to,
title: 'Atendimento',
text: 'Como posso ajudar?',
buttonText: 'Ver opções',
footer: 'Responda a qualquer momento',
sections: [{
title: 'Opções',
rows: [
{ title: 'Status do pedido', rowId: 'pedido' },
{ title: 'Segunda via de boleto', rowId: 'boleto' },
{ title: 'Falar com atendente', rowId: 'humano' },
],
}],
});Para decisões curtas (sim/não, confirmar/cancelar), use botões de resposta rápida:
const confirmar = (to) =>
post('/message/button_reply', {
to,
header: { title: 'Confirmação' },
text: 'Posso agendar para amanhã às 10h?',
buttons: [
{ type: 'quick_reply', id: 'sim', text: 'Pode sim' },
{ type: 'quick_reply', id: 'nao', text: 'Outro horário' },
],
});Os rowId e id são o que volta no webhook quando o cliente escolhe — por isso o estado menu compara com 'pedido', 'boleto' e 'humano'.
O detalhe da primeira mensagem
Um comportamento pouco conhecido: o WhatsApp do destinatário não mostra botões nem listas na primeira mensagem de uma conversa que nunca existiu. Se o bot inicia o contato mandando um menu, o cliente pode não ver nada. A solução é abrir com um texto antes do menu: uma mensagem normal já basta, e o menu seguinte chega certo. Em conversas iniciadas pelo cliente, como neste bot, a questão nem aparece.
Passo 5: parecer gente (digitando e lido)
Resposta em 0 milissegundos tem cara de robô — para o cliente e para o WhatsApp. Antes de responder, marque como lida e mostre "digitando...":
async function prepararResposta(to, messageId) {
await post('/message/read', { messageId });
await post('/message/presence', { to, status: 'composing' });
await new Promise((r) => setTimeout(r, 1200));
}A WAME já aplica um ritmo humano de leitura e digitação por trás de cada instância, proporcional ao tamanho do texto; o trecho acima é para quando você quer controlar isso explicitamente. Mais em como simular "digitando..." pela API.
Passo 6: juntar tudo no webhook
import express from 'express';
const app = express();
app.use(express.json());
app.post('/webhook/wame', async (req, res) => {
res.sendStatus(200); // responda já; o processamento vem depois
const c = extrair(req.body);
if (!c) return;
const estado = sessoes.get(c.de) ?? 'inicio';
if (estado === 'humano') return; // atendente no comando
try {
await prepararResposta(c.de, c.id);
const proximo = await fluxo[estado](c);
sessoes.set(c.de, proximo);
} catch (e) {
console.error('falha no bot', c.de, e);
await enviarTexto(c.de, 'Tive um problema aqui. Já chamo alguém da equipe.');
sessoes.set(c.de, 'humano');
}
});
app.listen(3000);Quando o atendente terminar, seu painel volta o estado do contato para inicio e o bot reassume. Se vários atendentes dividem o mesmo número, veja multiatendimento no mesmo número.
Checklist antes de colocar no ar
- Idempotência: o mesmo evento pode chegar duas vezes. Guarde os
idjá processados — veja webhook em produção. - Estado persistente: o
Mapem memória some no deploy. Use Redis ou banco. - Saída sempre visível: toda tela do bot precisa de um caminho para humano.
- Palavra de saída: se alguém escrever "sair" ou "parar", respeite e registre — opt-out vale para bot também.
- Tempo de sessão: se o cliente some por horas no meio de um fluxo, volte para
iniciona próxima mensagem.
Bot e bloqueio: o que realmente importa
Um bot que responde a quem escreveu é o uso mais seguro possível da API não oficial — e é por isso que a taxa de bloqueio nesse cenário é muito baixa quando o número é usado do jeito certo. Além do comportamento, a WAME protege cada instância com identidade de dispositivo própria e coerente com o país do número, limites de ritmo, reconexão espaçada e um monitor de saúde que pausa envios ao primeiro sinal de problema.
Onde o bot vira risco é quando ele passa a iniciar conversas em massa com quem nunca pediu. Isso é spam, e a WAME não apoia. Se o seu projeto precisa de campanhas, comece pela lista com opt-in e pelo controle de ritmo.
Conclusão
Criar um bot de WhatsApp com a API não oficial é juntar quatro peças: conexão por QR Code, webhook no formato meta, uma máquina de estados com uma função por etapa e respostas com lista, botões e texto livre. Some a isso "digitando...", passagem para humano e idempotência, e o bot está pronto para produção — sem aprovação da Meta, sem template e sem cobrança por mensagem. Quando as perguntas ficarem abertas demais para um menu, é hora de plugar IA na mesma estrutura. Todos os endpoints estão na documentação.
Pronto para automatizar seu WhatsApp?
Crie sua conta gratuita e comece a enviar mensagens pela API em minutos.
Começar grátisPerguntas frequentes
Como criar um bot de WhatsApp com a API não oficial?+
Conecte seu número a uma instância da WAME por QR Code ou código de pareamento, configure a URL do seu servidor como webhook e, a cada mensagem recebida, decida a resposta com uma máquina de estados. As respostas saem por endpoints como /message/text, /message/list e /message/button_reply.
Preciso de aprovação da Meta ou de templates para o bot?+
Não. Na API não oficial o bot envia texto livre, listas e botões sem cadastro de app na Meta e sem templates pré-aprovados. A camada não oficial não é afiliada ao WhatsApp e o uso é de responsabilidade de quem opera o número.
Por que meus botões não aparecem na primeira mensagem?+
O WhatsApp do destinatário não renderiza mensagens interativas (botões e listas) na primeira mensagem de uma conversa que nunca existiu. A solução é abrir a conversa com um texto antes do menu: uma mensagem normal já basta, e em conversas iniciadas pelo cliente o problema não aparece.
O bot precisa ser feito com inteligência artificial?+
Não. Um bot de regras com menu resolve a maior parte do atendimento repetitivo (segunda via, horário, status de pedido) de forma previsível e barata. IA entra quando as perguntas são abertas demais para um menu.
Como passo a conversa do bot para um atendente?+
Tenha um estado 'humano' na máquina de estados. Quando o cliente escolhe falar com alguém, o bot avisa, marca a conversa e para de responder aquele número até o atendente encerrar o atendimento.
Continue lendo
Bot de comandos para grupo de WhatsApp (!menu, !regras) com a API não oficial
Monte um bot de comandos para grupo de WhatsApp com a API não oficial: parser de !menu e !regras, boas-vindas, resposta citada e controle anti-flood.
Agente de voz no WhatsApp: latência, interrupção (barge-in) e silêncio
Como deixar um agente de voz no WhatsApp natural: latência, streaming, detecção de fala, interrupção (barge-in), silêncio e eco, com exemplos em Node.js.
Anti-detecção na API não oficial do WhatsApp: como a WAME protege seu número
Como funciona a camada de anti-detecção da API não oficial da WAME: identidade de dispositivo, tempo humano, ritmo de envio, reconexão e monitor de saúde.