Documentação
ZAP API
API REST para enviar e receber mensagens WhatsApp. Autentique com Bearer token, gerencie instâncias e configure webhooks em minutos.
https://api.zap-api.tech/v1Em 3 passos você já está enviando mensagens WhatsApp via API.
Criar uma instância
No dashboard, acesse Instâncias → Nova Instância e dê um nome.
Conectar via QR Code
Clique em Conectar e escaneie o QR Code com seu WhatsApp.
Copiar o token
Acesse Credenciais na instância e copie o Bearer token.
curl -X POST https://api.zap-api.tech/v1/instances/inst_xxx/send \
-H "Authorization: Bearer tk_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"phone":"5511999999999","type":"text","body":"Olá! API funcionando ✅"}'Cada instância possui um Bearer token único. Inclua-o em todas as requisições no header Authorization.
Header obrigatório
Authorization: Bearer tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Node.js (axios)
const axios = require('axios');
const api = axios.create({
baseURL: 'https://api.zap-api.tech/v1',
headers: {
'Authorization': 'Bearer tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'Content-Type': 'application/json',
},
});
const response = await api.post('/instances/inst_xxx/send', {
phone: '5511999999999',
type: 'text',
body: 'Olá! Mensagem via ZAP API.',
});
console.log(response.data);Python (requests)
import requests
headers = {
"Authorization": "Bearer tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
}
resp = requests.post(
"https://api.zap-api.tech/v1/instances/inst_xxx/send",
json={"phone": "5511999999999", "type": "text", "body": "Olá via Python!"},
headers=headers,
)
print(resp.json())Cada instância representa uma conexão WhatsApp independente com seu próprio token.
/instances/:id/instances/:id/status/instances/:id/qrcode/instances/:id/connect/instances/:id/pairing/instances/:id/disconnectGET /instances — listar
curl https://api.zap-api.tech/v1/instances \ -H "Authorization: Bearer tk_xxxxxxxxxxxx"
{
"instances": [
{
"id": "inst_abc123",
"name": "Suporte",
"status": "connected",
"phone": "+5511999999999",
"plan": "pro",
"createdAt": "2026-01-15T10:00:00Z"
}
]
}POST /instances/:id/connect — conectar
Inicia (ou reinicia) a conexão da instância. Em seguida, busque o QR Code em /qrcode e escaneie pelo WhatsApp.
curl -X POST https://api.zap-api.tech/v1/instances/inst_abc123/connect \ -H "Authorization: Bearer tk_xxxxxxxxxxxx"
GET /instances/:id/qrcode — QR Code
QRCODE, chame POST /connect primeiro e tente de novo.curl https://api.zap-api.tech/v1/instances/inst_abc123/qrcode \ -H "Authorization: Bearer tk_xxxxxxxxxxxx"
{
"instanceId": "inst_abc123",
"qrCode": "data:image/png;base64,iVBORw0KGgo...",
"status": "qr_required"
}GET /instances/:id/status — status de conexão
{
"instanceId": "inst_abc123",
"waStatus": "CONNECTED",
"connected": true,
"number": "5511999999999",
"name": "Suporte",
"profilePicUrl": null,
"qrcode": null
}Principais valores de waStatus:
CONNECTEDDISCONNECTEDQRCODE/instances/:id/send/instances/:id/send/batch/instances/:id/send/scheduletype: text, image, audio, video, document, sticker, gif, location, contact, link, reaction, poll, buttons, list, product, order, pix, event.POST /instances/:id/send — texto
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
phone | string | sim | Número com DDI, só dígitos, sem + (ex: 5511999999999) ou JID de grupo (@g.us) |
type | string | sim | Tipo da mensagem — use "text" |
body | string | sim | Conteúdo do texto (1–4096 caracteres) |
previewUrl | boolean | opcional | Gera preview do link no texto |
quotedMessageId | string | opcional | ID de uma mensagem para responder/citar |
curl -X POST https://api.zap-api.tech/v1/instances/inst_abc123/send \
-H "Authorization: Bearer tk_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"phone": "5511999999999",
"type": "text",
"body": "Seu pedido #1234 foi confirmado. ✅"
}'body — nunca text ou message. Um 200 significa que a mensagem foi aceita na fila — acompanhe a entrega real em /messages/status/:msgId ou pelo webhook message.status.POST /instances/:id/send — mídia (imagem, vídeo, documento…)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
phone | string | sim | Número com DDI, só dígitos, sem + |
type | string | sim | image, video, gif, audio, document, sticker… |
mediaUrl | string | sim | URL pública do arquivo (jpg, png, pdf, mp4…) |
caption | string | opcional | Legenda (image / video / gif / document) |
fileName | string | opcional | Nome do arquivo (obrigatório para document) |
curl -X POST https://api.zap-api.tech/v1/instances/inst_abc123/send \
-H "Authorization: Bearer tk_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"phone": "5511999999999",
"type": "document",
"mediaUrl": "https://exemplo.com/boleto.pdf",
"fileName": "boleto-fev-2026.pdf",
"caption": "Seu boleto de fevereiro"
}'Configure uma URL no seu servidor para receber eventos em tempo real: mensagens recebidas, mudanças de status e confirmações de entrega.
Configurar webhook
Configure via API com PUT /instances/:id/webhook ou pelo Dashboard em Instâncias → Webhook. A URL deve ser HTTPS e pública (não localhost).
curl -X PUT https://api.zap-api.tech/v1/instances/inst_abc123/webhook \
-H "Authorization: Bearer tk_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://seu-servidor.com/webhook",
"events": ["message.received", "message.status"],
"secret": "sua_chave_secreta"
}'POST /webhook/test.Eventos disponíveis
message.receivedmessage.sentmessage.statusmessage.readinstance.connectedinstance.disconnectedSão 21 eventos no total (também grupos, contatos, presença, chamadas, status e newsletter). Inscreva só os que precisar no campo events.
Payload — message.received
{
"event": "message.received",
"instanceId": "inst_abc123",
"timestamp": "2026-02-15T14:30:00Z",
"data": {
"messageId": "msg_xyz789",
"from": "5511999999999",
"name": "João Silva",
"type": "text",
"body": "Olá, quero saber sobre o produto",
"quotedMessage": null
}
}Verificação HMAC-SHA256
Configure um Webhook Secret na instância. Cada entrega traz o header X-ZapAPI-Signature-256 no formato sha256=<hmac-hex> (padrão GitHub). O header legado X-Zap-Signature é mantido por compatibilidade.
const crypto = require('crypto');
app.post('/webhook', (req, res) => {
const payload = JSON.stringify(req.body);
const header = req.headers['x-zapapi-signature-256'] || '';
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(payload)
.digest('hex');
// comparação em tempo constante (evita timing attack)
const ok = header.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
if (!ok) {
return res.status(401).json({ error: 'Unauthorized' });
}
const { event, data } = req.body;
console.log('Evento recebido:', event, data);
res.json({ ok: true });
});Limite de envio por instância, por minuto. Ao atingir o teto a API retorna HTTP 429 com o header Retry-After. Não há limite mensal de envio — a cobrança é apenas por instância ativa.
| Plano | Envio/min | Preço por instância | Retenção de logs |
|---|---|---|---|
| Trial | 30 | Grátis por 7 dias | — |
| Pago | 120 | R$ 49 (1ª e 2ª) · R$ 29 (3ª+) | 30 dias |
Todos os erros seguem o formato: { "error": "ERROR_CODE", "message": "texto explicativo" }. Em um 404 de rota não-escopada, a resposta inclui o campo hint com o caminho correto.
| HTTP | Significado | Causa comum |
|---|---|---|
200 | OK | Aceito (no envio: enfileirado, não necessariamente entregue) |
400 | VALIDATION_ERROR | Campo obrigatório ausente/inválido (ex: phone, type, body) |
401 | Unauthorized | Bearer token inválido ou ausente |
404 | ROUTE_NOT_SCOPED | Rota chamada sem /instances/:id — use o campo hint da resposta |
409 | NOT_CONNECTED | Instância não está conectada (waStatus ≠ CONNECTED) |
422 | SELF_SEND_BLOCKED | Tentativa de enviar para o próprio número da instância |
429 | Too Many Requests | Rate limit por minuto atingido — veja Retry-After |
503 | CIRCUIT_OPEN | Circuit breaker aberto após falhas — aguarde ~60s |
Pronto para integrar?
7 dias grátis · sem cartão · instância funcionando em minutos.