Ir para o conteúdo
Desenvolvedores

Uma API pequena, documentada e previsível

O que dá para automatizar está aqui: clientes, pessoas, produtos, notas de versão, base de conhecimento e agentes de IA. A especificação é gerada do próprio código — o que está na doc é o que o servidor faz.

  • Spec OpenAPI com 42 operações
  • Idempotência nas escritas
  • 600 requisições por minuto
Início rápido

Da chave à primeira chamada

Três passos no painel e uma chamada no seu terminal.

  1. 1

    Gere a chave

    Em Integrações › Chaves de API, marcando só os escopos de que a integração precisa.

  2. 2

    Guarde fora do código

    Variável de ambiente no seu servidor. A chave de servidor nunca vai para o navegador.

  3. 3

    Chame

    Toda requisição leva Authorization: Bearer. As escritas aceitam Idempotency-Key.

ServidorPáginaSDKs
# a spec sai do servidor, não de um arquivo escrito à mão
curl -s https://api.bfocus.com.br/api/v1/integration/openapi.json \
  | jq '.info, (.paths | keys | length)'

# toda chamada autenticada leva a chave no cabeçalho
curl -s https://api.bfocus.com.br/api/v1/integration/products \
  -H "Authorization: Bearer $BFOCUS_API_KEY"

A especificação é servida pela própria API, gerada do código

SDKs oficiais

Sete linguagens, o mesmo comportamento

Todas passam pelo mesmo conjunto de 74 casos de conformidade: mesmos nomes, mesmos erros com código estável e a mesma política de nova tentativa.

As sete estão publicadas no registro de cada linguagem, na versão 0.2.5, com o código em repositório público. Para outra linguagem, a API REST atende do mesmo jeito.

Todos os repositórios em github.com/bernisoftware

Monitoramento

Nove pacotes de captura, o mesmo evento em todos

Pacotes do módulo Monitoramento (adicional): uma chamada de init com a chave de envio do agente e o erro do seu sistema chega agrupado, sem dado pessoal, e nasce como demanda no Projetos. Mesma rota, mesmo formato de evento e a mesma versão em todos — nenhum tem dependência de runtime e nenhum faz chamada de rede ao ser importado.

Sem build no front? Uma tag de script resolve: <script src="https://widget.bfocus.com.br/v1/monitor.js" data-bf-monitor-key="bf_mon_…" async></script>

Os nove estão no registro de cada linguagem, na versão 0.1.2. Falha do monitor nunca derruba o seu sistema: o tratador que já existe continua valendo, a fila é limitada e todo erro nosso é engolido.

Ver o que o Monitoramento faz

Papéis do produto

O papel chega pela sua página, e você sincroniza pela SDK

O papel diz quem é a pessoa naquele produto — administrador, faturamento, balconista. A sua página declara role: { key, label } no init do widget e, se aquele papel ainda não existir, ele é cadastrado e vinculado sozinho. Estas três operações são o outro caminho: sincronizar, a cada deploy, os papéis que o seu sistema já conhece, com as duas instruções que o agente de IA usa.

  • products.roles.list products:read
    GET /products/{slug}/roles

    Os papéis daquele produto, em ordem de nome, com quantas pessoas estão em cada um.

  • products.roles.upsert products:write
    PUT /products/{slug}/roles/{key}

    Idempotente: pode rodar a cada deploy. Só o que vem no corpo muda, e string vazia limpa uma instrução.

  • products.roles.delete products:write
    DELETE /products/{slug}/roles/{key}

    Quem estava no papel fica sem papel e a novidade dirigida a ele volta a valer para todos. Se a sua página continuar declarando a chave, ele é cadastrado de novo na próxima sessão.

Nas sete linguagens, com o mesmo nome. A key é imutável — é por ela que a sua página se refere ao papel; o rótulo e as duas instruções mudam à vontade. O papel é declaração, não permissão: ele é declarado pela sua página e viaja FORA da assinatura (o userHash cobre usuário e cliente), então as limitações de acesso são instrução de conversa para o agente — quem decide o que a pessoa vê continua sendo o bFocus.

Ver como o widget declara o papel

Sincronia

O seu sistema e o bFocus, com o mesmo cadastro

Ninguém digita cliente duas vezes. O seu ERP, o seu SaaS ou o seu sistema de mesa manda o que já tem — com o id que ele já usa — e o bFocus passa a saber quem é quem, quem usa qual produto e o que saiu em cada versão.

  1. 1

    O id é o seu

    PUT /customers/{seu_id}: criar e atualizar são a mesma chamada, com o código que o seu sistema já usa. Vale para cliente, pessoa, contato, identificador extra, vínculo com produto, produto, nota de versão e artigo da base.

  2. 2

    A carga inicial vai em lote

    Até 500 clientes ou 500 pessoas por chamada (100 artigos). Cada item é independente: o que falha volta com o código do erro dele, na mesma ordem, e não derruba os outros.

  3. 3

    Repetir é seguro

    As escritas da API pública aceitam Idempotency-Key: por 24 horas, a repetição devolve a resposta original com Idempotent-Replayed, sem executar de novo. As SDKs mandam a chave sozinhas em cada nova tentativa — um timeout seguido de retry devolve a mesma resposta em vez de criar o registro duas vezes.

  4. 4

    O cadastro responde o que aconteceu

    linked quando a mesma pessoa passa a valer em mais um cliente, merged_into quando o seu id virou apelido de uma ficha que já existia, unlinked quando ela sai daqui e continua nos outros. O 409 de contato repetido diz de quem é o contato.

O que a sincronia liga do outro lado

  • Quem você sincronizou é quem entra no widget, com acesso decidido por vínculo e a assinatura do seu servidor
  • O vínculo cliente↔produto decide o que cada um enxerga de novidades e o que a IA usa para responder
  • A nota de versão publicada pelo seu deploy, idempotente por produto e versão, acende o selo no app do cliente e registra a ciência de cada um
  • Os artigos da base entram por código externo e viram fonte do agente de IA, com busca pela mesma API
  • O histórico do cliente aceita as interações do seu sistema, e elas aparecem no dossiê ao lado da Mesa
  • O CPF junta cadastros sozinho; sem CPF, nome e contato vão para a fila de possíveis duplicados em vez de fundir na marra

O que a API não faz

  • Não abre chamado: o chamado nasce do widget, do e-mail, do chat, do telefone ou do WhatsApp — e é assim de propósito, para todo atendimento ter uma conversa de origem.
  • Não cria lead: o lead nasce na porta do seu site ou à mão, na tela de Leads.
O que a API cobre

Poucos recursos, bem resolvidos

Preferimos uma API pequena que não muda a uma API grande que quebra.

Clientes

O contratante, PJ ou PF: kind, CNPJ ou CPF em document, razão social e inscrições na empresa, RG na pessoa física. Com contatos, produtos vinculados, campos personalizados e registros de contato.

Pessoas

A pessoa vive dentro do cliente (e a carga em lote e os identificadores dela têm rota própria), com CPF, campos personalizados e acesso ao portal. A resposta diz o que aconteceu: linked quando a mesma pessoa passa a valer em mais um cliente, merged_into quando o seu id virou apelido de uma ficha que já existia, unlinked quando ela sai deste cliente e continua nos outros.

Identificadores extras

Uma pessoa ou um cliente é achado por vários ids. A lista volta legível — external_id, label e quem ligou — então você descobre que o id do seu sistema virou apelido do cadastro de outro.

Carga em lote

Até 500 clientes ou pessoas numa chamada. Cada item é independente: o que falha volta com o código do erro dele, na mesma ordem, e não derruba os outros.

Produtos

O catálogo do que a sua empresa vende, que organiza base de conhecimento, agentes e notas de versão.

Papéis do produto

Listar, cadastrar/atualizar e apagar o papel de quem usa cada produto: GET, PUT e DELETE em /products/{slug}/roles, com os escopos products:read e products:write. O PUT é idempotente, feito para rodar no seu deploy. O papel também chega sozinho pelo widget — e serve para guiar o agente de IA e dirigir novidade interna, nunca como permissão.

Notas de versão

Publicação idempotente por produto e versão, pensada para rodar dentro do seu deploy.

Base de conhecimento

Criação e atualização por código externo, em lotes de até 100, com publicação e busca.

Agentes de IA

Leitura da configuração e prévia de resposta, para você testar o agente antes de liberar.

Chaves

Várias por empresa, com escopo por recurso, lista de IPs opcional, revogação e registro do último uso. O endereço recusado entra na fila de Autorizações, para liberar com um clique.

Regras da casa

  • Autenticação por Bearer, com escopos separados de leitura e escrita
  • Idempotency-Key nas escritas desta API: por 24 horas, repetir a chamada devolve a mesma resposta em vez de criar de novo
  • X-Request-Id em toda resposta, para você correlacionar com o seu log
  • Limite de 600 requisições por minuto por chave
  • Chamada de servidor para servidor: a API de integração não valida domínio nem usa CORS — quem autentica é a chave secreta
  • Restrição de origem opcional por IP, faixa CIDR ou nome de máquina resolvido na hora da chamada
  • Erros com código estável, pensados para o seu tratamento não quebrar quando o texto mudar
  • Apagar contato é explícito: clear: ["email", "phone"] apaga; null ou campo ausente quer dizer "não mexe"
  • O 409 de contato já usado diz de quem é o contato, então você decide o que fazer sem abrir o banco
  • Especificação OpenAPI com 42 operações, gerada do código e servida pela própria API
Identidade verificada

O seu servidor diz quem está do outro lado

Com a identidade verificada ligada, é o que impede um cliente de ver o chamado de outro. Vale no widget web, nos pacotes nativos e no modo navegador. Quem cria o widget hoje já começa com ela ligada.

  1. 1 O seu backend assina o par usuário + empresa com a chave secreta da sua conta
  2. 2 O app passa essa assinatura ao inicializar o widget
  3. 3 O bFocus confere a assinatura. Com a identidade verificada ligada, o bFocus recusa quem não traz uma assinatura válida
  4. 4 A assinatura vale 7 dias e carrega o instante em que foi feita. Quando vence, o widget pede uma nova à página e continua de onde estava, sem recarregar — o visitante não perde o que digitou
  5. 5 A página responde por um destes caminhos: onIdentityExpired nas opções do init, o evento bfocus:identity-expired em window, ou bFocus.identify({ user, customer, userHash }) a qualquer momento, com os campos que quiser
  6. 6 A resposta precisa chegar em 8 segundos. Sem ela, aparece a tela de identidade recusada, como antes
  7. 7 Nos nove pacotes nativos não há nada a fazer: a renovação usa o userHashProvider que você já configurou
  8. 8 Ao trocar a chave secreta, a anterior ainda vale por 7 dias, então a troca não derruba quem está com a assinatura antiga

Exemplos prontos

O guia de identidade verificada traz o cálculo da assinatura v2 em Node, Python, PHP e nas demais linguagens das SDKs, com um exemplo para copiar e um teste para conferir se a sua implementação bate com a nossa.

Perguntas técnicas

Por onde entram os chamados?

Pelo widget, com a chave publicável, pelo e-mail e pelo WhatsApp. A API de integração cuida do cadastro em volta: clientes, contatos, produtos, identificadores, importação em lote e interações com clientes.

Posso ver o código das SDKs?

Pode. Cada SDK e cada pacote nativo tem repositório público em github.com/bernisoftware, com o README e os exemplos que aparecem nesta página.

Como vocês versionam a API?

Cada release das SDKs declara se a superfície pública mudou. Recomendamos fixar a versão exata do pacote e subir lendo essa linha.

Posso usar só a API, sem widget?

Pode. Muita gente começa sincronizando clientes do ERP e publicando notas de versão pelo deploy, e só depois coloca o widget.

Como o widget decide em que domínios ele abre?

O navegador informa o endereço da página, então a conferência é por domínio de verdade — é essa lista que protege a chave publicável, que é pública. Cadastre o domínio raiz e os subdomínios vêm junto: https://cliente.com.br já libera app.cliente.com.br e loja.cliente.com.br. É o caminho recomendado, porque dá menos margem a erro. O curinga explícito também funciona, como alternativa: https://*.cliente.com. O esquema precisa bater (https não cobre http) e a porta também, quando você declara uma. Nos pacotes nativos a origem é app:// seguido do id do aplicativo, e ali o host é um identificador: app://com.cliente não libera app://com.cliente.outro, então cadastre cada id.

Um domínio (ou um IP) foi recusado. Como libero?

Sem digitar nada. Domínio recusado no widget, ou endereço recusado numa chave de API, vira uma linha em Empresa › Integrações › Autorizações: o endereço exatamente como chegou, quantas tentativas e quando foi a última. Liberar é um clique, e o valor entra na lista certa — os domínios do widget ou os IPs daquela chave. Isso acaba com o erro de digitar www no lugar do domínio raiz, ou http no lugar de https. Só administrador libera. Descartar tira da fila sem autorizar nada.

A assinatura venceu com a página aberta. O usuário perde o que digitou?

Não. O widget pede uma identidade nova à página e segue de onde estava, sem recarregar. A página responde pelo onIdentityExpired do init, pelo evento bfocus:identity-expired em window ou chamando bFocus.identify a qualquer momento — e a resposta pode ser uma promessa. O prazo é de 8 segundos; passando disso, aparece a tela de identidade recusada. Nos pacotes nativos a renovação usa o userHashProvider que você já configurou.

Dá para restringir a API de integração por domínio?

Não, e isso é de propósito: numa chamada de servidor não existe Origin, e um domínio declarado pelo cliente seria forjável — pareceria proteção sem ser. A credencial ali é a chave secreta, com escopos por recurso, limite por minuto, revogação e registro do último uso. Existe ainda a restrição opcional por endereço de origem: IP, faixa CIDR ou nome de máquina resolvido por DNS na hora da chamada. Ela resolve para quem chama de servidor com IP de saída fixo, como VPS ou servidor próprio. Em plataforma sem IP de saída fixo — App Platform, Lambda, Cloud Run, CI — ela não serve, porque o IP que sai de lá não tem relação com o domínio do seu app. A chave secreta nunca vai para o navegador. Se o seu front precisa dos dados, quem chama a API é o backend da sua empresa; no navegador vai só a chave publicável do widget.

Gere uma chave e teste em dez minutos

A conta de teste já vem com acesso à API e à especificação completa.