Conta, projetos e usuários
O bZapper organiza tudo em três níveis:
Conta (empresa)
├── Usuários (admin / membro) ← faturamento e equipe vivem na conta
├── Contatos (compartilhados) ← visíveis em todos os projetos, filtráveis
└── Projetos
├── Projeto A
│ ├── Números (instâncias) + rotação
│ ├── Inbox (conversas/mensagens)
│ ├── API keys
│ ├── Estatísticas
│ └── Identidade dos números (perfil/"Sobre")
└── Projeto B … (isolado de A)
O que é um projeto?
Um projeto é um ambiente isolado dentro da sua conta. Diferente de outras ferramentas onde "instância = um número", aqui um projeto agrupa vários números que se revezam entre si (redundância). Cada projeto isola:
- Números (instâncias) e a rotação entre eles;
- Inbox — conversas e mensagens;
- API keys;
- Estatísticas (consumo);
- Identidade dos números (perfil/"Sobre").
Use projetos para separar clientes, marcas, ambientes (produção/teste) ou equipes — sem misturar números, conversas nem cobrança.
API keys são por projeto
Cada API key pertence a exatamente um projeto. A chave já carrega o contexto: toda chamada autenticada por ela opera somente nos números, inbox e estatísticas daquele projeto. Não é preciso enviar mais nada.
# Esta key é do "Projeto A" → só vê os números/inbox do Projeto A.
curl https://api.bzapper.com.br/instances -H "Authorization: Bearer bz_live_doProjetoA..."
Para operar em outro projeto, gere uma key naquele projeto (no painel, troque o projeto no seletor do topo e crie a key em Keys).
X-Project-IdA key já carrega o projeto dela. O header X-Project-Id serve só para a sessão do
painel (JWT), onde o projeto ativo vem do seletor — numa chamada autenticada por API key
ele é simplesmente ignorado. Para recortar dados por projeto use o parâmetro
?project_id= dos endpoints que o aceitam.
No painel, o projeto ativo é escolhido no seletor do cabeçalho e enviado em
cada requisição no header X-Project-Id. As telas (Números, Inbox, Keys,
Estatísticas) refletem o projeto ativo. Trocar o projeto troca todo o contexto.
Rotação de API key
A chave crua (bz_live_...) aparece uma única vez. Se ela vazou, se um dev saiu do
time ou se você simplesmente quer trocar de chave por higiene, não apague e crie
outra: rotacione. POST /keys/{id}/rotate cria uma chave nova que herda
papel, escopos, projeto e nome da antiga e mantém a antiga funcionando por um
período de carência — a sua integração não cai no meio do deploy.
curl -X POST https://api.bzapper.com.br/keys/$KEY_ID/rotate \
-H "Authorization: Bearer $BZ_KEY" \
-H "Content-Type: application/json" \
-d '{ "revoke_in_seconds": 86400 }'
Resposta 200:
{
"api_key": "bz_live_novaChaveCrua...",
"key": { "id": "9b1c…", "name": "produção", "role": "admin", "project_id": "4d2e…" },
"previous_key": { "id": "3f2a…", "expires_at": "2026-07-02T12:00:00Z", "rotated_to": "9b1c…" },
"old_key_expires_at": "2026-07-02T12:00:00Z"
}
api_key é mostrado uma única vezO campo api_key da resposta é a chave crua nova — ela não é recuperável depois.
Guarde no seu cofre de segredos antes de fechar a requisição.
A carência (revoke_in_seconds)
revoke_in_seconds é por quanto tempo a chave antiga continua valendo:
| Valor | Efeito |
|---|---|
| omitido | 86400 (24 horas) — o padrão |
0 | revoga a antiga na hora (só faça isso se você troca a chave em todos os lugares ao mesmo tempo) |
até 2592000 | máximo de 30 dias |
Passado o prazo, a chave antiga responde 401 key_expired — um código distinto de
key_revoked, para você saber no log que foi uma rotação que venceu, não uma revogação.
O procedimento seguro (sem downtime)
- Rotacione com uma carência que caiba na sua janela de deploy (24 h é folgado).
Guarde o
api_keynovo no cofre. - Suba a chave nova onde a integração roda (variáveis de ambiente, secret manager) e faça o deploy. As duas chaves valem ao mesmo tempo — nenhuma requisição falha.
- Confira que ninguém mais usa a antiga:
GET /keysmostra olast_used_atde cada chave. Se ele parou de andar, a migração terminou. - Deixe a antiga vencer sozinha no fim da carência — ou apresse com
DELETE /keys/{id}se já confirmou o passo 3.
Não inverta a ordem: rotacionar depois do deploy derruba a integração entre os dois momentos.
No painel, a tela Keys tem o botão Rotacionar com a carência em três opções (1 dia, 1 semana ou agora) — a chave nova é revelada uma única vez, com o aviso de quando a antiga para de valer.
GET /keys durante a rotação
A listagem ganha dois campos que contam a história de cada chave:
| Campo | O que diz |
|---|---|
expires_at | quando a chave rotacionada para de funcionar. null quando ela nunca foi rotacionada |
rotated_to | o id da chave que a substituiu — o rastro de quem veio depois |
Quem pode, e o que dá erro
Rotação é só de admin (uma key agent ou um usuário membro recebe
403 admin_required). Chave inexistente é 404; chave que já foi revogada ou que
já venceu responde 409 com key_already_revoked / key_already_expired — não há
nada para rotacionar.
Uma chave emitida a um software parceiro pelo bZapper Connect não rotaciona aqui: use
POST /partner/connections/{id}/rotate-key. Veja a
referência do Connect.
Nas SDKs oficiais
// Node / TypeScript
const { api_key, old_key_expires_at } = await bz.rotateKey(keyId, { revoke_in_seconds: 3600 });
# Python
rotated = bz.rotate_key(key_id, revoke_in_seconds=3600)
print(rotated["api_key"]) # guarde agora; não é mostrado de novo
// PHP
$rotated = $bz->rotateKey($keyId, 3600);
// Go
grace := 3600
rot, err := bz.RotateKey(ctx, keyID, bzapper.RotateKeyParams{RevokeInSeconds: &grace})
// Java
ApiKeyRotated rotated = bz.rotateKey(keyId, 3600);
// .NET (C#)
var rotated = await bz.RotateMyKeyAsync(keyId, new RotateApiKey { RevokeInSeconds = 3600 });
# Ruby
rotated = bz.accounts.rotate_my_key(key_id, revoke_in_seconds: 3600)
Contatos são da conta (compartilhados)
A base de contatos é da conta — o mesmo cliente é reconhecido em qualquer projeto. Você pode filtrar os contatos por projeto:
GET /contacts # todos os contatos da conta
GET /contacts?project_id=<id> # só quem teve conversa naquele projeto
GET /contacts?project_id=current # só do projeto da sua key/sessão
Usuários e papéis
Usuários pertencem à conta e enxergam todos os projetos. Há dois papéis:
| Papel | Pode |
|---|---|
| Administrador | tudo: faturamento, consumo da conta, gerenciar usuários e projetos |
| Membro | tudo, exceto faturamento e a página da conta |
Um admin convida usuários em Conta → Equipe (por e-mail; o convidado recebe um link para definir a senha). A conta sempre mantém ao menos um administrador.
Faturamento da conta (plano Pro)
O faturamento é da conta (não do projeto): a conta tem um plano (Free ou Pro) e uma moeda, e os recursos de todos os projetos contam contra os limites da conta. O Free é grátis para sempre; o Pro é uma assinatura mensal recorrente (mensagens ilimitadas + um pacote de recursos), com add-ons para ampliar. Detalhes em Cobrança.
A página Cobrança (admin) mostra o plano, as faturas, os cartões (com cartão principal + recorrência) e o consumo agregado por projeto (números, enviadas, recebidas, total).
GET /me/entitlements # limites efetivos da conta (plano, add-ons, franquias, consumo)
GET /me/subscription # estado do plano (status, vencimento, recorrência, moeda)
GET /me/invoices # histórico de faturas da conta
GET /account/usage # admin: { account: {…}, projects: [{ name, numbers, total, … }] }
Resumo
- Conta = empresa (usuários, faturamento/plano, contatos).
- Projeto = ambiente isolado (números, inbox, keys, stats, identidade).
- API key = sempre de um projeto; troque com rotação (
POST /keys/{id}/rotate), nunca apagando e recriando. - Contatos = compartilhados, filtráveis por projeto.
- Plano = Free ou Pro (recorrente + add-ons); faturamento vive na conta.
- Membros veem tudo menos faturamento.