Como criar um chatbot de IA com a API da OpenAI para responder no WhatsApp
Um webhook, uma chamada à API da OpenAI e uma resposta pela WAME API: o código completo de um chatbot de IA que atende no WhatsApp, Instagram e Messenger. Com memória por contato, controle de custo e o que fazer quando a IA não deve responder.
Um chatbot de IA no WhatsApp são três peças: receber a mensagem, perguntar ao modelo, devolver a resposta. Nenhuma delas é difícil — o que costuma dar trabalho é o meio de campo: o formato do webhook, a memória da conversa e saber quando a IA não deve responder.
Este artigo mostra o código completo, em Node.js, e trata das três coisas.
O que você precisa
- Uma instância na WAME API — a não oficial conecta por QR Code em segundos e serve para testar.
- Uma chave da API da OpenAI.
- Uma URL pública para o webhook. Em desenvolvimento,
ngrokou similar.
Peça 1: receber a mensagem
Aponte o webhook da sua instância (formato meta) para a sua URL. Todo evento chega no envelope padrão da Meta Cloud API, e o campo provider diz o canal:
{
"object": "wame",
"provider": "whatsapp",
"entry": [{
"id": "<instance-id>",
"changes": [{
"field": "messages",
"value": {
"messages": [{
"from": "5566996852025",
"id": "wamid.XXXX",
"type": "text",
"text": { "body": "vocês entregam em Cuiabá?" }
}]
}
}]
}]
}
Isso importa mais do que parece: como os três canais chegam no mesmo envelope, o bot que você escrever para o WhatsApp já atende Instagram e Messenger. É o padrão único de webhook da plataforma.
O extrator, com as guardas que evitam 90% dos bugs:
function extrair(body) {
const msg = body?.entry?.[0]?.changes?.[0]?.value?.messages?.[0];
// Status de entrega ("delivered", "read") também chega aqui.
// Sem esta guarda, o bot responde a si mesmo em loop.
if (!msg || msg.type !== 'text') return null;
return {
de: msg.from,
texto: msg.text.body,
canal: body.provider,
messageId: msg.id,
};
}
Peça 2: perguntar ao modelo
A API da OpenAI não guarda estado. Cada chamada é independente, então a memória é sua:
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// Em produção use Redis ou banco. Em memória, some no restart.
const historico = new Map();
const SYSTEM = `Você é o atendente da Loja Exemplo, no WhatsApp.
Regras:
- Responda em português, em no máximo 3 frases curtas.
- Nunca invente prazo, preço ou disponibilidade.
- Se a pergunta exigir dado que você não tem, responda exatamente
com o texto [HUMANO] e nada mais.`;
async function responder(de, texto) {
const anterior = historico.get(de) ?? [];
// Últimas 10 mensagens: o suficiente para o contexto e
// o bastante para o custo não crescer sem limite.
const mensagens = [
{ role: 'system', content: SYSTEM },
...anterior.slice(-10),
{ role: 'user', content: texto },
];
const r = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: mensagens,
max_tokens: 300,
temperature: 0.3,
});
const resposta = r.choices[0].message.content.trim();
historico.set(de, [
...anterior.slice(-10),
{ role: 'user', content: texto },
{ role: 'assistant', content: resposta },
]);
return resposta;
}
Três decisões nesse código valem explicação:
temperature: 0.3 — atendimento não quer criatividade. Temperatura baixa deixa a resposta mais previsível e reduz invenção.
max_tokens: 300 — WhatsApp não é lugar de parágrafo longo. Além de melhorar a leitura, limita o custo por resposta.
slice(-10) — o custo da OpenAI é por token, e o histórico inteiro vai em toda chamada. Sem corte, uma conversa longa fica progressivamente mais cara. Dez mensagens costumam bastar.
Peça 3: devolver pelo WhatsApp
async function enviar(para, texto, canal) {
await fetch(`https://us.api-wa.me/${process.env.WAME_KEY}/message/text`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ to: para, text: texto, channel: canal }),
});
}
Juntando tudo
import express from 'express';
const app = express();
app.use(express.json());
app.post('/webhook/wame', async (req, res) => {
// Responda 200 IMEDIATAMENTE. A OpenAI leva segundos, e um
// webhook que demora a responder é reenviado — o cliente
// receberia a mesma resposta duas ou três vezes.
res.sendStatus(200);
const msg = extrair(req.body);
if (!msg) return;
try {
const resposta = await responder(msg.de, msg.texto);
if (resposta.includes('[HUMANO]')) {
await enviar(msg.de, 'Só um instante, vou chamar alguém do time.', msg.canal);
await avisarAtendente(msg); // sua fila, seu CRM, seu Chatwoot
return;
}
await enviar(msg.de, resposta, msg.canal);
} catch (e) {
console.error('falha ao responder', msg.de, e);
await enviar(msg.de, 'Tive um problema aqui. Já chamo um atendente.', msg.canal);
await avisarAtendente(msg);
}
});
app.listen(3000);
Pronto — cerca de 60 linhas para um bot de IA que atende nos três canais.
O detalhe que separa demo de produção
Responder 200 antes de processar. É a linha mais importante do arquivo. A chamada à OpenAI leva de 1 a 5 segundos; se o seu handler esperar por ela para responder ao webhook, a entrega é considerada falha e reenviada. O resultado é o cliente recebendo a mesma resposta três vezes — e você pagando três vezes por ela.
Ter uma saída para o humano. O [HUMANO] do system prompt existe para isso. Um bot que responde "não sei" é ruim; um bot que inventa o prazo de entrega é pior, porque vira reclamação. Modelo instruído a admitir o limite e código que trata esse caso resolvem os dois. Como o avisarAtendente funciona do outro lado — fila, atribuição e o bot saindo de cena — está em vários atendentes no mesmo número.
Tratar o erro como caminho normal. A OpenAI vai falhar em algum momento — timeout, limite, indisponibilidade. O catch acima não deixa o cliente no vácuo. Do lado do WhatsApp, cada erro pede um tratamento diferente: alguns valem nova tentativa, outros não.
Não responder a si mesmo. A guarda em extrair cuida disso: status de entrega e leitura também chegam no webhook, e sem o filtro o bot entra em loop.
E se o webhook não chegar?
Acontece, e quase sempre é uma das mesmas causas. Antes de mexer no código, aponte o webhook da instância para uma URL do webhook.site e mande uma mensagem: se o evento aparecer lá, o problema é o seu servidor; se não aparecer, é a configuração da instância. Esse teste de 30 segundos separa os dois mundos e evita horas de depuração no lado errado. Há um guia completo em webhook não chega: as 7 causas.
Quando usar n8n em vez de código
Se você quer o fluxo montado visualmente, ou já opera n8n, existe um template pronto de bot de IA com memória por contato — cinco nós, sem escrever nada.
O código faz sentido quando você precisa de controle: regra de negócio no meio da conversa, consulta ao seu banco antes de responder, custo medido por cliente, ou o bot rodando dentro de um sistema que você já mantém. Se você entrega software para clientes, normalmente é esse o caso.
E se o que você quer não é um bot atendendo cliente, mas um agente de IA operando o WhatsApp para você — ler a caixa de entrada, achar quem ficou sem resposta, mandar um documento —, o caminho é outro: o servidor MCP da WAME, que dispensa escrever integração.
Conclusão
O chatbot em si é a parte fácil. O que decide se ele fica no ar é o entorno: responder o webhook na hora, cortar o histórico, ter saída para o humano e tratar erro como caminho esperado.
Comece com uma instância não oficial e um número de teste. Quando o comportamento estiver bom, migre para a API oficial — o webhook e o SDK são os mesmos, então o código do bot não muda.
Pronto para automatizar seu WhatsApp?
Crie sua conta gratuita e comece a enviar mensagens pela API em minutos.
Começar grátisPerguntas frequentes
Como conectar a API da OpenAI ao WhatsApp?+
São três peças: um webhook que recebe a mensagem do WhatsApp pela WAME API, uma chamada à API da OpenAI com o histórico da conversa, e um POST para /{key}/message/text devolvendo a resposta. O webhook recebe todos os canais no mesmo formato, então o mesmo código atende WhatsApp, Instagram e Messenger.
Preciso de n8n para fazer um bot de IA no WhatsApp?+
Não. O n8n é conveniente quando você quer montar o fluxo visualmente ou já usa a ferramenta, e existe um template pronto da WAME para isso. Mas em código são cerca de 60 linhas, e você ganha controle total sobre memória, custo e regras de quando não responder.
Quanto custa rodar um chatbot de IA no WhatsApp?+
Dois custos separados: o da OpenAI, cobrado por token consumido, e o da mensagem. Na API não oficial da WAME a mensagem tem preço fixo por instância; na oficial, a Meta cobra por conversa. O custo da IA é o que mais varia, e ele depende do tamanho do histórico que você envia a cada chamada — por isso limitar a memória importa.
Como fazer o bot lembrar da conversa anterior?+
A API da OpenAI não guarda estado: cada chamada é independente. Você mantém as últimas mensagens por contato num armazenamento seu (Redis, banco ou memória) e as envia como histórico a cada requisição. Guardar as últimas 10 costuma bastar e mantém o custo previsível.
O que fazer quando a IA não souber responder?+
Instrua o modelo no system prompt a devolver um marcador combinado quando não tiver certeza, e trate esse marcador no seu código transferindo para um atendente humano. Bot de IA que inventa resposta em atendimento custa mais caro que bot que passa a bola.
Continue lendo
Bot de IA no WhatsApp, Instagram e Messenger com n8n (template pronto)
Monte um bot de IA (GPT/OpenAI) que responde no WhatsApp, Instagram e Messenger num único fluxo do n8n. Template pronto WAME, com memória por contato.
Cobrança por Pix dentro do WhatsApp pela API: como enviar e o que muda na conversão
Mandar o código Pix no WhatsApp resolve o pior ponto da cobrança digital: o cliente não precisa sair do app. Como enviar a cobrança pela API, tratar a confirmação e evitar os erros que transformam a facilidade em suporte.
Erros da API do WhatsApp: o que cada um significa e como tratar
A mensagem não saiu e o log diz apenas 'erro ao enviar'. Os erros que você vai encontrar de verdade — janela fechada, número inválido, template não aprovado, limite atingido, instância caída — e o tratamento certo para cada um.