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

A base de todas as chamadas é https://app.bee-zap.com. Os endpoints ficam em https://app.bee-zap.com/api/v1/... — por exemplo, https://app.bee-zap.com/api/v1/messages e https://app.bee-zap.com/api/v1/contacts.

A URL é a mesma para todos os clientes — não há subdomínio por cliente. Quem identifica o seu cliente é a API key no header Authorization: Bearer. Nos exemplos abaixo, onde aparecer HUB_URL, use https://app.bee-zap.com.

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 https://app.bee-zap.com/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 https://app.bee-zap.com/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.

POST /v1/contacts

Cadastra (ou enriquece) um contato e, por padrão, cria um lead no CRM. Idempotente por número de WhatsApp: chamar de novo com o mesmo telefone não duplica — atualiza o contato existente. Útil pra integrar um sistema externo (CRM, formulário, ERP) que empurra leads pro BeeZap.

Headers

HeaderObrigatórioDescrição
authorizationsimBearer SUA_API_KEY
content-typesimapplication/json

Body

CampoTipoDescrição
phonestring?Telefone em qualquer formato (ex: 11999998888, +55 11 99999-8888). DDI/DDD/9º dígito são normalizados. Obrigatório se não enviar whatsappJid.
whatsappJidstring?JID pronto (5511999998888@c.us). Alternativa ao phone.
namestring?Nome do contato. Se vazio, usa o telefone formatado.
emailstring?E-mail do contato.
companystring?Empresa.
documentstring?CPF/CNPJ ou outro documento.
notesstring?Observações livres.
tagsstring[]?Tags pra aplicar ao contato (criadas se não existirem). Não dispara automações de TAG_ADDED.
createLeadboolean?Cria também um card no CRM (pipeline/estágio padrão). Default true.
sourcestring?Origem registrada no card (default api).
triggerAutomationsboolean?Se true, as tags enviadas disparam as automações ativas com gatilho TAG_ADDED daquela tag — útil pra um evento externo iniciar um fluxo (ex: boas-vindas). Default false.
Disparar uma automação por evento externo
Amarre o fluxo a uma tag no painel (START → gatilho TAG_ADDED). Aí o sistema externo chama POST /v1/contacts com essa tag e triggerAutomations: true — o fluxo começa para o contato. Funciona tanto pra contato novo quanto pra um já existente (a chamada é idempotente). Já há proteção contra rodar o mesmo fluxo em duplicado pro mesmo contato.

Resposta

201 quando o contato é novo, 200 quando já existia (enriquecido).

json
{
  "contactId": "cmod1828ze00d2bl8sn3kr0w",
  "name": "Maria",
  "whatsappJid": "5511999998888@c.us",
  "phone": "5511999998888",
  "created": true,
  "lead": { "leadId": "cmod...", "stageId": "cmod...", "created": true }
}

Criar contato/lead dispara os webhooks CONTACT_CREATED e LEAD_CREATED (veja a página de Webhooks) — então um sistema externo pode reagir à criação.

Exemplo (curl)

curl
curl https://app.bee-zap.com/api/v1/contacts \
  -X POST \
  -H "authorization: Bearer bz_xxx..." \
  -H "content-type: application/json" \
  -d '{"phone":"11999998888","name":"Maria","email":"maria@ex.com","tags":["vip"]}'

POST /v1/events

Registra um evento personalizado (KPI) que aparece no dashboard automaticamente. Útil pra acompanhar compra, abandonado, ticket fechado, etc — com contagem por período e delta versus o anterior. Cada nome novo vira um card.

curl
curl https://app.bee-zap.com/api/v1/events \
  -X POST \
  -H "authorization: Bearer bz_xxx..." \
  -H "content-type: application/json" \
  -H "idempotency-key: pedido-12345" \
  -d '{
    "name": "compra",
    "value": 199.90,
    "chatId": "5511999998888@c.us",
    "metadata": { "product": "premium" }
  }'
  • name obrigatório, lowercase, regex ^[a-z][a-z0-9_-]{0,63}$.
  • occurredAt opcional (ISO-8601 com offset). Default: agora.
  • value opcional (decimal); usado pra somar "quanto" (ex: ticket).
  • chatId opcional pra correlacionar com uma conversa.
  • metadata opcional (JSON livre).
  • Header Idempotency-Key opcional → segunda chamada com a mesma key retorna 409.
  • Cap de 200 nomes distintos por tenant. Rate limit: 120 eventos/min/tenant.

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()