Pular para o conteúdo principal

bZapper Connect

O bZapper Connect é para softwares parceiros: CRMs, ERPs, plataformas de atendimento e sistemas verticais que querem oferecer WhatsApp aos próprios clientes.

Seu cliente clica em "Ativar WhatsApp" dentro do seu sistema. Abre o componente do bZapper, que já vem com os dados dele. Ali mesmo ele:

  1. cria a conta no bZapper (sem senha, sem captcha, sem confirmar e-mail — ele já está logado no seu sistema);
  2. assina o bZapper Pro (cartão ou Pix);
  3. conecta o número (QR code ou código de pareamento).

No fim, o seu backend recebe uma API key da conta do cliente e passa a enviar e receber mensagens por ela. O cliente nunca sai da sua tela.

Quem é cliente de quem

O seu cliente vira cliente direto do bZapper: a assinatura, as faturas e os dados são dele. Você recebe uma credencial autorizada por ele, que ele pode desconectar quando quiser em Apps conectados. Você nunca vê cartão nem senha.

Visão geral do fluxo​

 Seu backend                Seu front (navegador)             bZapper
│ │ │
│ 1. POST /partner/connect-sessions (bz_partner_…) ─────────▶│
│◀──────────────── session_token (cs_…, 30 min) ─────────────│
│── session_token ───────────▶│ │
│ │ 2. BzapperConnect.open(...) ─▶│ conta → Pro → número
│ │◀── onComplete({ code }) ──────│
│◀────────── code ────────────│ │
│ 3. POST /partner/connect/exchange { code } ───────────────▶│
│◀──────────────── api_key (bz_live_…) + conexão ────────────│
│ 4. usa a api_key normalmente (enviar, receber, webhooks) │
│◀═══════════ webhooks connect.* + message.* ════════════════│
CredencialOnde vivePara quê
bz_partner_… (secret do parceiro)só no seu backendabrir sessões, trocar o code, gerir conexões
cs_… (ingresso da sessão)navegador, por 30 minabrir o componente
cc_… (code de conclusão)navegador → seu backend, 10 min, uso únicotrocar pela API key
bz_live_… (API key do cliente)só no seu backendoperar o WhatsApp do cliente

0. Cadastro do parceiro​

O cadastro de parceiros é feito pela equipe do bZapper. Você informa:

  • nome e logo (aparecem para o cliente na tela de autorização). A logo é enviada como arquivo pela equipe do bZapper — PNG, JPEG, WebP ou SVG, até 2 MB — e passa a ser servida pela CDN do bZapper, para não quebrar quando você mexer no seu site;
  • origens permitidas: os domínios onde o componente vai rodar (ex.: https://app.seusistema.com.br). Fora delas, a API recusa com 403 origin_not_allowed;
  • URL do webhook que recebe os eventos de todas as suas conexões.

Você recebe o secret do parceiro (bz_partner_…) e o secret do webhook. Os dois aparecem uma única vez.

1. Abra a sessão (no seu backend)​

Quando o cliente clicar em "Ativar WhatsApp", o seu backend chama:

curl -X POST https://api.bzapper.com.br/partner/connect-sessions \
-H "Authorization: Bearer $BZAPPER_PARTNER_SECRET" \
-H "Content-Type: application/json" \
-d '{
"external_id": "cliente-4821",
"customer": {
"name": "Ana Souza",
"email": "[email protected]",
"company": "Boxy Pharma",
"phone": "+5511988887777",
"country": "BR",
"locale": "pt-BR"
}
}'
{
"session_token": "cs_8a82868d9a91…",
"expires_at": "2026-09-17T17:20:00Z",
"connection": { "id": "7ece7f98-…", "external_id": "cliente-4821", "status": "pending_account" }
}
  • external_id é o id do cliente no seu sistema. O mesmo external_id sempre reaproveita a mesma conexão. Chamar de novo depois de concluído abre o componente no modo gerenciar.
  • customer.company vira o nome da conta e do projeto no bZapper ("Boxy Pharma"). Sem empresa, usamos o nome da pessoa.
  • customer.phone já vem preenchido no passo do WhatsApp.
  • customer.country define a moeda (BR → BRL; Américas → USD; demais → EUR). Pix só aparece em BRL.
O secret nunca vai para o navegador

Só o session_token vai para o front. Ele dura 30 minutos e só abre o componente a partir das suas origens cadastradas.

E se o cliente já tiver conta no bZapper?​

O componente sempre pergunta "Você já tem conta no bZapper?" — Criar conta nova ou Já tenho conta. Se o e-mail que você mandou já tem conta, a tela abre direto em Já tenho conta, com "Encontramos sua conta". O cliente também pode vincular por outro e-mail (o da conta bZapper dele, se for diferente do que está no seu sistema).

Para vincular, a pessoa passa por um passo a mais: digita um código de 6 dígitos que enviamos para o e-mail da conta, e esse e-mail precisa ser administrador dela. Sem isso, qualquer sistema que soubesse o e-mail de alguém conseguiria acesso à conta dessa pessoa. Depois do código, o fluxo segue igual (se a conta já for Pro, o pagamento é pulado).

2. Abra o componente (no seu front)​

Carregue o script uma vez:

<script src="https://widget.bzapper.com.br/v1/connect.js"></script>

Modo modal (recomendado)​

async function ativarWhatsApp() {
const { session_token } = await fetch('/api/bzapper/sessao', { method: 'POST' }).then((r) => r.json());

BzapperConnect.open({
session: session_token,
onComplete: async ({ code }) => {
await fetch('/api/bzapper/concluir', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code }),
});
},
onClose: () => console.log('fechou'),
onError: ({ code }) => console.warn('bZapper Connect:', code),
});
}

BzapperConnect.open() devolve { close() } caso você queira fechar por código.

Modo inline​

<bzapper-connect data-session="cs_8a82868d9a91…"></bzapper-connect>

<script>
document.querySelector('bzapper-connect')
.addEventListener('bzapper:complete', (e) => enviarParaOBackend(e.detail.code));
</script>

Opções e eventos​

Opção (open)Atributo (inline)Descrição
sessiondata-sessionObrigatório. O session_token da etapa 1.
localedata-localeIdioma (pt, en, es, it, de, fr). Padrão: <html lang> ou o do navegador.
apiBasedata-apiBase da API. Padrão: https://api.bzapper.com.br.
CallbackEvento DOMdetail
onReadybzapper:ready{ step, connectionId, status }
onStepbzapper:step{ step }: account, verify_email, payment, number, manage, revoked
onCompletebzapper:complete{ code, connectionId, externalId }
onClosebzapper:close— (só no modal)
onErrorbzapper:error{ code, message } (ex.: connect_session_expired)

O componente usa Shadow DOM, então o CSS do seu site não interfere nele (nem o dele no seu). O formulário de cartão é do próprio Stripe e o número do cartão nunca passa pelo seu código nem pelo nosso.

CSP

Se o seu site usa Content-Security-Policy, libere: script-src https://widget.bzapper.com.br https://js.stripe.com; connect-src https://api.bzapper.com.br; frame-src https://js.stripe.com https://hooks.stripe.com;

3. Troque o code pela API key (no seu backend)​

curl -X POST https://api.bzapper.com.br/partner/connect/exchange \
-H "Authorization: Bearer $BZAPPER_PARTNER_SECRET" \
-H "Content-Type: application/json" \
-d '{ "code": "cc_4291a95ab388…" }'
{
"id": "7ece7f98-…",
"external_id": "cliente-4821",
"status": "active",
"account_id": "08eaa5be-…",
"project_id": "88a27b8c-…",
"api_key": "bz_live_45cd5a…",
"numbers": [{ "id": "209bd3cd-…", "phone": "+5511988887777", "status": "connected" }]
}

Guarde a api_key junto do seu cliente (external_id). Ela não é mostrada de novo. O code vale uma vez e por 10 minutos.

Perdeu a key ou o cliente fechou a aba antes da troca?

Você recebe o webhook connect.completed de qualquer jeito. Chame POST /partner/connections/{id}/rotate-key para gerar uma nova (a anterior para de valer na hora).

4. Use a API key​

É uma API key normal do bZapper, presa ao projeto da conexão. Serve para tudo que opera o WhatsApp dele: mensagens, números, grupos, conversas, presença, etiquetas, chamadas, pools e campanhas — além de POST /contacts/check (saber se um número tem WhatsApp).

Três limites existem de propósito:

  • Projeto, não conta. Números de outros projetos do mesmo cliente não existem para essa key (404), mesmo sendo do mesmo titular.
  • Nada de conta e dinheiro. Plano e cobrança, usuários, outras API keys, webhooks da conta, projetos e exclusão de conta respondem 403 forbidden.
  • Sem GET /stream e sem a agenda da conta. O SSE é filtrado por conta e carrega o QR e o código de pareamento; a base de contatos (/contacts, /tags, /contact-groups, /suppressions, /blocklist) também é da conta inteira. Você recebe os eventos pelo seu webhook, que já vem filtrado por conexão.

Ciclo de vida da conexão​

statusO que significaA key
pending_accountSessão aberta, conta ainda não criada—
pending_paymentConta criada, Pro não pago—
pending_numberPro pago, WhatsApp não conectado—
activeConcluídafunciona
suspendedO Pro do cliente não foi pagoresponde 402 connect_suspended
revokedEncerrada (pelo cliente, por você ou exclusão da conta)responde 401 connect_revoked

A conexão só existe paga. O canal de parceiros não tem plano Free. Se a renovação do Pro falhar, a conexão fica suspended e volta sozinha para active assim que o cliente paga. Para ele pagar, basta você abrir o componente de novo (mesmo external_id): ele cai direto na tela de pagamento, com o aviso.

Revogação é definitiva

Quando o cliente desconecta você em Apps conectados, a conexão vai para revoked e solta a conta: a key morre e qualquer operação na sessão aberta passa a responder 409 connection_revoked. Abrir o componente de novo com o mesmo external_id recomeça do passo da conta — com o código no e-mail do cliente. Você não reconecta sozinho; quem desconectou precisa autorizar outra vez.

Tratando a suspensão no seu código​

const res = await fetch('https://api.bzapper.com.br/messages/text', {
method: 'POST',
headers: { Authorization: `Bearer ${cliente.bzapperKey}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ to: '+5511999990000', body: 'Seu pedido saiu para entrega' }),
});
if (res.status === 402) {
const { code } = await res.json();
if (code === 'connect_suspended') mostrarBannerRegularizarWhatsApp(); // reabre o Connect
}

Webhooks do parceiro​

Todos os eventos das suas conexões chegam na URL de webhook do parceiro, com a mesma assinatura dos webhooks do bZapper (X-Bzapper-Signature: sha256=<hex>, HMAC-SHA256 do corpo cru com o secret do webhook do parceiro). O envelope é o de sempre, com um bloco connection a mais para você saber de qual cliente é:

{
"event_id": "evt_3f…",
"event_type": "message.received",
"timestamp": "2026-09-17T16:55:02Z",
"instance_id": "209bd3cd-…",
"payload": { "type": "text", "from": "+5511999990000", "body": "Olá!" },
"connection": {
"id": "7ece7f98-…",
"external_id": "cliente-4821",
"account_id": "08eaa5be-…",
"project_id": "88a27b8c-…",
"status": "active"
}
}

Ciclo de vida:

EventoQuando
connect.completedO cliente concluiu (Pro pago + WhatsApp conectado)
connect.suspendedO Pro do cliente deixou de estar pago
connect.resumedO cliente pagou e a conexão voltou
connect.revokedA conexão foi encerrada. payload.revoked_by: customer, partner ou account_deleted

Operação (só das conexões active): os mesmos eventos de projeto do bZapper, como message.*, instance.* e contact.opted_out. QR code e código de pareamento não são repassados: são o segredo do aparelho do cliente.

Não é preciso cadastrar webhook na conta do cliente. Tentativas: até 5, com backoff exponencial. Para reconciliar, use GET /partner/connections.

Gestão das conexões (backend)​

MétodoRotaPara quê
GET/partner/meQuem é você (confere o secret)
GET/partner/connections?external_id=&status=Lista conexões
GET/partner/connections/{id}Status, conta, projeto e números
POST/partner/connections/{id}/rotate-keyNova API key (a anterior morre)
DELETE/partner/connections/{id}Encerra a conexão (não cancela o plano do cliente)

Do lado do cliente: Apps conectados​

No painel do bZapper, em Apps conectados, o cliente vê os softwares ligados à conta dele e pode desconectar qualquer um. A key do parceiro para na hora e você recebe connect.revoked. O plano e os números continuam com ele.

A conta criada pelo Connect nasce sem senha. Se o cliente quiser entrar no painel por fora (faturas, cartões), ele usa o link de boas-vindas que chega por e-mail ou "Esqueci minha senha" na tela de login.

Referência completa

Cada endpoint, campo, estado e código de erro está em Referência — bZapper Connect.

SDKs​

Os 5 SDKs oficiais têm o cliente de parceiro. Veja SDKs.

import os
from bzapper import PartnerClient

partner = PartnerClient(os.environ["BZAPPER_PARTNER_SECRET"])
sessao = partner.create_connect_session(
external_id="cliente-4821",
customer={"name": "Ana Souza", "email": "[email protected]", "company": "Boxy Pharma", "country": "BR"},
)
# devolva sessao["session_token"] ao front; depois do onComplete:
conexao = partner.exchange_code(code)
salvar_key(cliente_id="cliente-4821", api_key=conexao["api_key"])
SDKCliente de parceiro
Nodenew BzapperPartner({ partnerSecret })
PythonPartnerClient(partner_secret)
Gobzapper.NewPartnerClient(secret)
PHPnew Bzapper\PartnerClient($secret)
JavaBzapperPartner

Erros​

CódigoHTTPOndeO que fazer
partner_unauthorized401/partner/*Secret ausente, errado ou rotacionado
partner_inactive403todosIntegração desativada pelo bZapper
external_id_required / customer_email_required / customer_name_required400criar sessãoComplete os dados
origin_not_allowed403componenteO domínio da página não está nas origens cadastradas
connect_session_expired401componenteAbra uma sessão nova
invalid_code400trocaCode errado, vencido (10 min) ou já usado → use rotate-key
connection_revoked409componenteO cliente desconectou você: abra uma sessão nova (recomeça no passo da conta)
payment_pending409pagamentoA tentativa anterior está sendo confirmada (Pix/3DS). Espere alguns segundos
account_admin_required403conta existenteO e-mail tem conta no bZapper, mas não é administrador dela
code_attempts_exceeded429conta existenteTentativas erradas demais para aquele e-mail na última hora
code_sends_exceeded429conta existenteCódigos enviados demais para aquele e-mail na última hora
account_not_found404conta existente"Já tenho conta" com um e-mail que não tem conta no bZapper
connection_not_active409rotate-keyConexão não concluída ou encerrada
connect_suspended402API keyPro do cliente não pago → reabra o Connect
connect_revoked401API keyConexão encerrada → reabra o Connect para reconectar