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:
- cria a conta no bZapper (sem senha, sem captcha, sem confirmar e-mail — ele já está logado no seu sistema);
- assina o bZapper Pro (cartão ou Pix);
- 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.
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.* ════════════════│
| Credencial | Onde vive | Para quê |
|---|---|---|
bz_partner_… (secret do parceiro) | só no seu backend | abrir sessões, trocar o code, gerir conexões |
cs_… (ingresso da sessão) | navegador, por 30 min | abrir o componente |
cc_… (code de conclusão) | navegador → seu backend, 10 min, uso único | trocar pela API key |
bz_live_… (API key do cliente) | só no seu backend | operar 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 com403 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 mesmoexternal_idsempre reaproveita a mesma conexão. Chamar de novo depois de concluído abre o componente no modo gerenciar.customer.companyvira o nome da conta e do projeto no bZapper ("Boxy Pharma"). Sem empresa, usamos o nome da pessoa.customer.phonejá vem preenchido no passo do WhatsApp.customer.countrydefine a moeda (BR → BRL; Américas → USD; demais → EUR). Pix só aparece em BRL.
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 |
|---|---|---|
session | data-session | Obrigatório. O session_token da etapa 1. |
locale | data-locale | Idioma (pt, en, es, it, de, fr). Padrão: <html lang> ou o do navegador. |
apiBase | data-api | Base da API. Padrão: https://api.bzapper.com.br. |
| Callback | Evento DOM | detail |
|---|---|---|
onReady | bzapper:ready | { step, connectionId, status } |
onStep | bzapper:step | { step }: account, verify_email, payment, number, manage, revoked |
onComplete | bzapper:complete | { code, connectionId, externalId } |
onClose | bzapper:close | — (só no modal) |
onError | bzapper: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.
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.
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 /streame 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
status | O que significa | A key |
|---|---|---|
pending_account | Sessão aberta, conta ainda não criada | — |
pending_payment | Conta criada, Pro não pago | — |
pending_number | Pro pago, WhatsApp não conectado | — |
active | Concluída | funciona |
suspended | O Pro do cliente não foi pago | responde 402 connect_suspended |
revoked | Encerrada (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.
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:
| Evento | Quando |
|---|---|
connect.completed | O cliente concluiu (Pro pago + WhatsApp conectado) |
connect.suspended | O Pro do cliente deixou de estar pago |
connect.resumed | O cliente pagou e a conexão voltou |
connect.revoked | A 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étodo | Rota | Para quê |
|---|---|---|
GET | /partner/me | Quem é 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-key | Nova 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.
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"])
| SDK | Cliente de parceiro |
|---|---|
| Node | new BzapperPartner({ partnerSecret }) |
| Python | PartnerClient(partner_secret) |
| Go | bzapper.NewPartnerClient(secret) |
| PHP | new Bzapper\PartnerClient($secret) |
| Java | BzapperPartner |
Erros
| Código | HTTP | Onde | O que fazer |
|---|---|---|---|
partner_unauthorized | 401 | /partner/* | Secret ausente, errado ou rotacionado |
partner_inactive | 403 | todos | Integração desativada pelo bZapper |
external_id_required / customer_email_required / customer_name_required | 400 | criar sessão | Complete os dados |
origin_not_allowed | 403 | componente | O domínio da página não está nas origens cadastradas |
connect_session_expired | 401 | componente | Abra uma sessão nova |
invalid_code | 400 | troca | Code errado, vencido (10 min) ou já usado → use rotate-key |
connection_revoked | 409 | componente | O cliente desconectou você: abra uma sessão nova (recomeça no passo da conta) |
payment_pending | 409 | pagamento | A tentativa anterior está sendo confirmada (Pix/3DS). Espere alguns segundos |
account_admin_required | 403 | conta existente | O e-mail tem conta no bZapper, mas não é administrador dela |
code_attempts_exceeded | 429 | conta existente | Tentativas erradas demais para aquele e-mail na última hora |
code_sends_exceeded | 429 | conta existente | Códigos enviados demais para aquele e-mail na última hora |
account_not_found | 404 | conta existente | "Já tenho conta" com um e-mail que não tem conta no bZapper |
connection_not_active | 409 | rotate-key | Conexão não concluída ou encerrada |
connect_suspended | 402 | API key | Pro do cliente não pago → reabra o Connect |
connect_revoked | 401 | API key | Conexão encerrada → reabra o Connect para reconectar |