BoaVoz
Documentação · API

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.

Permissão da chaveprovisioning · 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.
RotaO que faz
POST /v1/clientsCria 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/botsCria 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-linksO link para a loja conectar o WhatsApp ou o Instagram dela.
GET /v1/bots/{id}/channelsOs 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, /resumePausa e retoma a IA do chatbot em todos os canais.
GET /v1/usageO 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

  1. 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.
  2. POST /v1/clients com o id da loja no seu sistema (external_id).
  3. POST /v1/bots com o cliente, o modelo, o context (por exemplo {"loja_id": "42"}, que vai para as ações) e o display (o nome e o horário da loja, para a IA).
  4. O chat do site da loja usa o widget_key da 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.
Repetir é seguro: o mesmo 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

Criar o cliente (a loja)
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"
}'
Resposta · 201
{
  "client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
  "external_id": "loja-42",
  "name": "Pizzaria do Zé",
  "compliance_status": "active"
}
O mesmo external_id devolve o mesmo cliente
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"
}'
Resposta · 200
{
  "client_id": "cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e",
  "external_id": "loja-42",
  "name": "Pizzaria do Zé",
  "compliance_status": "active"
}
Cliente com a declaração de lembretes
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."
  }
}'
Resposta · 201
{
  "client_id": "cli_6c3d9f2b-8e4a-4b7c-8d9f-2a3b4c5d6e7f",
  "external_id": "loja-42-lembretes",
  "name": "Clínica Sorriso",
  "compliance_status": "active"
}
CampoRegraErro
nameO nome do cliente, de 2 a 80 caracteres.400 name
external_idObrigatório: o id do cliente no seu sistema, até 120 caracteres. Único na conta.400 external_id
siteOpcional: o endereço do site (até 200 caracteres).400 site
utility_consentOpcional: 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}

Os dados, os chatbots e a conformidade do cliente
curl "https://boavoz.com/api/v1/clients/cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e" \
  -H "Authorization: Bearer $BOAVOZ_API_KEY"
Resposta · 200
{
  "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

Criar o chatbot da loja a partir do modelo
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"
  }
}'
Resposta · 201
{
  "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
}
Com valores próprios nos campos que o modelo libera
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?"
  }
}'
Resposta · 201
{
  "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
}
CampoRegraErro
client_idObrigatório: o cli_… do POST /v1/clients. Com chave de escopo de um cliente, só o cliente dela.400 client_id; 404
template_idObrigató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_idOpcional: o id do chatbot no seu sistema, até 120 caracteres, único no cliente. Com ele, repetir devolve o mesmo chatbot (200).400 external_id
contextOpcional: 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
displayOpcional: 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
overridesOpcional: 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, overageOpcionais, 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.

O que o chatbot herda do modelo muda quando você publica o modelo de novo; o 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}

Mudar o display, a saudação e o horário
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"
    ]
  }
}'
Resposta · 200
{
  "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
  }
}
CampoRegraErro
displayOs dados da loja para a IA, como no POST; null tira.400 display
overridesSó 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_hoursO 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_destinationOs 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).

O link de conexão do WhatsApp
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"
}'
Resposta · 200
{
  "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

Os canais do chatbot
curl "https://boavoz.com/api/v1/bots/bot_7c9e6679-7425-40de-944b-e07fc1f90ae7/channels" \
  -H "Authorization: Bearer $BOAVOZ_API_KEY"
Resposta · 200
{
  "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}

Desconectar de vez
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"
Resposta · 204
(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

Pausar o chatbot
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
}'
Resposta · 200
{
  "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

Retomar (as medidas em vigor voltam em restrictions)
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"
Resposta · 200
{
  "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

O uso do mês por cliente e chatbot
curl "https://boavoz.com/api/v1/usage" \
  -H "Authorization: Bearer $BOAVOZ_API_KEY"
Resposta · 200
{
  "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

Convidar alguém da loja para o portal
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"
}'
Resposta · 201
{
  "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"
}
CampoRegraErro
emailObrigatório: a pessoa recebe nele o link de acesso, com a marca da sua conta.400 email
roleObrigatório: manager (gestor: tudo o que a agência liberou no portal) ou agent (atendente: só as conversas).400 role
display_nameOpcional: 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).

O BoaVoz guarda a chave que convidou cada pessoa. Ao revogar uma chave, a tela das chaves mostra quantas pessoas ela convidou, com "remover todas". O dono da conta recebe por dia o resumo dos convites pela API e um alerta na hora quando eles passam de 20 em 24 horas.

GET/v1/clients/{id}/members

A equipe do portal do cliente
curl "https://boavoz.com/api/v1/clients/cli_5b2c8e1a-7d3f-4a6b-9c8e-1f2a3b4c5d6e/members" \
  -H "Authorization: Bearer $BOAVOZ_API_KEY"
Resposta · 200
{
  "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}

Tirar o acesso ao portal
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"
Resposta · 204
(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.