BeeZapdocs
EntrarPainel →

API REST

A API do BeeZap segue REST simples sobre HTTPS. Toda chamada é autenticada via Authorization: Bearer com a chave do cliente.

Base URL

Todos os endpoints ficam em <URL_DO_HUB>/api/v1/.... Exemplo de produção: https://hub.exemplo.com.br/api/v1/messages.

Autenticação

Inclua o header Authorization: Bearer SUA_API_KEY. A chave começa com bz_ (chaves antigas começam com zh_ — ambas continuam válidas).

curl
curl <URL_DO_HUB>/api/v1/messages/123 \
  -H "Authorization: Bearer bz_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Respostas de erro de autenticação:

StatusMotivo
401Header ausente, vazio ou chave inválida
403Cliente inativo

POST /v1/messages

Dispara uma mensagem WhatsApp pelo hub.

Headers

HeaderObrigatórioDescrição
authorizationsimBearer SUA_API_KEY
content-typesimapplication/json
idempotency-keyopcionalIdentificador único do request. Se enviar a mesma key duas vezes, a 2ª chamada não duplica — devolve a mensagem original.

Body

CampoTipoDescrição
chatIdstringJID do destinatário no WhatsApp. Ex: 5511999999999@c.us pra contatos, 1234567890@g.us pra grupos.
textstring?Texto da mensagem (até 4096 chars). Obrigatório se não enviar mediaUrl.
mediaUrlstring?URL pública de uma imagem/vídeo/áudio/documento.
mediaTypeenum?IMAGE | VIDEO | AUDIO | DOCUMENT. Obrigatório se mediaUrl for usado.
captionstring?Legenda da mídia (até 1024 chars).
sessionIdstring?Força o envio por uma sessão específica (bypassa o router). Use só se souber o que tá fazendo — geralmente o router escolhe melhor.
sessionNamestring?Idem, mas por nome humano da sessão.
poolStrategyenum?STICKY | LEAST_USED | ROUND_ROBIN. Sobrescreve a estratégia padrão do cliente pra esta chamada.

Resposta de sucesso

json
{
  "messageId": "cmod1828ze00d2bl8sn3kr0w",
  "externalMessageId": "true_5511999999999@c.us_3EB0...",
  "wahaMessageId": "true_5511999999999@c.us_3EB0...",
  "status": "SENT",
  "session": {
    "id": "ckxx...",
    "name": "Zoom Principal",
    "engine": "WAHA",
    "routedReason": "sticky"
  }
}

wahaMessageId é um alias depreciado e idêntico a externalMessageId. Use o novo nome em código novo.

Use messageId pra consultar status depois (acks de entrega/leitura chegam pelo webhook ou via GET).

Erros possíveis

StatusErroQuando
400validaçãoBody inválido (campo faltando, tipo errado).
404Session not foundVocê passou sessionId/sessionName que não pertence ao cliente.
409Idempotency key conflictMesma idempotency-key foi usada em outro cliente.
409Session not connectedA sessão escolhida não tá CONNECTED.
429Rate limit exceededCota do cliente (msgs/min) estourada. Header retry-after indica espera.
503No session availableNenhuma sessão CONNECTED disponível (todas em cooldown ou daily cap atingido). Body detalha: no_sessions, all_in_cooldown ou all_at_cap.
502Engine upstreamFalha conversando com a engine WhatsApp. O hub registra como FAILED e marca a sessão se passar do limite de erros consecutivos.
Idempotência
Sempre que enviar mensagem disparada por evento (ex: lead chegou no CRM), gere uma idempotency-key determinística (ex: new-lead-{leadId}). Se o seu sistema retentar por timeout, o BeeZap não duplica.

GET /v1/messages/:id

Consulta status atual de uma mensagem.

curl
curl <URL_DO_HUB>/api/v1/messages/cmod1828ze00d2bl8sn3kr0w \
  -H "Authorization: Bearer bz_xxx..."
json
{
  "id": "cmod1828ze00d2bl8sn3kr0w",
  "chatId": "5511999999999@c.us",
  "direction": "OUTBOUND",
  "status": "READ",
  "externalMessageId": "true_5511...",
  "wahaMessageId": "true_5511...",
  "failReason": null,
  "sentAt": "2026-04-27T13:42:01.123Z",
  "deliveredAt": "2026-04-27T13:42:03.001Z",
  "readAt": "2026-04-27T13:42:30.220Z",
  "createdAt": "2026-04-27T13:42:00.998Z"
}

Em geral, prefira receber acks via webhook em vez de polling.

Rate limits

  • Por cliente: definido pelo admin do hub (default 60 msgs/min). Excede → 429 com retry-after: 60.
  • Por sessão WhatsApp: cota diária (default 100/dia, ramp do warmup). Estouro retorna 503.

Exemplos

Node.js

js
async function sendWhatsApp(phone, text) {
  const res = await fetch(`${process.env.HUB_URL}/api/v1/messages`, {
    method: "POST",
    headers: {
      "content-type": "application/json",
      authorization: `Bearer ${process.env.HUB_API_KEY}`,
      "idempotency-key": `lead-${phone}-${Date.now()}`,
    },
    body: JSON.stringify({
      chatId: `${phone.replace(/\D/g, "")}@c.us`,
      text,
    }),
  });
  if (!res.ok) throw new Error(`hub ${res.status}: ${await res.text()}`);
  return res.json();
}

PHP

php
<?php
function sendWhatsApp(string $phone, string $text): array {
    $payload = [
        'chatId' => preg_replace('/\D/', '', $phone) . '@c.us',
        'text'   => $text,
    ];
    $ch = curl_init(getenv('HUB_URL') . '/api/v1/messages');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            'content-type: application/json',
            'authorization: Bearer ' . getenv('HUB_API_KEY'),
            'idempotency-key: lead-' . $phone . '-' . time(),
        ],
        CURLOPT_POSTFIELDS => json_encode($payload),
        CURLOPT_RETURNTRANSFER => true,
    ]);
    $body = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    if ($code >= 400) throw new RuntimeException("hub $code: $body");
    return json_decode($body, true);
}

Python

python
import os, requests, time

def send_whatsapp(phone: str, text: str) -> dict:
    digits = "".join(c for c in phone if c.isdigit())
    res = requests.post(
        f"{os.environ['HUB_URL']}/api/v1/messages",
        headers={
            "authorization": f"Bearer {os.environ['HUB_API_KEY']}",
            "content-type": "application/json",
            "idempotency-key": f"lead-{phone}-{int(time.time())}",
        },
        json={"chatId": f"{digits}@c.us", "text": text},
        timeout=15,
    )
    res.raise_for_status()
    return res.json()