WZAP-API WZAP-API
Documentação oficial

Uma API clara para operar seu WhatsApp.

Integre mensagens, conexão, consultas e webhooks por uma única fachada autenticada. A sessão correta é vinculada no servidor e as credenciais internas nunca fazem parte da sua integração.

Base da fachada
https://api2.wzap-api.com
Formato
JSON UTF-8
Ações públicas
32
01

Primeira chamada

Gere o bearer uma vez no painel, copie o ID e o token da instância e envie uma mensagem de teste pelo seu backend.

1

Obtenha as credenciais

Bearer da API, ID e token da instância. O bearer completo é exibido uma única vez.

2

Monte a chamada

Use a base pública, a ação documentada e envie o token da instância somente no cabeçalho.

3

Envie pelo backend

Nunca exponha as credenciais em JavaScript do navegador.

cURL · enviar texto
curl --request POST \
  --url "https://api2.wzap-api.com/instances/SEU_INSTANCE_ID/send-text" \
  --header "Authorization: Bearer wzap_live_SEU_BEARER" \
  --header "X-Instance-Token: SEU_INSTANCE_TOKEN" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data '{
    "chatId": "[email protected]",
    "text": "Olá pela WZAP-API!"
  }'
Importante

Não envie session no JSON. A WZAP-API injeta a sessão pertencente ao usuário autenticado e ignora qualquer tentativa de substituí-la.

02

Autenticação

A fachada usa um bearer com escopos e, quando necessário, a credencial da instância. O fluxo legado com API key e CSRF existe apenas durante a migração.

CredencialOnde enviarFinalidade
api_tokenAuthorization: Bearer …Identifica a conta e aplica os escopos da credencial.
instance_idSegmento da URLSeleciona uma instância pertencente à conta nas ações da fachada.
instance_tokenX-Instance-Token: …Autoriza o uso daquela instância nas ações da fachada sem entrar no request-target.
Segredos e logs

Copie o bearer no momento da emissão: somente o hash é persistido e uma rotação revoga os anteriores. Nunca coloque o token da instância na URL; envie-o em X-Instance-Token e remova cabeçalhos sensíveis da observabilidade.

Escopos

A credencial principal emitida pelo painel inclui somente instances:read, instances:write, messages:send, webhooks:read, webhooks:write e billing:balance. Credenciais legadas permanecem temporariamente apenas em ações não financeiras.

03

Contrato da API

Uma estrutura previsível para todas as ações.

BASEhttps://api2.wzap-api.com/instances/{instance_id}/{action}

Método exato

Cada ação aceita apenas o método documentado. Outro método retorna 405 e o cabeçalho Allow.

JSON estrito

Chamadas com corpo exigem application/json, objeto JSON válido e no máximo 10 MiB.

Escopo por usuário

A instância precisa pertencer à mesma conta das credenciais. Recursos de outros usuários não são revelados.

Assinatura ativa

Conta bloqueada ou instância inativa, pausada, não paga ou vencida é interrompida antes do WhatsApp. Um cancelamento agendado continua ativo até o vencimento.

Formato de chatId

DestinoFormato
Contato[email protected]
Grupo[email protected]
LID123456789012345@lid
Canal120363000000000000@newsletter
Statusstatus@broadcast
Respostas de sucesso

A WZAP-API preserva o status HTTP 2xx e retorna somente o contrato público permitido em ok, data e request_id. Campos internos da engine são descartados. Cada resposta inclui X-Request-Id.

04

Limites e compatibilidade

Planeje payloads, paginação e evolução do cliente usando somente o contrato público da WZAP-API.

ItemLimite públicoComo integrar
Corpo da fachada10 MiBPara mídia grande, prefira file.url HTTPS temporária.
Resposta do upstream8 MiBUse paginação nas consultas e não dependa de respostas ilimitadas.
Listagenslimit de 1 a 200Avance com offset e ordenação estável.
Webhooks do clienteAté 9 por instânciaAssine apenas os eventos necessários e use uma fila no recebimento.
Contatos por envio1 a 20Divida lotes maiores em chamadas independentes.

Resposta estável

Listagens usam data.items/data.count; envios retornam somente confirmação e o ID público quando disponível.

Estados assíncronos

Conexão, ativação e exclusão remota podem ficar pendentes. Consulte o estado antes de repetir uma ação.

Infraestrutura isolada

A API pública da WZAP-API é o único contrato necessário para sua integração.

Sem retry cego

Após timeout em um envio, verifique seus registros e webhooks para evitar mensagens duplicadas.

05

Ciclo de vida da instância

Crie, ative, renove e exclua instâncias da sua própria conta usando o bearer do backend.

Contrato diferente da fachada

Estas rotas usam https://wzap-api.com/endpoint/, bearer em Authorization e JSON. Criação e exclusão exigem instances:write; pagamento com saldo também exige billing:balance e Idempotency-Key. Use-as somente pelo seu backend.

POST

Criar instância

Cria a instância com Pix pendente ou debita o saldo da conta e libera uma assinatura de 30 dias.

#
https://wzap-api.com/endpoint/criar_instancia.php

Corpo JSON

application/json
{
  "nome": "Atendimento São Paulo",
  "criar_instancia": true,
  "payment_method": "balance"
}

Cabeçalho para saldo

Retry seguro
Idempotency-Key: 9f643462-ec66-49f1-977f-3cccf57d42ea

Resposta 201 Created ou 202 Accepted

application/json
{
  "status": "success",
  "instance_id": 123,
  "instance_hash": "ID_GERADO_PELO_SERVIDOR",
  "instance_token": "TOKEN_GERADO_PELO_SERVIDOR",
  "payment_status": "PAID",
  "expires_at": "2026-10-01 12:00:00",
  "balance_remaining_cents": 5010,
  "idempotent_replay": false,
  "remote_start_pending": false
}
  • nome é obrigatório e aceita de 2 a 120 caracteres.
  • O bearer precisa de instances:write; com payment_method: balance, também precisa de billing:balance.
  • criar_instancia é opcional; quando enviado, precisa ser true.
  • payment_method aceita pix ou balance. Pix devolve payment_url; saldo debita o preço do plano no servidor e libera exatamente 30 dias.
  • Para balance, gere uma chave UUID por operação, persista-a e reutilize a mesma Idempotency-Key em timeout ou retry. Trocar payload com a mesma chave retorna 409.
  • pagar_nahora: true é aceito como alias legado de payment_method: balance. O valor precisa ser booleano estrito e não pode conflitar com payment_method; caso contrário, retorna 422.
  • remote_start_pending: true não desfaz o pagamento: a assinatura já foi liberada e o worker repetirá o início da sessão.
  • Replay concluído pode responder 200. Nova criação responde 201; início remoto pendente responde 202.
  • Erros possíveis: 400 JSON inválido, 401 credenciais, 402 saldo insuficiente, 403 escopo/conta, 405 método, 409 conflito idempotente, 413 limite de 32 KiB, 422 validação e 503 ledger indisponível.
POST

Ativar ou renovar com saldo

Debita o preço do plano e concede 30 dias a uma instância existente, sem expor ou trocar seu token.

#
https://wzap-api.com/endpoint/ativar_instancia_saldo.php

Cabeçalhos

Bearer com billing:balance
Authorization: Bearer wzap_live_SEU_BEARER
Idempotency-Key: 9f643462-ec66-49f1-977f-3cccf57d42ea
Content-Type: application/json

Corpo JSON

application/json
{
  "instance_hash": "ID_DA_INSTANCIA"
}

Resposta 200 OK ou 202 Accepted

application/json
{
  "status": "success",
  "code": "balance_instance_renewed",
  "billing_source": "BALANCE",
  "idempotent_replay": false,
  "operation": "RENEW",
  "operation_id": "UUID_DA_OPERACAO",
  "payment_id": "UUID_DO_PAGAMENTO",
  "instance_id": 123,
  "instance_hash": "ID_DA_INSTANCIA",
  "amount_cents": 4990,
  "balance_remaining_cents": 5010,
  "expires_at": "2026-10-31 12:00:00",
  "vencimento": "2026-10-31 12:00:00",
  "payment_status": "PAID",
  "activation_pending": false,
  "remote_start_pending": false
}
  • O JSON aceita somente instance_hash com 32 caracteres hexadecimais. O token da instância não é necessário e nunca é retornado.
  • Gere uma UUID por aceite do cliente, persista-a e reutilize a mesma Idempotency-Key após timeout. Um replay devolve o mesmo operation_id sem novo débito.
  • Ativação vencida parte do horário atual; renovação ativa parte do vencimento existente. Ambas acrescentam exatamente 30 dias.
  • Antes do débito, Pix aberto é consultado. Pix ainda incerto responde 409 payment_in_progress; Pix já pago retorna billing_source: ATIVOPAY e não debita saldo.
  • activation_pending ou remote_start_pending indica trabalho remoto pendente, não falha ou reversão financeira.
  • Erros: 401 bearer, 402 insufficient_balance, 403 escopo/conta, 404 instance_not_found, 409 pagamento/ativação/conflito/estado, 422 corpo/chave, 429 limite e 503 billing_unavailable.
POST

Excluir instância

Desativa uma instância pertencente à conta e solicita a remoção segura da sessão correspondente.

#
https://wzap-api.com/endpoint/deletar_instancia.php

Corpo JSON

application/json
{
  "instance_hash": "ID_DA_INSTANCIA"
}

Resposta 200 OK

application/json
{
  "status": "success",
  "message": "Instância excluída.",
  "remote_cleanup_pending": false
}
  • Envie instance_hash ou, alternativamente, instance_id numérico. Se ambos forem enviados e o hash for válido, ele prevalece.
  • O endpoint também aceita o método DELETE com o mesmo corpo JSON.
  • remote_cleanup_pending: true significa que a exclusão local foi concluída, mas a limpeza da sessão ainda não foi confirmada.
  • Uma cobrança Pix ou ativação ainda pendente bloqueia a exclusão com 409, evitando que um pagamento tardio fique sem serviço.
  • Erros possíveis: 400 JSON inválido, 401 credenciais, 404 instância ausente ou de outra conta, 405 método, 409 cobrança/ativação pendente, 413 limite de 16 KiB, 422 identificador e 500 falha interna.
POST

Alterar dias diretamente — removido

A rota histórica não altera mais vencimentos. Licenças mudam somente por Pix confirmado, saldo transacional ou ação administrativa auditada.

#
https://wzap-api.com/endpoint/add_days.php

Resposta 410 Gone

application/json
{
  "status": "error",
  "code": "endpoint_retired",
  "message": "Alteração direta de vencimento foi desativada."
}
  • Não implemente fallback para esta rota. Use ativar_instancia_saldo.php ou o fluxo Pix.
06

Instância e conexão

Consulte o estado da sessão, obtenha o QR Code e controle a conexão do WhatsApp.

GET

Obter QR Code

Retorna o QR Code atual em JSON quando a sessão aguarda pareamento.

#
/instances/{instance_id}/qr
Não envie corpo nesta ação.
  • Consulte novamente apenas enquanto o status for SCAN_QR_CODE.
  • O campo mais comum na resposta é value.
GET

Consultar status

Retorna somente o estado público atual da conexão, sem configuração interna da sessão.

#
/instances/{instance_id}/status
Não envie corpo nesta ação.
  • WORKING indica uma sessão pronta para uso.
  • A resposta não inclui metadata, credenciais, webhooks internos ou configuração da engine.
POST

Reiniciar sessão

Reinicia o processo da sessão sem remover o pareamento salvo.

#
/instances/{instance_id}/restart
Não envie corpo nesta ação.
  • Não envie corpo JSON.
  • Acompanhe a conclusão pela ação status.
POST

Desconectar WhatsApp

Encerra o pareamento atual. Um novo QR Code será necessário para reconectar.

#
/instances/{instance_id}/disconnect
Não envie corpo nesta ação.
  • Não exclui o cadastro comercial da instância.
  • Esta operação é intencionalmente diferente de reiniciar.
07

Envio de mensagens

Envie texto, mídia, links, localização, contatos e mensagens interativas.

POST

Enviar texto

Envia texto para um contato, grupo, canal ou status compatível.

#
/instances/{instance_id}/send-text

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "text": "Olá! Sua confirmação chegou.",
  "linkPreview": false
}
  • A fachada força linkPreview=false para impedir buscas externas pelo motor.
  • Use reply_to para responder diretamente a uma mensagem.
  • O alias legado to/message é normalizado, mas chatId/text é o formato recomendado.
POST

Enviar imagem

Envia uma imagem por URL HTTPS pública ou Base64. URLs são importadas pela fachada e repassadas como dados.

#
/instances/{instance_id}/send-image

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "file": {
    "mimetype": "image/jpeg",
    "filename": "comprovante.jpg",
    "url": "https://cdn.exemplo.com/comprovante.jpg"
  },
  "caption": "Seu comprovante"
}
  • Para Base64 bruto, sem prefixo data URI, troque file.url por file.data.
  • URL e Base64 aceitam até 7 MiB decodificados e passam por detecção do MIME real.
POST

Enviar vídeo

Envia vídeo importado com transporte fixado ou Base64, com conversão opcional.

#
/instances/{instance_id}/send-video

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "file": {
    "mimetype": "video/mp4",
    "filename": "demonstracao.mp4",
    "url": "https://cdn.exemplo.com/demonstracao.mp4"
  },
  "caption": "Veja a demonstração",
  "convert": true
}
  • URL e Base64 bruto aceitam até 7 MiB decodificados, com validação do MIME real.
  • convert assume true quando omitido.
  • asNote pode ser usado em engines compatíveis para vídeo circular.
POST

Enviar arquivo

Envia documento importado com transporte seguro ou Base64.

#
/instances/{instance_id}/send-file

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "file": {
    "mimetype": "application/pdf",
    "filename": "contrato.pdf",
    "url": "https://cdn.exemplo.com/contrato.pdf"
  },
  "caption": "Contrato para conferência"
}
  • O corpo JSON aceita até 10 MiB; URL e Base64 aceitam mídia de até 7 MiB decodificados.
  • O MIME real e extensões executáveis são validados antes do envio.
POST

Enviar localização

Envia coordenadas geográficas e um título legível.

#
/instances/{instance_id}/send-location

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "latitude": -23.55052,
  "longitude": -46.633308,
  "title": "Unidade Centro"
}
  • latitude aceita de -90 a 90.
  • longitude aceita de -180 a 180.
POST

Enviar contato

Envia um ou mais contatos em formato de cartão.

#
/instances/{instance_id}/send-contact

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "contacts": [
    {
      "fullName": "Atendimento WZAP",
      "organization": "WZAP-API",
      "phoneNumber": "+55 11 99999-9999",
      "whatsappId": "5511999999999",
      "vcard": null
    }
  ]
}
  • São aceitos de 1 a 20 contatos por chamada.
  • whatsappId não deve conter + nem @c.us.
POST

Enviar botões

Envia uma mensagem interativa com botões de resposta, URL, ligação ou cópia.

#
/instances/{instance_id}/send-buttons

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "header": "Atendimento",
  "body": "Como podemos ajudar?",
  "footer": "Escolha uma opção",
  "buttons": [
    {"type": "reply", "text": "Financeiro", "id": "financeiro"},
    {"type": "url", "text": "Central", "url": "https://www.exemplo.com"}
  ]
}
  • A disponibilidade pode variar conforme a engine e as regras do WhatsApp.
  • São aceitos no máximo 10 botões.
POST

Enviar lista

Envia um menu com seções e linhas selecionáveis.

#
/instances/{instance_id}/send-list

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "message": {
    "title": "Menu principal",
    "description": "Selecione o assunto",
    "footer": "Equipe WZAP",
    "button": "Escolher",
    "sections": [
      {
        "title": "Atendimento",
        "rows": [
          {"title": "Financeiro", "rowId": "financeiro", "description": "Pagamentos e notas"},
          {"title": "Suporte", "rowId": "suporte", "description": "Ajuda técnica"}
        ]
      }
    ]
  }
}
  • A disponibilidade depende da engine conectada.
  • rowId deve ser único dentro da lista.
08

Operações em mensagens

Marque conversas como lidas, apague, reaja, encaminhe ou responda mensagens existentes.

POST

Marcar como lida

Marca as mensagens pendentes de um chat como visualizadas.

#
/instances/{instance_id}/mark-as-read

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "messageIds": [
    "[email protected]_AAAAAAAAAAAAAAAAAAAA"
  ]
}
  • messageIds é opcional para marcar as pendências do chat.
  • Em grupos, participant pode ser necessário em algumas engines.
DELETE

Apagar mensagem

Solicita a remoção de uma mensagem pelo identificador completo.

#
/instances/{instance_id}/delete-message

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "messageId": "[email protected]_AAAAAAAAAAAAAAAAAAAA"
}
  • O WhatsApp aplica limites de tempo e permissão próprios.
  • Esta ação apaga mensagem; não exclui a instância.
PUT

Adicionar ou remover reação

Adiciona uma reação a uma mensagem ou a remove enviando texto vazio.

#
/instances/{instance_id}/send-reaction

Corpo JSON

application/json
{
  "messageId": "[email protected]_AAAAAAAAAAAAAAAAAAAA",
  "reaction": "👍"
}
  • Envie reaction como string vazia para remover a reação.
  • Use o messageId completo recebido no webhook.
POST

Encaminhar mensagem

Encaminha uma mensagem existente para outro chat.

#
/instances/{instance_id}/forward-message

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "messageId": "[email protected]_AAAAAAAAAAAAAAAAAAAA"
}
  • chatId é o destino.
  • messageId identifica a mensagem de origem.
POST

Responder mensagem

Envia texto vinculado a uma mensagem anterior.

#
/instances/{instance_id}/reply-message

Corpo JSON

application/json
{
  "chatId": "[email protected]",
  "reply_to": "[email protected]_AAAAAAAAAAAAAAAAAAAA",
  "text": "Recebemos sua mensagem e já vamos ajudar."
}
  • messageId/message também são normalizados para reply_to/text.
  • A resposta é contabilizada como mensagem de texto.
09

Chats, contatos e grupos

Consulte dados armazenados pela engine usando paginação e ordenação controladas.

GET

Listar contatos

Lista os contatos disponíveis para a sessão.

#
/instances/{instance_id}/get-contacts?limit=100&offset=0&sortBy=name&sortOrder=asc
Não envie corpo nesta ação.
  • limit: 1 a 200; offset: 0 a 100000.
  • sortBy: id ou name; sortOrder: asc ou desc.
POST

Verificar número

Confirma se um número internacional está disponível e retorna somente um identificador seguro quando existir.

#
/instances/{instance_id}/check-number

Corpo JSON

application/json
{
  "phone": "5511999999999"
}
  • phone aceita de 8 a 15 dígitos no padrão E.164, sem o sinal +.
  • A resposta inclui numberExists/number_exists e chatId/chat_id; nenhuma configuração interna é devolvida.
GET

Listar chats

Lista conversas com paginação, ordenação e união opcional de LID.

#
/instances/{instance_id}/get-chats?limit=100&offset=0&sortBy=conversationTimestamp&sortOrder=desc&merge=true
Não envie corpo nesta ação.
  • sortBy: conversationTimestamp, id ou name.
  • merge aceita true ou false.
GET

Listar grupos

Lista grupos da sessão sem carregar participantes por padrão.

#
/instances/{instance_id}/groups?limit=100&offset=0&sortBy=id&sortOrder=desc&exclude=participants
Não envie corpo nesta ação.
  • sortBy: id ou subject.
  • exclude aceita somente participants.
10

Configuração de webhooks

Gerencie destinos do cliente e callbacks server-to-server sem expor configurações operacionais.

GET

Consultar webhooks

Lista somente os webhooks do cliente confirmados na instância.

#
/instances/{instance_id}/get-webhooks
Não envie corpo nesta ação.
  • Webhooks operacionais e de integrações privadas nunca são retornados.
  • Chaves HMAC e valores de cabeçalhos personalizados são substituídos por indicadores de configuração.
PUT

Salvar webhooks

Atualiza exclusivamente config.webhooks da sessão autenticada.

#
/instances/{instance_id}/save-webhooks

Corpo JSON

application/json
{
  "config": {
    "webhooks": [
      {
        "url": "https://app.exemplo.com/webhooks/wzap",
        "events": ["message", "message.ack", "session.status"],
        "hmac": {"key": "uma-chave-secreta-com-32-caracteres"},
        "retries": {
          "policy": "exponential",
          "delaySeconds": 2,
          "attempts": 5
        },
        "customHeaders": [
          {"name": "X-Integration-Id", "value": "wzap-producao"}
        ]
      }
    ]
  }
}
  • O destino deve ser HTTPS público na porta 443. DNS e IP são revalidados em cada entrega; redes privadas, reservadas, redirects e proxies são bloqueados.
  • Envie config.webhooks como [] para remover todos os webhooks do cliente; o webhook operacional interno é preservado.
  • Idempotency-Key é opcional neste PUT; quando enviado, um replay do mesmo payload devolve a resposta persistida e outro payload recebe 409.
  • A resposta só confirma os destinos e eventos; HMAC, valores de cabeçalhos, metadata, referência opaca do relay e configuração interna nunca são devolvidos.
  • São aceitos até 9 webhooks do cliente e 25 eventos por webhook.
  • Depois de um 2xx confirmado, o mesmo corpo autenticado não é reenviado. A entrega continua sendo pelo menos uma vez em timeouts ambíguos; deduplicate pelo X-Webhook-Request-Id.
POST

Registrar callback de integração

Faz upsert do callback privado configurado no servidor e preserva os webhooks de cliente protegidos pelo relay.

#
/instances/{instance_id}/register-integration-webhook
Não envie corpo nesta ação.
  • Disponível somente para a conta técnica vinculada no servidor; outras credenciais recebem 404.
  • Pode ser chamada logo após adopt-integration, mesmo com a instância ainda suspensa; proprietário, token e vínculo gerenciado são revalidados sob lock.
  • Configurações diretas legadas precisam ser reconciliadas para o relay antes do upsert.
  • Exige Idempotency-Key de 8 a 120 caracteres seguros.
  • Se uma gravação/verificação anterior ficar uncertain, repetir exatamente a mesma chave e configuração reexecuta este upsert determinístico; envios ambíguos nunca recebem esse tratamento.
  • Não envie URL, eventos ou HMAC: a ação não aceita corpo e usa apenas a configuração privada.
  • O servidor confirma a gravação com um novo GET; a resposta nunca contém URL, segredo ou resposta interna.
POST

Adotar instância legada

Vincula explicitamente uma sessão existente ao identificador reservado da integração sem trocar ID, token ou webhooks.

#
/instances/{instance_id}/adopt-integration

Corpo JSON

application/json
{
  "source_ref": "wdivulga-user-0123456789abcdef0123456789abcdef"
}
  • Disponível somente para a conta técnica configurada e uma instância ativa pertencente a ela; outras credenciais recebem 404.
  • Exige o token atual da instância e Idempotency-Key de 8 a 120 caracteres seguros.
  • A referência deve seguir exatamente wdivulga-user-<32 hex> e estar livre ou já pertencer à mesma instância.
  • Uma adoção nova responde 202 e começa suspensa por segurança; em seguida chame resume-integration somente se a assinatura local estiver válida.
  • Replays preservam o lifecycle atual e nunca reativam uma instância suspensa.
POST

Suspender instância da integração

Revoga imediatamente o uso pela fachada e agenda a pausa da sessão preservando ID e token.

#
/instances/{instance_id}/suspend-integration
Não envie corpo nesta ação.
  • Disponível somente para a conta técnica e instâncias com billing externo gerenciado; outras credenciais recebem 404.
  • Exige Idempotency-Key de 8 a 120 caracteres seguros.
  • HTTP 200 indica pausa confirmada; HTTP 202 indica revogação local aplicada e sincronização remota pendente no worker.
  • Repetir a mesma chave devolve a resposta persistida sem aplicar uma segunda transição.
POST

Retomar instância da integração

Agenda a retomada da sessão preservada e só libera envios depois da confirmação remota.

#
/instances/{instance_id}/resume-integration
Não envie corpo nesta ação.
  • Disponível somente para a conta técnica e instâncias com billing externo gerenciado; outras credenciais recebem 404.
  • Exige Idempotency-Key de 8 a 120 caracteres seguros.
  • HTTP 200 indica retomada confirmada; HTTP 202 mantém a fachada bloqueada enquanto o worker tenta novamente.
  • A operação não recria nem devolve credenciais da instância.
11

Receber webhooks com segurança

Valide a assinatura do corpo bruto antes de processar qualquer evento.

1EventoA sessão produz o evento.
2AssinaturaHMAC-SHA512 do corpo bruto.
3Seu endpointValida, responde 2xx e processa.

Cabeçalhos recebidos

PHP · validar HMAC antes do JSON
<?php
$secret = getenv('WZAP_WEBHOOK_SECRET');
$rawBody = file_get_contents('php://input');
$received = strtolower(trim($_SERVER['HTTP_X_WEBHOOK_HMAC'] ?? ''));
$algorithm = strtolower($_SERVER['HTTP_X_WEBHOOK_HMAC_ALGORITHM'] ?? '');
$timestampHeader = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$requestId = $_SERVER['HTTP_X_WEBHOOK_REQUEST_ID'] ?? '';

if (
    !is_string($secret) || $secret === ''
    || $algorithm !== 'sha512'
    || !preg_match('/^[a-f0-9]{128}$/', $received)
    || !preg_match('/^\d{10,16}$/', $timestampHeader)
) {
    http_response_code(401);
    exit;
}

$sentAt = (int) $timestampHeader;
if ($sentAt > 9999999999) {
    $sentAt = (int) floor($sentAt / 1000);
}
if (abs(time() - $sentAt) > 300) {
    http_response_code(401);
    exit;
}

$expected = hash_hmac('sha512', $rawBody, $secret);
if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit;
}

$event = json_decode($rawBody, true, 64, JSON_THROW_ON_ERROR);
http_response_code(204);

// Deduplique por $requestId e processe $event em fila.

Eventos principais

session.status message message.any message.ack message.reaction message.edited message.revoked chat.archive group.v2.join group.v2.leave group.v2.participants group.v2.update presence.update poll.vote call.received

Evite assinar * em produção: eventos desnecessários aumentam tráfego, custo e superfície de processamento.

12

Erros e status HTTP

Erros da fachada possuem estrutura estável e um request ID para diagnóstico.

Resposta de erro
{
  "ok": false,
  "error": {
    "code": "validation_error",
    "message": "O campo chatId é obrigatório.",
    "request_id": "7df043fe82bb56b928b132f4",
    "field": "chatId"
  }
}
HTTPSignificadoAção recomendada
400Rota, corpo ou JSON inválido.Corrija a requisição; não repita igual.
401Credenciais ausentes ou inválidas.Revise o bearer e gere outro se ele tiver sido rotacionado.
402Assinatura pausada, não paga ou vencida.Regularize a instância no painel.
403Conta bloqueada.Fale com o suporte.
404Ação inexistente, instância não encontrada ou token inválido.Revise rota, propriedade e token.
405Método HTTP incorreto.Use o método indicado em Allow.
409Estado atual incompatível com a operação.Consulte status, ajuste o fluxo e tente novamente.
410Instância inativa.Crie ou reative uma instância válida.
413Corpo ou mídia maior que o limite da rota.Mantenha o JSON em até 10 MiB e a mídia URL/Base64 em até 7 MiB decodificados.
415Content-Type incorreto.Envie application/json.
422Campo inválido.Corrija o campo apontado no erro.
429Limite temporário no serviço de WhatsApp.Aguarde e use backoff com jitter.
502Serviço de WhatsApp indisponível ou recusou autenticação interna.Repita apenas se a operação for segura.
504Tempo limite excedido.Consulte o estado antes de repetir um envio.
Suporte eficiente

Ao abrir um chamado, informe o horário, a ação e o request_id. Nunca envie bearer, API key legada, CSRF token ou token da instância.

13

Boas práticas de produção

Integrações confiáveis evitam vazamento de segredos e duplicidade de mensagens.

01

Somente no backend

Guarde credenciais em variáveis de ambiente ou cofre de segredos. Não chame a API diretamente do navegador.

02

Timeout consciente

Use timeout de conexão e de resposta. Em caso de dúvida após timeout, consulte status ou seus registros antes de reenviar.

03

Retry seletivo

Repita 429, 502 e 504 com backoff exponencial e jitter. Não repita automaticamente erros 4xx de validação.

04

Evite duplicidade

Quando o tipo de mensagem aceitar id, gere e reutilize um identificador estável ao tentar novamente.

05

Webhook rápido

Valide HMAC, deduplique pelo request ID, responda 2xx rapidamente e processe em fila.

06

Mídia segura

Use URLs HTTPS públicas temporárias de até 7 MiB, sem redirects. A fachada fixa o IP, valida o MIME e importa o arquivo antes do envio interno.

07

Observabilidade sem segredo

Registre ação, status, latência e request ID. Nunca registre Authorization, X-Csrf-Token ou X-Instance-Token.

08

Ritmo humano

Respeite consentimento, contexto e limites do WhatsApp. Automação agressiva aumenta bloqueios e reclamações.