Lojas pela API
Para quem tem muitas lojas ou clientes parecidos, como uma plataforma de delivery: o seu sistema cria o cliente e o chatbot dele a partir de um modelo, sem passar pelo painel. Cada chatbot já nasce com a personalidade, as ações, os roteiros e a base do modelo, e com o contexto e os dados da loja.
provisioning · criar cliente pede uma chave com escopo da conta inteira; size e overage pedem também billing; a equipe do portal pede membersPacoteIntegrações (R$ 49) e Plataforma (R$ 199), por mês, por conta. Sem eles, a API responde 403 plan_not_allowed.| Rota | O que faz |
|---|---|
POST /v1/clients | Cria o cliente (a loja). O external_id torna idempotente. |
GET /v1/clients/{id} | Os dados do cliente, os chatbots dele e a conformidade. |
POST /v1/bots | Cria o chatbot da loja a partir de um modelo, com o contexto, os dados da loja e os valores próprios. |
PATCH /v1/bots/{id} | Muda os dados da loja, os valores próprios, o horário e o destino do atendimento. |
POST /v1/bots/{id}/connect-links | O link para a loja conectar o WhatsApp ou o Instagram dela. |
GET /v1/bots/{id}/channels | Os canais da Meta do chatbot e o estado de cada um. |
DELETE /v1/bots/{id}/channels/{channel} | Desconecta o canal de vez. |
POST /v1/bots/{id}/pause, /resume | Pausa e retoma a IA do chatbot em todos os canais. |
GET /v1/usage | O uso do mês por cliente e chatbot. |
POST, GET /v1/clients/{id}/members, DELETE …/members/{member} | A equipe da loja no portal (permissão members). |
O caminho de uma loja nova
- No painel, monte o modelo (menu Modelos): a personalidade, as instruções, as ações, os roteiros e a base comuns a todas as lojas. Publique. O id do modelo para a API está na aba Herança.
POST /v1/clientscom o id da loja no seu sistema (external_id).POST /v1/botscom o cliente, o modelo, ocontext(por exemplo{"loja_id": "42"}, que vai para as ações) e odisplay(o nome e o horário da loja, para a IA).- O chat do site da loja usa o
widget_keyda resposta no código do widget (data-key). Para o WhatsApp e o Instagram, peça o link de conexão e mostre no painel da loja: ela abre e conecta com a conta dela na Meta.
external_id devolve o cliente ou o chatbot que já existe, com 200, sem criar outro. Assim, o provisionamento que falhou no meio pode rodar de novo do começo.POST/v1/clients
curl -X POST "https://boavoz.com/api/v1/clients" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"name": "Pizzaria do Zé",
"external_id": "loja-42",
"site": "pizzariadoze.com.br"
}'{
"client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
"external_id": "loja-42",
"name": "Pizzaria do Zé",
"compliance_status": "active"
}curl -X POST "https://boavoz.com/api/v1/clients" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Pizzaria do Zé",
"external_id": "loja-42",
"site": "pizzariadoze.com.br"
}'{
"client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
"external_id": "loja-42",
"name": "Pizzaria do Zé",
"compliance_status": "active"
}curl -X POST "https://boavoz.com/api/v1/clients" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"name": "Clínica Sorriso",
"external_id": "loja-42-lembretes",
"utility_consent": {
"source": "contrato",
"text": "Cláusula 7 do contrato: o paciente aceita lembretes de consulta pelo WhatsApp."
}
}'{
"client_id": "cli_6c3d9f2b-8e4a-4b7c-8d9f-2a3b4c5d6e7f",
"external_id": "loja-42-lembretes",
"name": "Clínica Sorriso",
"compliance_status": "active"
}| Campo | Regra | Erro |
|---|---|---|
name | O nome do cliente, de 2 a 80 caracteres. | 400 name |
external_id | Obrigatório: o id do cliente no seu sistema, até 120 caracteres. Único na conta. | 400 external_id |
site | Opcional: o endereço do site (até 200 caracteres). | 400 site |
utility_consent | Opcional: a declaração de consentimento para lembretes, como no painel: source (cadastro, contrato, compra ou outro) e text (de 20 a 1.000 caracteres: como os contatos aceitaram). A chave fica como autora; revogar a chave não revoga a declaração. | 400 utility_consent.source ou .text |
201 com client_id e compliance_status (active, review ou blocked; o cliente novo começa ativo). O external_id que já existe na conta devolve o mesmo cliente com 200, sem mudar nada. Com chave de escopo menor que a conta inteira: 403 forbidden_scope. Até 300 clientes novos por hora com a mesma chave. Aceita Idempotency-Key.
GET/v1/clients/{id}
curl "https://boavoz.com/api/v1/clients/cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e" \
-H "Authorization: Bearer $BOAVOZ_API_KEY"{
"id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
"external_id": "loja-42",
"name": "Pizzaria do Zé",
"site": "https://pizzariadoze.com.br/",
"created_at": "2026-10-19T15:20:11.042Z",
"utility_consent": null,
"bots": [
{
"id": "bot_2e4f6a8c-1b3d-4e5f-9a7b-8c9d0e1f2a3b",
"external_id": "loja-42-site",
"name": "Duda",
"status": "draft",
"paused": false,
"template_id": "bot_9d8c7b6a-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"channels": [
"whatsapp"
]
}
],
"compliance": {
"status": "active",
"restrictions": [],
"reason_summary": "Sem restrições em vigor.",
"next_step": null
}
}bots traz os chatbots do cliente que a chave alcança, com o external_id, o status, a pausa, o modelo e os canais da Meta conectados (whatsapp, instagram; o chat do site vale sempre). compliance traz o estado e as restrições em vigor, com o motivo resumido e o próximo passo, iguais aos do webhook compliance.changed. Esta rota nunca responde feature_suspended: ela é como você fica sabendo do que está suspenso.
POST/v1/bots
curl -X POST "https://boavoz.com/api/v1/bots" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
"template_id": "bot_9d8c7b6a-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"external_id": "loja-42-site",
"context": {
"loja_id": "42"
},
"display": {
"nome": "Pizzaria do Zé, Centro",
"horario": "terça a domingo, das 18h às 23h",
"endereco": "Rua das Flores, 120"
}
}'{
"bot_id": "bot_2e4f6a8c-1b3d-4e5f-9a7b-8c9d0e1f2a3b",
"widget_key": "5f0c2a9e7b1d3c4e6a8b0d2f",
"client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
"external_id": "loja-42-site",
"template_id": "bot_9d8c7b6a-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"name": "Duda",
"status": "live",
"context": {
"loja_id": "42"
},
"display": {
"nome": "Pizzaria do Zé, Centro",
"horario": "terça a domingo, das 18h às 23h",
"endereco": "Rua das Flores, 120"
},
"size_change": null
}curl -X POST "https://boavoz.com/api/v1/bots" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
"template_id": "bot_9d8c7b6a-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"external_id": "loja-42-delivery",
"context": {
"loja_id": "42"
},
"display": {
"nome": "Pizzaria do Zé, delivery"
},
"overrides": {
"assistant_name": "Bia",
"welcome": "Oi! Sou a Bia, do delivery do Zé. Quer ver o cardápio?"
}
}'{
"bot_id": "bot_7a9b1c3d-5e7f-4a2b-8c4d-6e8f0a2b4c6d",
"widget_key": "8d3e1b0f6a2c4e5d7b9a1c3e",
"client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
"external_id": "loja-42-delivery",
"template_id": "bot_9d8c7b6a-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"name": "Bia",
"status": "live",
"context": {
"loja_id": "42"
},
"display": {
"nome": "Pizzaria do Zé, delivery"
},
"size_change": null
}| Campo | Regra | Erro |
|---|---|---|
client_id | Obrigatório: o cli_… do POST /v1/clients. Com chave de escopo de um cliente, só o cliente dela. | 400 client_id; 404 |
template_id | Obrigatório: o modelo (bot_…, na aba Herança dele). O chatbot usa a versão publicada em vigor. | 400 template_id; 404 template_id |
external_id | Opcional: o id do chatbot no seu sistema, até 120 caracteres, único no cliente. Com ele, repetir devolve o mesmo chatbot (200). | 400 external_id |
context | Opcional: o contexto fixo, até 10 pares (chaves de letras, números, _, . e -; valores texto, número ou verdadeiro/falso). Vai em toda chamada de ação e escolhe as fontes com a mesma etiqueta. A IA não vê. | 400 context |
display | Opcional: o que a IA sabe da loja além da base, como o nome da unidade, o horário e o endereço, no mesmo formato do context. Entra como dado (nunca como instrução) e não vai para as ações. | 400 display |
overrides | Opcional: valores próprios, só nos campos que o modelo libera: assistant_name (2 a 40), welcome (até 300), appearance (color #rrggbb, avatar_text, suggested_questions até 6, position left ou right, offset 0 a 200), handoff_notice (com {atendente}) e extra_instructions (até 4.000, somadas às do modelo). | 403 field_locked; 400 overrides.… |
size, overage | Opcionais, com a permissão billing também: o tamanho e o excedente, com as regras do PATCH da cobrança (subir cobra no cartão da assinatura). Sem size, o chatbot nasce sem tamanho, como no painel. | 403 forbidden_scope; 402; 422 |
A Idempotency-Key é obrigatória (sem ela, 400 invalid_request). 201 com bot_id e widget_key (a chave do código do chat do site). O chatbot nasce no ar ("status": "live") quando o modelo tem pelo menos uma fonte pronta, a mesma regra do Publicar do painel; sem fonte, nasce em rascunho (draft) e vai ao ar pelo Publicar, no painel. O mesmo external_id dá 200 quando ele já existe no cliente, sem mudar o contexto, o display nem os valores próprios (o tamanho e o excedente são conferidos de novo: repetir depois de um 402 tenta a cobrança de novo, e o 402 traz o bot_id em details). Chave com escopo de chatbots escolhidos não cria chatbot: 403 forbidden_scope. Até 300 chatbots novos por hora com a mesma chave.
context, o display e os canais são sempre do chatbot. No painel, o contexto e os dados da loja ficam na aba Ações do chatbot.PATCH/v1/bots/{id}
curl -X PATCH "https://boavoz.com/api/v1/bots/bot_2e4f6a8c-1b3d-4e5f-9a7b-8c9d0e1f2a3b" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"display": {
"nome": "Pizzaria do Zé, Centro",
"horario": "terça a domingo, das 18h às 23h"
},
"overrides": {
"welcome": "Oi! Sou a Duda, do Zé. Quer ver o cardápio de hoje?"
},
"business_hours": {
"sun": [
"18:00",
"23:00"
],
"tue": [
"18:00",
"23:00"
],
"wed": [
"18:00",
"23:00"
],
"thu": [
"18:00",
"23:00"
],
"fri": [
"18:00",
"23:30"
],
"sat": [
"18:00",
"23:30"
]
}
}'{
"bot_id": "bot_2e4f6a8c-1b3d-4e5f-9a7b-8c9d0e1f2a3b",
"name": "Duda",
"client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
"external_id": "loja-42-site",
"template_id": "bot_9d8c7b6a-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"widget_key": "5f0c2a9e7b1d3c4e6a8b0d2f",
"display": {
"nome": "Pizzaria do Zé, Centro",
"horario": "terça a domingo, das 18h às 23h"
},
"overrides": {
"welcome": "Oi! Sou a Duda, do Zé. Quer ver o cardápio de hoje?"
},
"business_hours": {
"sun": [
"18:00",
"23:00"
],
"mon": null,
"tue": [
"18:00",
"23:00"
],
"wed": [
"18:00",
"23:00"
],
"thu": [
"18:00",
"23:00"
],
"fri": [
"18:00",
"23:30"
],
"sat": [
"18:00",
"23:30"
]
},
"handoff_destination": {
"email": null,
"phone": "(11) 3333-4444",
"site": null,
"form_url": null,
"address": null
}
}| Campo | Regra | Erro |
|---|---|---|
display | Os dados da loja para a IA, como no POST; null tira. | 400 display |
overrides | Só no chatbot criado de um modelo e só nos campos que o modelo libera (os mesmos do POST); null volta ao valor do modelo. A aparência parte da que o chatbot tem agora. | 403 field_locked; 400 overrides… |
business_hours | O horário do atendimento humano, de sun a sat: ["18:00", "23:00"] ou null (fechado), no horário de Brasília. Substitui o horário inteiro; null tira. Fora dele, o assistente diz quando a equipe volta. | 400 business_hours.… |
handoff_destination | Os outros jeitos de falar com a equipe, que o assistente oferece quando a pessoa pede um atendente: email, phone, site, form_url e address. Só muda o que vier; null tira. Toda troca manda um alerta de segurança ao dono da conta. | 400 handoff_destination.… |
Permissão provisioning; a resposta é o chatbot. O tamanho e o excedente (size, overage) vão no mesmo PATCH, com a permissão billing, em outro pedido (os dois juntos: 400), como na Cobrança. O contexto fixo, o modelo, as ações, os roteiros e a publicação ficam no painel: o que muda para onde vão os dados fica com quem cuida da conta. O modelo não aceita este PATCH (ele muda no painel e chega aos derivados ao publicar).
POST/v1/bots/{id}/connect-links
curl -X POST "https://boavoz.com/api/v1/bots/bot_7c9e6679-7425-40de-944b-e07fc1f90ae7/connect-links" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"channel": "whatsapp"
}'{
"url": "https://boavoz.com/conectar/q3Jx8vN0bT5kLm2Wc7rYp1sDf4Gh6Ak9",
"expires_at": "2026-10-26T15:31:07.512Z",
"channel": "whatsapp",
"channel_connected": true,
"connected_channel": {
"id": "chn_wa_109283746512345",
"type": "whatsapp",
"display": "+55 11 99999-0000",
"status": "connected",
"connected_at": "2026-10-04T14:20:31.000Z",
"disconnected_at": null,
"reason": null,
"issue": null
}
}channel é whatsapp ou instagram. Enquanto houver um link aberto (vale 7 dias e serve para uma conexão), pedir de novo devolve o mesmo; rotate: true cria outro e o anterior deixa de valer. A página do link sai com a marca da sua conta, no domínio do BoaVoz (a Meta só abre o login nos domínios do app), e antes da conexão pede o aceite do próprio negócio. Com o canal já conectado, o link serve para conectar de novo: o número novo substitui o antigo (channel_connected e connected_channel dizem o que está conectado agora).
Como no painel, o canal pede um chatbot com tamanho (sem ele, 422 bot_without_size), e o canal precisa estar liberado na conta (senão, 403 feature_suspended). O modelo não tem canais (400).
GET/v1/bots/{id}/channels
curl "https://boavoz.com/api/v1/bots/bot_7c9e6679-7425-40de-944b-e07fc1f90ae7/channels" \
-H "Authorization: Bearer $BOAVOZ_API_KEY"{
"data": [
{
"id": "chn_wa_109283746512345",
"type": "whatsapp",
"display": "+55 11 99999-0000",
"status": "connected",
"connected_at": "2026-10-04T14:20:31.000Z",
"disconnected_at": null,
"reason": null,
"issue": null
},
{
"id": "chn_ig_17841400000000000",
"type": "instagram",
"display": "@pizzariadoze",
"status": "disconnected",
"connected_at": "2026-10-05T09:12:44.000Z",
"disconnected_at": "2026-10-18T22:40:03.000Z",
"reason": "a conta tirou o acesso do BoaVoz no Instagram",
"issue": null
}
]
}Cada canal com o id (o mesmo dos webhooks channel.*), o número ou o @ da conta, o status (connected ou disconnected, quando caiu, com o motivo em reason) e o problema em aberto em issue (hoje, a conta do WhatsApp sem forma de pagamento na Meta, código 131042). O chat do site vale sempre e não aparece aqui.
DELETE/v1/bots/{id}/channels/{channel}
curl -X DELETE "https://boavoz.com/api/v1/bots/bot_7c9e6679-7425-40de-944b-e07fc1f90ae7/channels/chn_wa_109283746512345" \
-H "Authorization: Bearer $BOAVOZ_API_KEY"(sem corpo)É o "desconectar de vez" do painel: o BoaVoz deixa de receber as mensagens daquela conta e apaga o acesso. Nada muda na Meta: o número e a conta continuam do negócio, e o número nunca é descadastrado. As conversas antigas ficam. Até 5 desconexões por hora com a mesma chave (429 rate_limited), e o dono da conta recebe um alerta de segurança em cada uma. Para parar a IA sem desconectar, use a pausa.
POST/v1/bots/{id}/pause
curl -X POST "https://boavoz.com/api/v1/bots/bot_2e4f6a8c-1b3d-4e5f-9a7b-8c9d0e1f2a3b/pause" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"reason": "loja fechada para reforma",
"notify_contacts": false
}'{
"bot_id": "bot_2e4f6a8c-1b3d-4e5f-9a7b-8c9d0e1f2a3b",
"paused": true,
"paused_at": "2026-10-19T16:02:18.774Z",
"already_paused": false
}A mesma pausa do botão de emergência do painel: a IA e os envios param em todos os canais, os canais continuam conectados e as mensagens continuam gravadas, para a equipe responder pelo painel e pelo portal. Serve para loja fechada, contrato suspenso ou inadimplência com a sua plataforma. reason (até 200 caracteres) vai no webhook bot.paused; com notify_contacts: true, o contato recebe o aviso de atendimento indisponível uma vez por conversa. Já pausado: devolve o paused_at da pausa que vale, com already_paused: true.
POST/v1/bots/{id}/resume
curl -X POST "https://boavoz.com/api/v1/bots/bot_2e4f6a8c-1b3d-4e5f-9a7b-8c9d0e1f2a3b/resume" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90"{
"bot_id": "bot_2e4f6a8c-1b3d-4e5f-9a7b-8c9d0e1f2a3b",
"paused": false,
"was_paused": true,
"restrictions": []
}Tira só a pausa do dono (feita pelo painel ou pela API) e sai o webhook bot.resumed. Medidas do BoaVoz e ordens da Meta continuam e voltam em restrictions, no mesmo formato do compliance.changed.
GET/v1/usage
curl "https://boavoz.com/api/v1/usage" \
-H "Authorization: Bearer $BOAVOZ_API_KEY"{
"month": "2026-10",
"clients": [
{
"client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
"external_id": "loja-42",
"name": "Pizzaria do Zé",
"atendimentos": 412,
"messages": 3180,
"campaign_contacts": 250,
"meta_billed": {
"marketing": 250,
"utility": 40
},
"meta_cost_estimate_brl": 88.9,
"bots": [
{
"bot_id": "bot_2e4f6a8c-1b3d-4e5f-9a7b-8c9d0e1f2a3b",
"external_id": "loja-42-site",
"name": "Duda",
"atendimentos": 412,
"messages": 3180,
"campaign_contacts": 250,
"meta_billed": {
"marketing": 250,
"utility": 40
},
"meta_cost_estimate_brl": 88.9
}
]
}
],
"account": {
"atendimentos": 412,
"messages": 3180,
"campaign_contacts": 250,
"meta_billed": {
"marketing": 250,
"utility": 40
},
"meta_cost_estimate_brl": 88.9,
"overage_atendimentos": 12,
"overage_value_brl": 4.2,
"credit_balance_brl": 87.5
}
}O uso de um mês (month, como 2026-10; sem ele, o mês atual, no calendário de São Paulo) por cliente e chatbot do escopo da chave, com os filtros client_id e bot_id: os atendimentos (a unidade da cota: cada 24 horas em que a IA respondeu um contato), as mensagens, os contatos que receberam campanha ou lembrete (não contam na cota) e as mensagens do WhatsApp cobradas pela Meta, com o custo estimado pelo preço de referência. O custo da Meta é só informativo: a Meta cobra direto do negócio. O custo de IA não aparece (é do BoaVoz).
Com chave da conta inteira e sem filtro, vem também account: os totais da conta, os atendimentos a mais (excedente) do mês, o valor deles e o saldo de crédito.
Equipe do portal
A equipe da loja atende pelo portal do cliente (as conversas dela, com a marca da sua conta). Estas rotas pedem a permissão members, que vem desmarcada ao criar a chave: o portal mostra e exporta conversas, então provisioning sozinha não convida ninguém. A chave alcança os clientes do escopo dela.
POST/v1/clients/{id}/members
curl -X POST "https://boavoz.com/api/v1/clients/cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e/members" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"email": "carla@pizzariadoze.com.br",
"role": "agent",
"display_name": "Carla"
}'{
"id": "mbr_8f7e6d5c-4b3a-4291-8e7d-6c5b4a392817",
"email": "carla@pizzariadoze.com.br",
"role": "agent",
"display_name": "Carla",
"last_login_at": null,
"created_at": "2026-10-19T16:20:41.208Z",
"invited_by": {
"type": "api_key",
"name": "Plataforma, produção",
"prefix": "bv_live_7Hq2…"
},
"invite_email": "sent"
}| Campo | Regra | Erro |
|---|---|---|
email | Obrigatório: a pessoa recebe nele o link de acesso, com a marca da sua conta. | 400 email |
role | Obrigatório: manager (gestor: tudo o que a agência liberou no portal) ou agent (atendente: só as conversas). | 400 role |
display_name | Opcional: o nome que o contato vê quando a pessoa assume a conversa (até 40 caracteres). | 400 display_name |
201 com a pessoa e invite_email (sent ou failed: o acesso fica criado mesmo se o e-mail falhar, e a pessoa pode pedir um link na entrada do portal). O mesmo e-mail no cliente devolve a pessoa que já existe, com 200, sem mudar o papel. Até 20 pessoas por cliente (422 plan_limit_reached).
GET/v1/clients/{id}/members
curl "https://boavoz.com/api/v1/clients/cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e/members" \
-H "Authorization: Bearer $BOAVOZ_API_KEY"{
"data": [
{
"id": "mbr_1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"email": "dono@pizzariadoze.com.br",
"role": "manager",
"display_name": null,
"last_login_at": "2026-10-18T20:11:09.000Z",
"created_at": "2026-10-05T10:00:00.000Z",
"invited_by": null
},
{
"id": "mbr_8f7e6d5c-4b3a-4291-8e7d-6c5b4a392817",
"email": "carla@pizzariadoze.com.br",
"role": "agent",
"display_name": "Carla",
"last_login_at": null,
"created_at": "2026-10-19T16:20:41.208Z",
"invited_by": {
"type": "api_key",
"name": "Plataforma, produção",
"prefix": "bv_live_7Hq2…"
}
}
]
}invited_by é a chave que convidou (o nome e o começo dela), ou null para quem foi convidado pelo painel.
DELETE/v1/clients/{id}/members/{member}
curl -X DELETE "https://boavoz.com/api/v1/clients/cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e/members/mbr_8f7e6d5c-4b3a-4291-8e7d-6c5b4a392817" \
-H "Authorization: Bearer $BOAVOZ_API_KEY"(sem corpo)Tira o acesso na hora: a sessão aberta perde o acesso na próxima página. Responde 204; a pessoa que não é do cliente, 404.