Pular para o conteúdo principal

Referência da API

A fonte única é o OpenAPI (packages/sdk/openapi.yaml), que gera o SDK TypeScript e esta referência. Abaixo, os endpoints do núcleo com exemplos reais. Autentique com Authorization: Bearer bz_live_....

Enviar texto — POST /messages/text​

Só to e body são obrigatórios. Não informe o número de origem e o bZapper escolhe um do seu pool (distribuição + afinidade de conversa):

curl -X POST https://api.bzapper.com.br/messages/text \
-H "Authorization: Bearer $BZ_KEY" -H "Content-Type: application/json" \
-d '{"to":"+5511988888888","body":"Olá","client_reference":"lead-42"}'
import requests
requests.post("https://api.bzapper.com.br/messages/text",
headers={"Authorization": f"Bearer {key}"},
json={"to": "+5511988888888", "body": "Olá"})
await fetch("https://api.bzapper.com.br/messages/text", {
method: "POST",
headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
body: JSON.stringify({ to: "+5511988888888", body: "Olá" }),
});
<?php
$ch = curl_init("https://api.bzapper.com.br/messages/text");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $key", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode(["to" => "+5511988888888", "body" => "Olá"]),
CURLOPT_RETURNTRANSFER => true,
]);
$res = curl_exec($ch);

Resposta 202: { "message_id": "...", "status": "queued", "client_reference": "lead-42" }.

instance_id é opcional

instance_id (e pool_id) não são obrigatórios. Omita-os e o gateway escolhe o número (rotação/sticky). Informe instance_id apenas para forçar um número específico — ex.: {"instance_id":"<id>","to":"...","body":"..."}. Veja Listar números para obter os ids. Detalhes do comportamento em Atendimento.

Listar números — GET /instances​

Lista as instâncias (números) do projeto, com o id que você usa como instance_id em envios direcionados. Requer o escopo instances:read.

curl https://api.bzapper.com.br/instances -H "Authorization: Bearer $BZ_KEY"
{ "data": [
{ "id": "ce…", "phone": "+5511…", "nickname": "Suporte", "status": "connected", "health_score": 100 }
] }

No admin, a tela Números mostra o instance_id de cada número com um botão de copiar.

Idempotência no envio​

Se você repete um envio sozinho (timeout, fila com retry), mande o cabeçalho Idempotency-Key com um valor único por mensagem (ex.: um UUID ou o id da mensagem no seu sistema). Vale em todas as rotas POST /messages/{tipo}:

curl -X POST https://api.bzapper.com.br/messages/text \
-H "Authorization: Bearer $BZ_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-4412-aviso-1" \
-d '{"to":"+5511988888888","body":"Seu pedido saiu para entrega"}'
  • A mesma chave na mesma conta, por 24 horas, devolve a mesma resposta (mesmo message_id) com o cabeçalho Idempotent-Replayed: true — a mensagem não é enviada de novo.
  • A 1ª ainda está em andamento → 409 idempotency_in_progress: repita em alguns segundos.
  • Mesma chave com outro corpo → 422 idempotency_key_reused: use uma chave nova por mensagem.
  • A 1ª falhou (qualquer resposta que não seja 2xx) → a chave é liberada e pode ser usada de novo.
  • Até 255 caracteres (400 idempotency_key_invalid). Sem o cabeçalho, nada muda.

Outros do núcleo​

  • POST /messages/{image,video,document,audio,sticker,location,contact,poll,reaction,buttons,list}
  • POST /messages/otp — código de verificação em 2 mensagens (texto + balão do código); conta como 1 envio. O código nunca é persistido nem exibido no inbox (mascarado + echoguard). Omitindo body, a API gera o texto no idioma da conta. Detalhes em Tipos de mensagem → OTP.
  • POST /contacts/check — IsOnWhatsApp (trata @lid)
  • POST /contacts/import · GET /contacts/export — importação em lote (até 1000 linhas, upsert por telefone, dry_run) e exportação CSV com os filtros da listagem; ver Gestão de contatos
  • POST /keys/{id}/rotate — rotaciona a API key mantendo a antiga viva por uma carência; ver Rotação de API key
  • GET /conversations?instance_id= e GET /conversations/{jid}/messages — inbox
  • GET /media/{id} — referência estável da mídia recebida (privada): responde 302 para uma URL pré-assinada fresca. Ver Tipos de mensagem.
  • POST /webhooks — registrar webhook (HMAC); ver o guia de webhooks
  • GET /stream — SSE em tempo real
  • GET /usage — telemetria de uso
  • GET /me/entitlements · GET /me/subscription · GET /me/invoices — plano, limites e faturas da conta; ver Cobrança

Erros​

Todo erro tem código neutro estável + mensagem traduzida:

{ "code": "not_connected", "message": "Número desconectado...", "locale": "pt-BR" }

Use o code na lógica. Comuns: unauthorized, forbidden, rate_limited, not_connected, no_number_available, not_supported (experimental).

Rate limit​

O limite é um token bucket por API key (por IP nas rotas sem autenticação). O padrão é 20 requisições por segundo, com pico (burst) de 40. Contas com enforcement de plano ligado usam o teto do próprio plano (veja GET /me/entitlements).

Ao estourar, a API responde 429 com code: "rate_limited" e o header Retry-After: 1 — o balde repõe tokens em frações de segundo, e 1 s é a menor espera que o header consegue expressar. Não há headers X-RateLimit-*. Faça backoff no cliente; as SDKs oficiais já respeitam o Retry-After.

Tamanho de mídia​

O quêTeto
Mídia enviada a partir de uma URL (media_url)64 MiB
Upload de imagem de campanha5 MB
Upload de logo/avatar (conta, projeto, white-label)5 MB

Acima do teto a API responde com media_too_large. O storage consumido conta contra a franquia do plano (100 MB no Free, 1 GB no Pro, +1 GB por add-on).