API WhatsApp · Referencia Interativa · BETA
BETA

WhatsApp API v2 Reference

Documentacao interativa gerada a partir da spec OpenAPI 3.1. Clique em qualquer endpoint para ver parametros, exemplos de request e response. Copie com um clique.

Documentacao em desenvolvimento (BETA): Esta documentacao esta em construcao. Alguns endpoints, campos e exemplos podem estar incompletos ou faltar. Reporte inconsistencias via WhatsApp 5551980331519.
--
ENDPOINTS
--
CATEGORIAS
3
MODOS DE CONEXAO
120s
TTL PAIRING CODE
AUTH
Autenticacao
Todas as rotas exigem o token de API no header Authorization: {seu_token} (sem prefixo "Bearer "). Tokens sao gerados no painel do usuario.
BASH
# Header correto: Authorization + token direto (SEM "Bearer") curl -X POST https://apifacil.dev/api/v2/whatsapp/mensagem/1/enviar \ -H "Authorization: SEU_TOKEN_AQUI" \ -H "Content-Type: application/json" \ -d '{"to":"5511999999999","type":"text","content":"Ola, como vai?"}'
Erro comum: Enviar Authorization: Bearer SEU_TOKEN retorna 401. O middleware valida o token direto no header — nao use prefixo "Bearer ".
CONN
3 Modalidades de Conexao
Escolha o melhor metodo para seu caso
1 · QR Code
POST /iniciar → GET /qrcode → escanear
2 · Pairing Code
POST /solicitar-pareamento → digitar codigo no celular
3 · Importar Sessao
POST /importar-sessao → conecta automatico
1
QR Code (tradicional)
Conexao por escanear codigo — ideal para onboarding manual
Plano: Todos Tempo: ~30s

O usuario abre o WhatsApp do celular, vai em Configuracoes › Aparelhos conectados › Conectar aparelho e escaneia o QR Code exibido pela API. A cada chamada de /iniciar um novo QR Code e gerado (validade ~60s, renova automaticamente).

1
Criar instancia
POST /instancia/criar
2
Iniciar sessao (gera QR)
POST /{id}/iniciar
3
Poll QR Code
GET /{id}/qrcode
4
Exibir QR para usuario escanear
5
Verificar status
GET /{id}/status

Exemplo completo em JavaScript

JAVASCRIPT · FLUXO COMPLETO
// 1. Iniciar sessao (gera QR Code no microservico) await fetch('https://apifacil.dev/api/v2/whatsapp/instancia/1/iniciar', { method: 'POST', headers: { 'Authorization': 'SEU_TOKEN' } }); // 2. Poll QR Code a cada 3s ate obter async function obterQRCode() { for (let i = 0; i < 20; i++) { const res = await fetch('https://apifacil.dev/api/v2/whatsapp/instancia/1/qrcode', { headers: { 'Authorization': 'SEU_TOKEN' } }); const json = await res.json(); if (json.data?.qr_code) { // data.qr_code = "2@/AW1mZXNhc3dhcmUuY29t..." console.log('QR Code obtido!'); return; } await new Promise(r => setTimeout(r, 3000)); } } // 3. Verificar status apos escanear async function verificarStatus() { const res = await fetch('https://apifacil.dev/api/v2/whatsapp/instancia/1/status', { headers: { 'Authorization': 'SEU_TOKEN' } }); const json = await res.json(); // json.data.status_banco = "connected" | "disconnected" | "connecting" if (json.data.status_banco === 'connected') { console.log('Conectado!'); } }
Dica: O QR Code expira em ~60 segundos. Se expirar, chame /iniciar novamente para gerar um novo. O microservico renova automaticamente enquanto a sessao estiver aberta.
2
Pairing Code (codigo de pareamento)
Conexao por codigo de 8 digitos — ideal para integracoes server-to-server e onboarding sem camera
Plano: Todos TTL: 120s Formato: 8 chars (ABC12345)

O parceiro envia o numero de telefone do cliente. A API inicia a sessao e solicita o codigo ao WhatsApp. O cliente digita o codigo manualmente no celular: Configuracoes › Aparelhos conectados › Conectar com codigo de telefone. O codigo expira em 120 segundos.

Importante: Nao e necessario chamar /iniciar antes — o endpoint /solicitar-pareamento ja inicia a sessao automaticamente. Se voce chamar /iniciar antes, pode conflitar com a sessao recem-iniciada.
1
Solicitar codigo
POST /{id}/solicitar-pareamento
body: {"phone":"5511999999999"}
2
API inicia sessao
start-session
3
API pede codigo ao WhatsApp
4
Retorna codigo
"W4NQJMRD" (8 chars)
5
Cliente digita no celular
Config › Aparelhos › Conectar com codigo

Formato do telefone

O telefone deve conter DDI + DDD + numero, apenas digitos, 10 a 15 caracteres. Regex validado: ^\d{10,15}$.

EXEMPLOFORMATOVALIDO?
5511999999999DDI+DDD+numeroSIM
55119999999911 digitosSIM
11999999999sem DDINAO (10 digitos ok mas sem DDI pode falhar)
+55 11 99999-9999com mascaraNAO (regex rejeita)

Exemplo completo em JavaScript (com polling)

JAVASCRIPT · FLUXO COMPLETO
// 1. Solicitar codigo de pareamento async function solicitarPareamento(instanciaId, phone) { const res = await fetch( `https://apifacil.dev/api/v2/whatsapp/instancia/${instanciaId}/solicitar-pareamento`, { method: 'POST', headers: { 'Authorization': 'SEU_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ phone }) // "5511999999999" } ); const json = await res.json(); if (json.error) { throw new Error(json.message); } // json.data = { pairingCode: "W4NQJMRD" } return json.data; } // 2. Mostrar codigo para cliente digitar no celular const { pairingCode } = await solicitarPareamento(1, '5511999999999'); console.log(`Codigo: ${pairingCode} (expira em 120s)`); // > "Codigo: W4NQJMRD (expira em 120s)" // Cliente vai no celular: Config › Aparelhos conectados › Conectar com codigo // 3. Poll de status para saber quando conectar async function aguardarConexao(instanciaId, timeoutMs = 120000) { const start = Date.now(); while (Date.now() - start < timeoutMs) { const res = await fetch( `https://apifacil.dev/api/v2/whatsapp/instancia/${instanciaId}/status`, { headers: { 'Authorization': 'SEU_TOKEN' } } ); const json = await res.json(); if (json.data?.status_banco === 'connected') { console.log('Conectado com sucesso!'); return true; } await new Promise(r => setTimeout(r, 3000)); // a cada 3s } return false; // timeout } const conectou = await aguardarConexao(1); if (!conectou) { console.log('Codigo expirou. Solicite um novo.'); } // 4. (Opcional) Recuperar codigo atual const res = await fetch( 'https://apifacil.dev/api/v2/whatsapp/instancia/1/codigo-pareamento', { headers: { 'Authorization': 'SEU_TOKEN' } } ); const json = await res.json(); // json.data = { pairing_code: "W4NQJMRD" } // se expirado: 404 com mensagem "Codigo de pareamento nao disponivel."

Troubleshooting

SINTOMA
CAUSA / SOLUCAO
"Erro ao solicitar codigo de pareamento"
Microservico offline ou nao respondeu em 10s. Verifique se o servidor da instancia esta acessivel. Tente novamente.
"Microservico nao retornou o codigo"
WhatsApp recusou o pareamento. Possiveis causas: numero invalido, numero sem conta WhatsApp, ou sessao anterior nao foi fechada corretamente. Aguarde 30s e tente novamente.
Codigo retornado mas cliente nao consegue digitar
Codigo expirou (120s). Solicite um novo via /solicitar-pareamento. Nao use /codigo-pareamento para gerar novo — ele so consulta o Redis.
Status fica "connecting" para sempre
Cliente digitou codigo errado ou nao confirmou no celular. Peça para refazer o fluxo. Se persistir, chame /desconectar e recomece.
"Sessao ja esta ativa. Desconecte antes..."
Instancia ja conectada. Se quer re-parear, chame POST /{id}/desconectar antes.
telefone invalido (422)
Regex ^\d{10,15}$ rejeitou. Envie apenas digitos, com DDI+DDD+numero. Ex: "5511999999999".
Quando usar Pairing Code vs QR Code?
Pairing Code: integracoes server-to-server, onboarding remoto (sem camera), apps mobile que mandam o codigo via push.
QR Code: onboarding presencial, web apps com camera, fluxo manual.
3
Importar Sessao (WebAuth)
Importa credenciais exportadas pela extensao WhatsApp Session Extractor — ideal para migrar sessoes entre instancias sem re-escanear
Plano: Todos Auto-connect

Importa uma sessao previamente pareada do armazenamento PostgreSQL do microservico v2. A sessao conecta automaticamente apos a importacao, sem precisar de QR Code ou pairing code.

Vantagem: Ideal para reconectar uma instancia apos restart do microservico ou migrar sessao entre servidores sem re-parear.
1
Solicitar importacao
POST /{id}/importar-sessao
2
Microservico busca sessao no PostgreSQL
store-postgres
3
Instancia conecta sozinha
nao precisa /iniciar

Exemplo completo em JavaScript

JAVASCRIPT · FLUXO COMPLETO
// 1. Enviar solicitacao de importacao para a API const res = await fetch( 'https://apifacil.dev/api/v2/whatsapp/instancia/1/importar-sessao', { method: 'POST', headers: { 'Authorization': 'SEU_TOKEN', 'Content-Type': 'application/json' } } ); const json = await res.json(); if (json.error) { console.error(json.message); return; } console.log(json.message); // > "Sessao importada" // 2. Poll de status (conecta automaticamente em ~5-10s) async function aguardarConexao(instanciaId) { for (let i = 0; i < 30; i++) { const res = await fetch( `https://apifacil.dev/api/v2/whatsapp/instancia/${instanciaId}/status`, { headers: { 'Authorization': 'SEU_TOKEN' } } ); const json = await res.json(); if (json.data?.status_banco === 'connected') { console.log('Sessao importada e conectada!'); return true; } await new Promise(r => setTimeout(r, 2000)); } return false; } const ok = await aguardarConexao(1);

Exemplo em PHP (Laravel)

PHP · LARAVEL HTTP
// Solicitar importacao de sessao do PostgreSQL $response = Http::withHeaders([ 'Authorization' => 'SEU_TOKEN', ])->post('https://apifacil.dev/api/v2/whatsapp/instancia/1/importar-sessao'); if ($response->successful()) { $data = $response->json(); // $data['message'] = "Sessao importada" }

Troubleshooting

SINTOMA
CAUSA / SOLUCAO
Importa mas status fica "disconnected"
Credenciais expiradas ou invalidas. Re-inicie a sessao e pareie novamente.
"Erro ao importar sessao" (500)
Microservico offline ou timeout. Verifique o servidor da instancia.
Conecta mas cai depois de alguns minutos
WhatsApp detectou sessao duplicada. Desconecte outras sessoes antes de importar.

QR Code vs Pairing Code vs Importar Sessao

CRITERIOQR CodePairing CodeImportar Sessao
Requer celular em maosSIMSIMNAO
Requer cameraSIMNAONAO
Requer sessao previa no PostgreSQLNAONAOSIM
Tempo medio de conexao~30s~15s~5-10s
Reconectar apos restartNAONAOSIM
Onboarding server-to-serverNAOSIMSIM
Onboarding mobile appSIMSIMNAO
Atencao: A importacao de sessao so funciona se houver uma sessao valida armazenada no PostgreSQL do microservico v2. Se a sessao foi removida (logout/desconectar), sera necessario re-parear via QR Code ou Pairing Code.
Carregando endpoints
HOOK
Webhooks
Eventos enviados para sua URL

Configure via PUT /whatsapp/instancia/{id}/configuracao. O microservico envia POST para sua URL com Content-Type: application/json, timeout 10s.

URLs de webhook (roteamento)

CAMPODESTINOUSA?
webhook_urlMensagens privadas (message_sent + message_received)SIM
webhook_grupoMensagens de grupoSIM
webhook_ativoLiga/desliga TODOS os webhooks (master switch)SIM

Bloqueio por tipo de mensagem (filtros)

Voce pode impedir que certos tipos de mensagem disparem o webhook. Util para ignorar stickers, audios longos, localizacoes, etc. Configure o campo tipos_envio dentro de config_json (via PUT /whatsapp/instancia/{id}/configuracao).

O campo tipos_envio recebe um array de tipos. Toda mensagem cujo tipo esteja nesse array sera salva no banco (com status skipped) mas nao disparara webhook. Comportamento identico ao painel de configuracao da instancia.

VALOR DE tipoDESCRICAO
textMensagem de texto
imageImagem
videoVideo
audioAudio (nota de voz ou arquivo)
documentDocumento (PDF, DOC, etc)
stickerSticker / figurinha
locationLocalizacao
Atencao: O valor comparado pelo filtro e o campo tipo do payload (em minusculas: text, image, etc). Nao confunda com os nomes em maiusculas usados na API v1 (MENSAGEM_ENVIADA, AUDIO_RECEBIDO). Na v2 os valores sao os mesmos do campo tipo retornado no webhook.
BASH · bloquear stickers e localizacoes
PUT https://apifacil.dev/api/v2/whatsapp/instancia/{id}/configuracao \ -H "Authorization: SEU_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "tipos_envio": ["sticker", "location"] }'
JSON · resposta (config_json atualizado)
{ "error": false, "message": "Configuracao atualizada", "data": { "config_json": { "tipos_envio": ["sticker", "location"] } } }
Limpar filtro: Envie "tipos_envio": [] para remover todos os bloqueios e voltar a receber todos os tipos via webhook. As mensagens bloqueadas continuam sendo salvas no banco e podem ser consultadas via GET /whatsapp/mensagens.

Eventos de webhook

EVENTODESCRICAOQUANDO
message_sentMensagem enviada por voceApos envio via API ou workflow
message_receivedMensagem recebida do contatoChega no WhatsApp do numero conectado
message_statusAtualizacao de status (delivered/read/played)Quando o destinatario recebe, le ou reproduz a midia
message_errorErro ao enviar mensagemFalha no envio (numero invalido, sem conexao, etc)

O campo from_me indica a direcao. O campo status indica o estado atual (pending, sent, delivered, read, played, failed). Em replies, os campos quoted_message_id e quoted_participant identificam a mensagem original.

JSON · webhook payload (message_received)
{ "event": "message_received", "mensagem_id": 123, "instancia_id": 1, "message_id": "3EB0123456789ABCDEF", "remote_jid": "5511999999999@s.whatsapp.net", "remote_jid_alt": null, "from_me": false, "participant": null, "tipo": "text", "conteudo": "Ola, como vai?", "caption": null, "media_url": null, "quoted_message_id": null, "quoted_participant": null, "status": "delivered", "push_name": "Joao Silva", "timestamp": "2026-07-24T12:00:00.000Z" }

Exemplo: webhook message_status (receipt)

JSON · webhook payload (message_status)
{ "event": "message_status", "mensagem_id": 123, "instancia_id": 1, "message_id": "3EB0123456789ABCDEF", "remote_jid": "5511999999999@s.whatsapp.net", "from_me": true, "tipo": "text", "status": "read", "timestamp": "2026-07-24T12:01:00.000Z" }

Exemplo: webhook message_received com reply (quoted)

JSON · webhook payload (reply)
{ "event": "message_received", "mensagem_id": 125, "instancia_id": 1, "message_id": "3EB0998877665544332211", "remote_jid": "5511999999999@s.whatsapp.net", "from_me": false, "tipo": "text", "conteudo": "Respondendo sua mensagem", "quoted_message_id": "3EB0123456789ABCDEF", "quoted_participant": "5511999999999@s.whatsapp.net", "status": "delivered", "timestamp": "2026-07-24T12:02:00.000Z" }

Valores de status (campo status)

STATUSDESCRICAO
pendingMensagem na fila aguardando envio
sentMensagem enviada para o WhatsApp
deliveredMensagem entregue no dispositivo
readMensagem lida pelo destinatario
playedMensagem de audio/visual reproduzida
failedFalha ao enviar

Sistema de retry

Retries acontecem em 1min, 5min e 30min em caso de falha (total 4 tentativas em ~36min). Apos falha na 4a tentativa: marca erro permanente.

Exemplo: receptor de webhook em Node.js (Express)

JAVASCRIPT · EXPRESS
const express = require('express'); const app = express(); app.use(express.json()); app.post('/webhook', (req, res) => { const { event, mensagem_id, message_id, tipo, conteudo, from_me, status, remote_jid } = req.body; console.log(`Evento: ${event}, Tipo: ${tipo}, Status: ${status}`); console.log(`De: ${remote_jid}, Enviada por mim: ${from_me}`); if (!from_me && tipo === 'text') { // Mensagem recebida do contato console.log(`Mensagem recebida: ${conteudo}`); } // Responder 2xx rapidamente (timeout 10s no remetente) res.status(200).json({ received: true }); }); app.listen(3000, () => console.log('Webhook receiver on :3000'));

Exemplo: receptor em PHP (Laravel)

PHP · LARAVEL
// routes/web.php Route::post('/webhook', function (Request $req) { $event = $req->input('event'); $tipo = $req->input('tipo'); $conteudo = $req->input('conteudo'); $fromMe = $req->input('from_me'); $status = $req->input('status'); if (!$fromMe && $tipo === 'text') { // Processar mensagem recebida Log::info("Mensagem recebida: {$conteudo}"); } return response()->json(['received' => true], 200); });
Dica: Seu receptor deve responder 2xx em ate 10 segundos (timeout do remetente). Se demorar mais, o microservico considerara falha e agendara retry. Processamento pesado deve ser assincrono (fila/queue).
PLAN
Planos e Recursos
RecursoFreePago
Mensagens de textoSIMSIM
WebhooksNAOSIM
Envio de imagensNAOSIM
Envio de videosNAOSIM
Envio de arquivosNAOSIM
Envio de audiosNAOSIM
Envio de localizacaoNAOSIM
SAFE
Boas Praticas e Anti-Ban
Evite restricoes e banimentos
Importante: O WhatsApp monitora padroes de comportamento para detectar spam. Numeros novos e contas com pouca atividade sao especialmente sensiveis. Siga estas orientacoes para reduzir o risco de restricoes.
1. Aqueca a conta antes de enviar em massa

Relatos indicam que numeros novos estao sendo banidos logo no primeiro envio. Antes de comecar a disparar mensagens em massa, aqueca a conta:

  • Interaja de forma organica e gradual por alguns dias (conversas reais, respostas, grupos).
  • Adicione foto de perfil, bio e nome configurados.
  • Converse com contatos que ja tem seu numero salvo.
  • Evite o primeiro envio sendo uma campanha em massa.
2. Evite comportamento de spam
  • Nao envie muitas mensagens de uma vez. Distribua os envios ao longo do dia.
  • Tenha cuidado redobrado com numeros estrangeiros (DDI diferente do seu), pois isso aumenta significativamente o risco de restricoes.
  • Varie o conteudo. Mensagens identicas repetidas disparam alertas.
  • Priorize contatos que ja interagiram com voce (opt-in).
3. O que fazer apos uma restricao/banimento

Se o numero tomou restricao, aguarde um periodo de descanso antes de voltar a enviar. Embora deixar o numero parado por ~15 dias ajude, o foco principal deve ser evitar o comportamento que causou o banimento inicial.

  • Pare os envios em massa imediatamente.
  • Deixe a conta em descanso por pelo menos 7 a 15 dias.
  • Quando retornar, recomece de forma lenta e organica (aquecimento novamente).
  • Revise o volume, horarios e tipos de mensagens que estavam sendo enviados.
  • Se o banimento se repetir, considere trocar o numero e comecar do zero com aquecimento adequado.
Resumo: Aqueca → envie gradual → evite numeros estrangeiros em massa → se tomar restricao, descanse e mude o comportamento antes de voltar.