Objetivos de aprendizado
Depois de ler este artigo, você vai conseguir:
- Escolher entre uma biblioteca não oficial e a Cloud API oficial da Meta
- Rodar um bot com Baileys que guarda a sessão e reconecta sozinho
- Verificar que o bot está online e corrigir os erros mais comuns
Nesta página
Um bot de WhatsApp é um programa que recebe mensagens do seu número, decide o que responder e envia a resposta. Para funcionar o dia todo, ele precisa de um processo vivo e de uma sessão autenticada que sobreviva a reinícios. Esses são os dois pontos em que a maioria dos bots quebra.
Este guia mostra os dois caminhos: Baileys, uma biblioteca não oficial que conecta como o WhatsApp Web, e a Cloud API, a interface oficial da Meta. Os exemplos usam a versão LTS ativa do Node.js e a API do Baileys 7. Se o npm install trouxer outra versão maior, leia as notas de versão do projeto antes de seguir.
Biblioteca não oficial ou Cloud API?#
| Baileys (não oficial) | Cloud API (oficial) | |
|---|---|---|
| Como conecta | WebSocket, como dispositivo vinculado ao número | Webhook HTTPS + chamadas à Graph API |
| Sessão | Pasta de autenticação em disco | Token de acesso, sem sessão |
| Servidor | Processo sempre ligado | Servidor HTTPS público com certificado válido |
| Mensagem fora de conversa | Livre, mas com risco de banimento | Só modelos (templates) aprovados |
| Risco | Ban por violar os Termos de Serviço | Sem esse risco, mas exige conta comercial |
A Cloud API entrega as mensagens recebidas por webhook. Quando o usuário escreve, abre-se uma janela de atendimento de 24 horas, que renova a cada nova mensagem dele. Dentro dela você responde com texto livre. Fora dela, só com modelos pré-aprovados. A Meta cobra por mensagem de modelo entregue, e mensagens de texto livre dentro da janela não são cobradas. Os valores e as regras de cobrança atuais estão na página de preços da Meta.
Para comparar as bibliotecas a fundo, veja Baileys, whatsapp-web.js ou Cloud API. Para criar a lógica do bot, veja como fazer um bot de WhatsApp.
O que significa manter um bot de WhatsApp 24/7?#
Significa ter o processo rodando sem parar, numa máquina que não desliga, e a sessão salva de forma que um reinício não exija novo pareamento. No Baileys, a sessão são as chaves e credenciais gravadas na pasta de autenticação. Se essa pasta some, o bot vira um dispositivo novo e precisa ser pareado outra vez.
Por isso, rodar no notebook serve para testar, mas não para produção. Pelo mesmo motivo, o disco importa tanto quanto o processo: em ambientes cujo disco é apagado a cada deploy, o bot perde a sessão a cada atualização.
Como rodar um bot com Baileys?#
Crie o projeto e instale as dependências:
npm init -y
npm pkg set type=module
npm install baileysO Baileys 7 é um módulo ES, por isso o type=module. Defina duas variáveis de ambiente: WA_PHONE, o número do bot só com dígitos e código do país (por exemplo 5562999999999), e, opcionalmente, AUTH_DIR, a pasta da sessão. Não deixe o número nem credenciais no código.
Crie o index.js:
import makeWASocket, {
DisconnectReason,
useMultiFileAuthState,
} from "baileys";
const AUTH_DIR = process.env.AUTH_DIR ?? "auth_info";
const PHONE = process.env.WA_PHONE;
async function start() {
const { state, saveCreds } = await useMultiFileAuthState(AUTH_DIR);
const sock = makeWASocket({ auth: state });
sock.ev.on("creds.update", saveCreds);
sock.ev.on("connection.update", async ({ connection, lastDisconnect, qr }) => {
// Primeira execução: sem sessão salva, gera um código de pareamento.
if (qr && !sock.authState.creds.registered) {
if (!PHONE) return console.error("Defina WA_PHONE para parear.");
console.log("Código de pareamento:", await sock.requestPairingCode(PHONE));
}
if (connection === "open") console.log("Conectado ao WhatsApp.");
if (connection === "close") {
const code = lastDisconnect?.error?.output?.statusCode;
if (code === DisconnectReason.loggedOut) {
console.error("Sessão encerrada pelo celular. Apague a pasta e pareie de novo.");
process.exit(1);
}
if (code === DisconnectReason.connectionReplaced) {
console.error("Outra instância assumiu a sessão. Encerrando.");
process.exit(1);
}
start(); // queda de rede ou reinício pedido pelo WhatsApp: reconecta
}
});
sock.ev.on("messages.upsert", async ({ messages, type }) => {
if (type !== "notify") return;
for (const msg of messages) {
if (msg.key.fromMe || !msg.message) continue;
const text =
msg.message.conversation ?? msg.message.extendedTextMessage?.text;
if (text?.trim().toLowerCase() === "!ping") {
await sock.sendMessage(msg.key.remoteJid, { text: "pong" });
}
}
});
}
start();Rode com WA_PHONE=5562999999999 node index.js. No WhatsApp do celular, abra Dispositivos conectados, escolha vincular com número de telefone e digite o código que apareceu no log. Depois de conectado, mande !ping de outro número: o bot responde pong.
Nas versões anteriores, a opção printQRInTerminal imprimia o QR code sozinha. No Baileys 7 ela foi descontinuada e não imprime mais nada: o QR chega no campo qr do evento connection.update, para você desenhar como quiser. O código de pareamento dispensa o QR e é mais fácil de ler num log de servidor.
Como a sessão sobrevive a reinícios?#
O useMultiFileAuthState grava credenciais e chaves na pasta de autenticação, e o evento creds.update chama o saveCreds sempre que algo muda. Na próxima execução, o Baileys lê a pasta e conecta sem QR nem código. A documentação do projeto alerta que as chaves precisam ser salvas sempre que mudam, senão as mensagens deixam de chegar ao destinatário.
Três cuidados:
- Não apague nem sobrescreva a pasta num deploy. Mantenha-a fora do ZIP e do repositório.
- Trate a pasta como senha. Quem a copia controla a sessão.
- Só uma instância por sessão. Duas cópias do bot com as mesmas credenciais derrubam uma à outra.
O próprio useMultiFileAuthState é só um exemplo: o código-fonte do Baileys não o recomenda para produção, com a ressalva de que talvez sirva para um bot. Num projeto maior, guarde o estado num banco de dados.
Como usar a Cloud API oficial?#
Na Cloud API não há sessão nem pareamento. Você precisa de uma conta comercial na Meta, um número de telefone comercial e um servidor com HTTPS válido (certificado autoassinado não funciona). Veja como funciona o Let's Encrypt se precisar de um certificado.
A Meta confirma o endpoint com uma requisição GET: se hub.verify_token bater com o seu valor, você responde 200 com o hub.challenge. As mensagens chegam por POST e vêm assinadas no cabeçalho X-Hub-Signature-256. Um servidor mínimo, só com a biblioteca padrão do Node.js:
import { createServer } from "node:http";
import { createHmac, timingSafeEqual } from "node:crypto";
const {
VERIFY_TOKEN,
APP_SECRET,
WA_TOKEN,
PHONE_NUMBER_ID,
GRAPH_API_VERSION,
PORT = "8080",
} = process.env;
if (!GRAPH_API_VERSION) throw new Error("Defina GRAPH_API_VERSION (formato vXX.0) com uma versão do changelog da Graph API");
async function reply(to, body) {
await fetch(`https://graph.facebook.com/${GRAPH_API_VERSION}/${PHONE_NUMBER_ID}/messages`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${WA_TOKEN}`,
},
body: JSON.stringify({
messaging_product: "whatsapp",
to,
type: "text",
text: { body },
}),
});
}
createServer(async (req, res) => {
const url = new URL(req.url, "http://localhost");
if (url.pathname !== "/webhook") return res.writeHead(404).end();
if (req.method === "GET") {
const ok =
url.searchParams.get("hub.mode") === "subscribe" &&
url.searchParams.get("hub.verify_token") === VERIFY_TOKEN;
return res
.writeHead(ok ? 200 : 403)
.end(ok ? url.searchParams.get("hub.challenge") : "");
}
const chunks = [];
for await (const chunk of req) chunks.push(chunk);
const raw = Buffer.concat(chunks);
const expected = Buffer.from(
"sha256=" + createHmac("sha256", APP_SECRET).update(raw).digest("hex"),
);
const got = Buffer.from(req.headers["x-hub-signature-256"] ?? "");
if (got.length !== expected.length || !timingSafeEqual(got, expected)) {
return res.writeHead(401).end();
}
res.writeHead(200).end(); // responda rápido; a Meta repete entregas que falham
for (const entry of JSON.parse(raw).entry ?? [])
for (const change of entry.changes ?? [])
for (const m of change.value?.messages ?? [])
if (m.type === "text") await reply(m.from, `Você disse: ${m.text.body}`).catch(console.error);
}).listen(Number(PORT));A Meta reenvia entregas que falham por até 7 dias, então o mesmo evento pode chegar duas vezes. Em produção, guarde o id de cada mensagem e ignore repetidas. Variáveis como WA_TOKEN e APP_SECRET entram por ambiente: veja o que são variáveis de ambiente. A versão da Graph API também, porque cada versão deixa de funcionar cerca de dois anos depois do lançamento: coloque em GRAPH_API_VERSION a mais recente do changelog da Graph API, no formato vXX.0, e quando ela envelhecer basta trocar o valor e reiniciar.
Como saber se o bot está online?#
- Mande uma mensagem de teste (
!ping) e confira a resposta. - No Baileys, procure
Conectado ao WhatsApp.no log e observe se aparecem quedas em sequência. - Na Cloud API, use o teste de webhook do painel da Meta e confira se o servidor responde 200.
- Confirme que o processo reinicia sozinho se parar. Em um VPS, essa é a função de
systemdoupm2.
Quais são os erros comuns?#
- O bot pede código a cada reinício: a pasta de autenticação foi apagada ou o disco não é persistente. Salve a pasta em local que sobrevive ao deploy.
- Sessão encerrada (
loggedOut): o aparelho foi removido em Dispositivos conectados, ou o WhatsApp invalidou a sessão. Apague a pasta e pareie de novo. - Dois bots derrubando um ao outro (
connectionReplaced): há outra instância com as mesmas credenciais, inclusive no seu PC. Mantenha uma só. Veja também por que o bot do WhatsApp desconecta. - Webhook da Cloud API não valida:
hub.verify_tokendiferente do configurado, URL sem HTTPS válido ou rota errada. - Mensagem rejeitada fora da janela de 24 horas: só modelos aprovados podem iniciar a conversa depois que a janela fecha.
Cannot use import statement outside a module: falta"type": "module"nopackage.json.
Como fazer isso na Square Cloud#
A Square Cloud é hospedagem self-service: você envia o projeto, define a memória e controla tudo no painel. Ela funciona com Baileys, WPPConnect, whatsapp-web.js e a Cloud API oficial. A pasta de autenticação fica no disco da aplicação, então a sessão continua conectada depois de um restart.
Os containers ficam sempre ligados, sem modo de suspensão, com reinício automático (ligado por padrão no deploy pelo painel) quando o processo encerra com erro. WA_PHONE, WA_TOKEN, GRAPH_API_VERSION e as demais variáveis são definidas por aplicação no painel, e os logs em tempo real mostram o código de pareamento e os eventos de conexão. Você faz o deploy por ZIP, CLI, GitHub ou extensão do VS Code, e o squarecloud.app é opcional: o painel gera o arquivo com runtime, memória e arquivo principal, ou você o escreve na raiz do projeto.
Todos os planos são pagos e cobrados em reais. O Hobby custa R$ 12,49 por mês, com 1 GB de RAM compartilhado entre as suas aplicações, e o mínimo por aplicação de fundo, como um bot, é de 256 MB. Aplicações web, como o webhook da Cloud API, partem de 512 MB e ganham um subdomínio squareweb.app com HTTPS. Veja a página de hospedagem de bots de WhatsApp.
Hospedagem de bots
Seu bot online 24/7, com reinício automático
Perguntas frequentes
O bot de WhatsApp precisa ficar com o computador ligado?
Precisa de um processo rodando em algum lugar. Se for o seu PC, o bot cai quando ele desliga ou perde a internet. Num servidor sempre ligado, ele continua respondendo sem depender da sua máquina.
Preciso parear o bot toda vez que ele reinicia?
Não, desde que a pasta de autenticação esteja salva em disco e não seja apagada. O Baileys lê as credenciais dessa pasta e reconecta sem novo pareamento. Só é preciso parear de novo se a sessão for encerrada pelo celular.
Preciso de domínio para hospedar um bot de WhatsApp?
Com o Baileys, não: o bot abre a conexão por conta própria. Com a Cloud API oficial, sim: a Meta entrega as mensagens por webhook, que exige uma URL pública com HTTPS e certificado válido.
Usar Baileys pode banir meu número?
Pode. Bibliotecas não oficiais não são autorizadas pelo WhatsApp, e os mantenedores do Baileys dizem não apoiar usos que violem os Termos de Serviço do WhatsApp, deixando a responsabilidade com quem usa. Para uso comercial, a Cloud API oficial evita esse risco.
Mais em Bots
Ver todos os 33 artigos- Quanto custa hospedar um bot do Discord?O custo de hospedar um bot do Discord depende de RAM, tempo online, banco de dados e serviços externos. Veja como estimar o seu e onde o gasto aparece.
- Rodar bot no celular (Termux) ou no PC vs hospedar: o que mudaUm bot no PC ou no celular (Termux) fica offline quando o aparelho desliga, dorme ou perde a rede. Compare as três opções e veja quando cada uma serve.
- Como deixar um bot do Discord online 24/7Para deixar um bot do Discord online 24/7, rode o processo numa máquina sempre ligada com reinício automático. Veja PC, VPS com pm2 ou systemd e hospedagem.
- Por que meu bot do Discord fica offline (e como resolver)Bot do Discord offline quase sempre é processo caído, token inválido, intent não habilitada ou falta de memória. Veja como diagnosticar cada causa e corrigir.