Documentação da API e do MCP
Ligue a ProtectZap ao seu sistema pela API, receba avisos por webhook e opere a conta por MCP. Esta página explica o que vale para todos os produtos; os endereços, avisos e ferramentas de cada um ficam na página do produto.
Produtos
Cada produto tem a sua API, com endereço base próprio. A mesma chave pode valer para mais de um produto.
Começo rápido
1. No painel, abra Integrações › Chaves de acesso e clique em Nova chave. Escolha os produtos que a chave pode usar, a permissão (Leitura, ou Leitura e escrita) e a validade. A chave aparece uma vez só: guarde num lugar seguro.
2. Faça a primeira consulta. Por exemplo, os contatos do Disparos:
curl https://www.protectzap.com.br/api/v1/disparos/contatos \
-H "Authorization: Bearer SUA_CHAVE"3. Siga para a página do produto que você vai integrar, com os endereços, exemplos e avisos dele.
Chaves e autenticação
Toda chamada leva a chave no cabeçalho Authorization: Bearer pzg_live_....
- Produtos: a chave vale só para os produtos escolhidos na criação, e só enquanto a conta tem o plano de cada um. Chamar a API de um produto que a chave não inclui é recusado com
produto_ausente. - Permissão: Leitura só consulta; Leitura e escrita consulta e age. Use a de leitura onde só precisa consultar. Cada endereço diz a permissão que exige.
- Validade: 30, 90 ou 365 dias. Chave que muda algo vale no máximo 365 dias; a de leitura também pode não vencer. Dá para limitar a chave a uma lista de IPs.
- A chave completa aparece uma vez, na criação. A ProtectZap guarda só uma impressão dela. Até 10 chaves ativas por conta.
- Criar e revogar chave avisa o dono no painel, e a chave que muda algo, usada de um IP novo, também.
- Nunca ponha a chave na URL. Ela fica gravada em log, por isso é revogada na hora em que aparece numa URL.
- A API é para servidor: chamada feita pelo navegador, de uma página de outro site, é recusada.
O Disparos tem também a Chave de Eventos, criada na própria automação: ela só coloca pessoas na fila daquela automação e não lê nada. Detalhes na página do Disparos.
Formato e ids
Pedidos e respostas em JSON. A resposta tem sempre o mesmo formato:
{ "success": true, "data": { ... } }
{ "success": false, "error": { "codigo": "nao_encontrado", "mensagem": "..." } }Os ids levam um prefixo que diz o que são. Um id de um tipo no lugar de outro é recusado com id_de_outro_tipo.
| Prefixo | O que é | Produto |
|---|---|---|
| num_ | número da conta | Todos |
| whk_ | webhook | Todos |
| whe_ | aviso de webhook | Todos |
| ctt_ | contato | Disparos |
| dsp_ | campanha | Disparos |
| aut_ | automação | Disparos |
| evt_ | evento (uma pessoa na fila de uma automação) | Disparos |
Datas em ISO 8601 com fuso (2026-11-10T19:00:00-03:00). Horários de regra (janela de envio, recorrência) são de Brasília. Telefones com DDI e DDD, só dígitos.
Simular e repetir com segurança
O que chega às pessoas pode ser conferido antes. Nos Grupos, os endereços marcados com Aceita simular devolvem a prévia com "simular": true no corpo, sem gravar nada; no Disparos, a campanha tem o endereço próprio /simular.
Os endereços que criam algo que chega às pessoas pedem o cabeçalho Idempotency-Key (de 8 a 100 caracteres: letras, números e _ - : ., por exemplo um uuid); cada endereço diz se exige. A mesma chave devolve o mesmo resultado em vez de agir de novo: se a sua chamada cair no meio, repita com a mesma chave sem medo de mandar duas vezes. Os eventos das automações usam o identificador do próprio evento para isso.
Mudanças em algo que pode ter mudado no meio do caminho (o texto de um envio ou de uma campanha rodando) pedem a versao que você leu. Se alguém mexeu depois, a resposta é 409 e você lê de novo.
Limites
Os limites existem para uma chave vazada não virar estrago. Valem para todos os produtos:
- 120 chamadas por minuto por chave e 300 por conta, somando as chaves. Passou, a resposta é 429 com
Retry-After. No Disparos, um lote de contatos ou de eventos conta 1 chamada a cada 10 itens. - Corpo de até 1 MB na API e 256 KB no MCP, onde um lote conta uma chamada por mensagem (até 20).
- 20 chaves inválidas de um mesmo IP em 10 min deixam o IP 15 min sem acesso.
- A API não acelera nada: os envios seguem o mesmo ritmo e as mesmas regras da tela.
Cada produto tem ainda os seus: a cota de mensagens do mês no Disparos e a cota diária de envios e ações em massa nos Grupos.
Erros
O codigo é fixo e serve para o seu sistema decidir; a mensagem é para gente e pode mudar. Estes valem para todos os produtos; os próprios de cada produto estão na página dele.
| Status | Código | Quando |
|---|---|---|
| 401 | nao_autenticado | Chave ausente, inválida, vencida ou revogada. A resposta é a mesma nos quatro casos. |
| 401 | chave_na_url | A chave apareceu na URL. Ela é revogada na hora, porque a URL fica gravada em log: crie outra e mande só no cabeçalho. |
| 403 | escopo_ausente | A chave é só de leitura e o endereço pede leitura e escrita, ou é uma Chave de Eventos usada fora da automação dela. |
| 403 | produto_ausente | A chave não inclui o produto do endereço (uma chave só dos Grupos chamando a API de Disparos). |
| 403 | sem_acesso | A conta não tem o plano que dá acesso à API do produto. |
| 403 | ip_nao_permitido | A chave tem lista de IPs e a chamada veio de outro. |
| 403 | origem_recusada | A chamada veio de uma página de outro site (navegador). A API é para servidor. |
| 400 | pedido_invalido | Corpo ou parâmetro inválido. A mensagem diz o que corrigir. |
| 400 | id_invalido | O id não está no formato do prefixo. |
| 400 | id_de_outro_tipo | Um id de outro tipo no lugar errado (um ctt_ onde se espera dsp_). |
| 400 | idempotency_key_ausente | O endereço exige o cabeçalho Idempotency-Key e ele não veio, ou veio fora do formato (8 a 100 caracteres: letras, números e _ - : .). |
| 404 | nao_encontrado | Não existe, ou é de outra conta. Em parte dos endereços o código diz o recurso (campanha_nao_encontrada, envio_nao_encontrado, webhook_nao_encontrado); todo 404 quer dizer o mesmo. |
| 409 | conflito | A situação mudou no meio do caminho (outra edição entrou antes, o item já saiu ou está saindo). Leia de novo antes de repetir. |
| 413 | pedido_grande | Corpo acima do tamanho máximo. |
| 429 | limite_excedido | Limite de chamadas por minuto da chave (o cabeçalho Retry-After diz quanto esperar) ou de usos por hora de um recurso, como a IA dos Grupos. |
| 429 | limite_da_conta | Limite de chamadas por minuto da conta, somando as chaves. |
| 429 | ip_bloqueado | Muitas chaves inválidas deste IP em pouco tempo. Espere o tempo do Retry-After. |
| 502 | falha_externa | O WhatsApp não respondeu como esperado ao pedido. Tente de novo em instantes. |
| 500 | erro_interno | Falha do nosso lado. Tente de novo em instantes; se continuar, fale com o suporte. |
| 503 | indisponivel | Não foi possível conferir a chave ou o limite agora. Tente de novo em instantes. |
Webhooks
Um webhook manda um POST para o seu endereço (https público) quando algo acontece. O cadastro é da conta: até 5 por conta, cada um com os avisos que pedir, de qualquer produto que a conta usa. Crie pela tela (Integrações › Webhooks) ou pela API de um dos produtos. O corpo é sempre:
{ "id": "6f1b2c3d-...", "tipo": "disparos.evento.enviado", "criado_em": "2026-11-10T19:41:07.512Z", "dados": { ... } }O id é o do aviso: na API, o mesmo aviso aparece como whe_ seguido desse id.
Cabeçalhos: X-ProtectZap-Evento (o id, igual ao do corpo), X-ProtectZap-Tipo, X-ProtectZap-Tentativa e X-ProtectZap-Assinatura. Os mesmos valores seguem também nos cabeçalhos X-ProtectGroups-*, para quem já recebia antes.
Confira a assinatura antes de confiar no aviso. Ela é t=<segundos>,v1=<hex>, onde v1 é o HMAC-SHA256 de t.corpo com o segredo do webhook. Use o corpo cru, exatamente como chegou, e recuse horário com mais de 5 minutos:
import crypto from "node:crypto"
function conferirAssinatura(segredo, cabecalho, corpoCru) {
const p = Object.fromEntries(cabecalho.split(",").map((s) => s.trim().split("=")))
const t = Number(p.t)
if (!t || !p.v1 || Math.abs(Date.now() / 1000 - t) > 300) return false
const esperado = crypto.createHmac("sha256", segredo).update(`${t}.${corpoCru}`).digest()
const recebido = Buffer.from(p.v1, "hex")
return recebido.length === esperado.length && crypto.timingSafeEqual(recebido, esperado)
}- Responda 2xx em até 10 segundos. Sem isso, tentamos de novo em 1 min, 5 min, 30 min, 2 h, 6 h, 12 h.
- O mesmo aviso pode chegar mais de uma vez (nova tentativa ou reenvio pelo painel): use o
idpara descartar o repetido. - Um endereço que falha sem parar por 3 dias é desligado e o dono é avisado. Religar entrega o que ficou na fila.
- Não seguimos redirecionamento e só entregamos para endereço público.
- O catálogo de avisos de cada produto está na página dele. O botão Testar manda um
webhook.teste.
MCP
O servidor MCP (Model Context Protocol) permite que qualquer aplicação compatível, como um aplicativo de IA, consulte e opere a conta com a mesma chave da API. É um servidor só, chamado protectzap: ele mostra as ferramentas dos produtos da chave. Endereço: https://www.protectzap.com.br/api/mcp. Transporte HTTP (Streamable HTTP), sem sessão, com a chave no cabeçalho Authorization: Bearer SUA_CHAVE.
Exemplo de configuração no formato mcpServers, aceito pela maioria das aplicações compatíveis:
{
"mcpServers": {
"protectzap": {
"type": "http",
"url": "https://www.protectzap.com.br/api/mcp",
"headers": {
"Authorization": "Bearer SUA_CHAVE"
}
}
}
}Nada chega às pessoas sem a sua confirmação. As ferramentas que planejam devolvem o plano e um código; só a ferramenta confirmar executa, com a mesma chave, em até 15 minutos e uma vez. Se o plano mudou entre planejar e confirmar (um número caiu, o público mudou), nada é executado e a aplicação recebe a diferença. Chave de leitura não vê nem chama confirmar.
Textos e nomes que vêm do WhatsApp ou do seu sistema chegam à aplicação marcados como dados: o servidor a instrui a nunca obedecer a algo escrito neles. As ferramentas de cada produto estão na página dele.