Ir al contenido
Desarrolladores

Una API pequeña, documentada y previsible

Lo que se puede automatizar está aquí: clientes, personas, productos, notas de versión, base de conocimiento y agentes de IA. La especificación se genera del propio código — lo que está en la doc es lo que hace el servidor.

  • Spec OpenAPI con 42 operaciones
  • Idempotencia en las escrituras
  • 600 solicitudes por minuto
Inicio rápido

De la clave a la primera llamada

Tres pasos en el panel y una llamada en su terminal.

  1. 1

    Genere la clave

    En Integraciones › Claves de API, marcando solo los alcances que la integración necesita.

  2. 2

    Guárdela fuera del código

    Variable de entorno en su servidor. La clave de servidor nunca va al navegador.

  3. 3

    Llame

    Toda solicitud lleva Authorization: Bearer. Las escrituras aceptan Idempotency-Key.

ServidorPáginaSDKs
# la spec sale del servidor, no de un archivo escrito a mano
curl -s https://api.bfocus.com.br/api/v1/integration/openapi.json \
  | jq '.info, (.paths | keys | length)'

# toda llamada autenticada lleva la clave en la cabecera
curl -s https://api.bfocus.com.br/api/v1/integration/products \
  -H "Authorization: Bearer $BFOCUS_API_KEY"

La especificación la sirve la propia API, generada del código

SDKs oficiales

Siete lenguajes, el mismo comportamiento

Todas pasan por el mismo conjunto de 74 casos de conformidad: mismos nombres, mismos errores con código estable y la misma política de reintento.

Los siete están publicados en el registro de cada lenguaje, en la versión 0.2.5, con el código en un repositorio público. Para otro lenguaje, la API REST funciona igual.

Todos los repositorios en github.com/bernisoftware

Monitoreo

Nueve paquetes de captura, el mismo evento en todos

Paquetes del adicional Monitoreo: una llamada a init con la clave de envío del agente y el error de su sistema llega agrupado, sin dato personal, y nace como tarea en Proyectos. La misma ruta, el mismo formato de evento y la misma versión en todos — ninguno tiene dependencia de runtime ni hace una llamada de red al importarse.

¿Sin build en el front? Una etiqueta de script alcanza: <script src="https://widget.bfocus.com.br/v1/monitor.js" data-bf-monitor-key="bf_mon_…" async></script>

Los nueve están en el registro de cada lenguaje, en la versión 0.1.2. Una falla del monitor nunca tira su sistema: el manejador que ya existía sigue valiendo, la cola es limitada y todo error nuestro se traga.

Ver qué hace el Monitoreo

Papeles del producto

El papel llega desde su página, y usted lo sincroniza por la SDK

El papel dice quién es la persona en ese producto — administrador, facturación, mostrador. Su página declara role: { key, label } en el init del widget y, si ese papel aún no existe, queda registrado y vinculado solo. Estas tres operaciones son el otro camino: sincronizar, en cada deploy, los papeles que su sistema ya conoce, con las dos instrucciones que usa el agente de IA.

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

    Los papeles de ese producto, por nombre, con cuántas personas hay en cada uno.

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

    Idempotente: puede correr en cada deploy. Solo cambia lo que viene en el cuerpo, y una cadena vacía limpia una instrucción.

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

    Quien tenía el papel queda sin papel y la novedad dirigida a él vuelve a valer para todos. Si su página sigue declarando la clave, el papel se registra de nuevo en la próxima sesión.

En los siete lenguajes, con el mismo nombre. La key es inmutable — es por ella que su página se refiere al papel; el rótulo y las dos instrucciones cambian a voluntad. El papel es declaración, no permiso: lo declara su página y viaja FUERA de la firma (el userHash cubre usuario y cliente), así que las limitaciones de acceso son instrucción de conversación para el agente — quien decide lo que la persona ve sigue siendo bFocus.

Ver cómo el widget declara el papel

Sincronía

Su sistema y bFocus, con el mismo registro

Nadie escribe un cliente dos veces. Su ERP, su SaaS o su sistema de escritorio manda lo que ya tiene — con el id que ya usa — y bFocus pasa a saber quién es quién, quién usa qué producto y qué salió en cada versión.

  1. 1

    El id es el suyo

    PUT /customers/{su_id}: crear y actualizar son la misma llamada, con el código que su sistema ya usa. Vale para cliente, persona, contacto, identificador extra, vínculo con producto, producto, nota de versión y artículo de la base.

  2. 2

    La carga inicial va en lote

    Hasta 500 clientes o 500 personas por llamada (100 artículos). Cada ítem es independiente: lo que falla vuelve con su propio código de error, en el mismo orden, y no tumba a los demás.

  3. 3

    Repetir es seguro

    Las escrituras de la API pública aceptan Idempotency-Key: por 24 horas, la repetición devuelve la respuesta original con Idempotent-Replayed, sin ejecutar de nuevo. Las SDK mandan la clave solas en cada reintento — un timeout seguido de retry devuelve la misma respuesta en vez de crear el registro dos veces.

  4. 4

    El registro responde qué pasó

    linked cuando la misma persona pasa a valer en un cliente más, merged_into cuando su id se volvió alias de una ficha que ya existía, unlinked cuando sale de este cliente y sigue en los otros. El 409 de contacto repetido dice de quién es el contacto.

Qué conecta la sincronía del otro lado

  • Quien usted sincronizó es quien entra en el widget, con acceso decidido por vínculo y la firma de su servidor
  • El vínculo cliente↔producto decide qué ve cada uno de las novedades y qué usa la IA para responder
  • La nota de versión publicada por su deploy, idempotente por producto y versión, enciende el distintivo en la app del cliente y registra el acuse de cada uno
  • Los artículos de la base entran por código externo y se vuelven fuente del agente de IA, con búsqueda por la misma API
  • El historial del cliente acepta las interacciones de su sistema, y aparecen en el dossier al lado de la Mesa
  • El CPF une registros solo; sin CPF, nombre y contacto van a la cola de posibles duplicados en vez de fusionarse a la fuerza

Qué no hace la API

  • No abre tickets: el ticket nace del widget, del correo, del chat, del teléfono o de WhatsApp — y es a propósito, para que toda atención tenga una conversación de origen.
  • No crea leads: el lead nace en la puerta de su sitio o a mano, en la pantalla de Leads.
Lo que cubre la API

Pocos recursos, bien resueltos

Preferimos una API pequeña que no cambia a una API grande que se rompe.

Clientes

El contratante, empresa o persona física: kind, el documento fiscal en document, razón social e inscripciones en la empresa, documento de identidad en la persona física. Con contactos, productos vinculados, campos personalizados e historial de contacto.

Personas

La persona vive dentro del cliente (la carga en lote y sus identificadores tienen ruta propia), con documento, campos personalizados y acceso al portal. La respuesta dice qué pasó: linked cuando la misma persona pasa a valer en un cliente más, merged_into cuando su id se volvió alias de una ficha que ya existía, unlinked cuando sale de este cliente y sigue en los demás.

Identificadores extra

Una persona o un cliente se encuentra por varios ids. La lista vuelve legible — external_id, label y quién lo vinculó — así descubre que el id de su sistema se volvió alias del registro de otro.

Carga en lote

Hasta 500 clientes o personas en una llamada. Cada ítem es independiente: el que falla vuelve con su código de error, en el mismo orden, y no tumba a los demás.

Productos

El catálogo de lo que vende su empresa, que organiza base de conocimiento, agentes y notas de versión.

Papeles del producto

Listar, registrar/actualizar y borrar el papel de quien usa cada producto: GET, PUT y DELETE en /products/{slug}/roles, con los alcances products:read y products:write. El PUT es idempotente, hecho para correr en su deploy. El papel también llega solo por el widget — y sirve para guiar al agente de IA y dirigir novedades internas, nunca como permiso.

Notas de versión

Publicación idempotente por producto y versión, pensada para correr dentro de su deploy.

Base de conocimiento

Creación y actualización por código externo, en lotes de hasta 100, con publicación y búsqueda.

Agentes de IA

Lectura de la configuración y vista previa de respuesta, para que pruebe el agente antes de liberarlo.

Claves

Varias por empresa, con alcance por recurso, lista de IPs opcional, revocación y registro del último uso. La dirección rechazada entra en la fila de Autorizaciones, para liberarla con un clic.

Reglas de la casa

  • Autenticación por Bearer, con alcances separados de lectura y escritura
  • Idempotency-Key en las escrituras de esta API: por 24 horas, repetir la llamada devuelve la misma respuesta en vez de crearla de nuevo
  • X-Request-Id en toda respuesta, para que la correlacione con su log
  • Límite de 600 solicitudes por minuto por clave
  • De servidor a servidor: la API de integración no valida dominios ni usa CORS — quien autentica es la clave secreta
  • Restricción de origen opcional por IP, rango CIDR o nombre de máquina resuelto en el momento de la llamada
  • Errores con código estable, pensados para que su tratamiento no se rompa cuando cambie el texto
  • Borrar un contacto es explícito: clear: ["email", "phone"] lo borra; null o el campo ausente significa "no lo toque"
  • El 409 de contacto ya usado dice de quién es el contacto, así que usted decide sin abrir la base
  • Especificación OpenAPI con 42 operaciones, generada del código y servida por la propia API
Identidad verificada

Su servidor dice quién está del otro lado

Con la identidad verificada activada, es lo que impide que un cliente vea el ticket de otro. Vale en el widget web, en los paquetes nativos y en el modo navegador. Quien crea el widget hoy ya empieza con ella activada.

  1. 1 Su backend firma el par usuario + empresa con la clave secreta de su cuenta
  2. 2 La app pasa esa firma al inicializar el widget
  3. 3 bFocus verifica la firma. Con la identidad verificada activada, bFocus rechaza a quien no trae una firma válida
  4. 4 La firma vale 7 días y lleva el instante en que se hizo. Cuando vence, el widget le pide una nueva a la página y sigue donde estaba, sin recargar — el visitante no pierde lo que escribió
  5. 5 La página responde por uno de estos caminos: onIdentityExpired en las opciones del init, el evento bfocus:identity-expired en window, o bFocus.identify({ user, customer, userHash }) en cualquier momento, con los campos que quiera
  6. 6 La respuesta tiene que llegar en 8 segundos. Sin ella, aparece la pantalla de identidad rechazada, como antes
  7. 7 En los nueve paquetes nativos no hay nada que hacer: la renovación usa el userHashProvider que usted ya configuró
  8. 8 Al cambiar la clave secreta, la anterior sigue valiendo 7 días, así que el cambio no deja fuera a quien lleva la firma anterior

Ejemplos listos

La guía de identidad verificada trae el cálculo de la firma v2 en Node, Python, PHP y en los demás lenguajes de las SDKs, con un ejemplo para copiar y una prueba para comprobar que su implementación coincide con la nuestra.

Preguntas técnicas

¿Por dónde entran los tickets?

Por el widget, con la clave publicable, por el correo y por WhatsApp. La API de integración se ocupa del registro alrededor: clientes, contactos, productos, identificadores, importación en lote e interacciones con clientes.

¿Puedo ver el código de los SDKs?

Puede. Cada SDK y cada paquete nativo tiene repositorio público en github.com/bernisoftware, con el README y los ejemplos que aparecen en esta página.

¿Cómo versionan la API?

Cada release de las SDKs declara si la superficie pública cambió. Recomendamos fijar la versión exacta del paquete y subir leyendo esa línea.

¿Puedo usar solo la API, sin widget?

Puede. Mucha gente empieza sincronizando clientes del ERP y publicando notas de versión desde el deploy, y solo después coloca el widget.

¿Cómo decide el widget en qué dominios abre?

El navegador informa la dirección de la página, así que la comprobación va por el dominio real — esa lista es lo que protege la clave publicable, que es pública. Registre el dominio raíz y los subdominios vienen incluidos: https://cliente.com ya habilita app.cliente.com y tienda.cliente.com. Es el camino recomendado, porque deja menos margen de error. El comodín explícito también funciona, como alternativa: https://*.cliente.com. El esquema tiene que coincidir (https no cubre http) y el puerto también, cuando usted declara uno. En los paquetes nativos el origen es app:// seguido del id de la aplicación, y ahí el host es un identificador: app://com.cliente no habilita app://com.cliente.otro, así que registre cada id.

Un dominio (o una IP) fue rechazado. ¿Cómo lo libero?

Sin escribir nada. Un dominio rechazado en el widget, o una dirección rechazada en una clave de API, se vuelve una línea en Empresa › Integraciones › Autorizaciones: la dirección exactamente como llegó, cuántos intentos y cuándo fue el último. Liberar es un clic, y el valor entra en la lista correcta — los dominios del widget o las IPs de esa clave. Eso acaba con el error de escribir www en lugar del dominio raíz, o http en lugar de https. Solo el administrador libera. Descartar saca la línea de la fila sin autorizar nada.

La firma venció con la página abierta. ¿El usuario pierde lo que escribió?

No. El widget le pide una identidad nueva a la página y sigue donde estaba, sin recargar. La página responde por el onIdentityExpired del init, por el evento bfocus:identity-expired en window o llamando a bFocus.identify en cualquier momento — y la respuesta puede ser una promesa. El plazo es de 8 segundos; pasado eso, aparece la pantalla de identidad rechazada. En los paquetes nativos la renovación usa el userHashProvider que usted ya configuró.

¿Puedo restringir la API de integración por dominio?

No, y es a propósito: en una llamada de servidor no existe Origin, y un dominio declarado por el cliente sería falsificable — parecería protección sin serlo. La credencial aquí es la clave secreta, con alcances por recurso, límite por minuto, revocación y registro del último uso. Existe además la restricción opcional por dirección de origen: IP, rango CIDR o nombre de máquina resuelto por DNS en el momento de la llamada. Le sirve a quien llama desde un servidor con IP de salida fija, como un VPS o una máquina propia. En una plataforma sin IP de salida fija — App Platform, Lambda, Cloud Run, CI — no sirve, porque la IP que sale de ahí no tiene relación con el dominio de su aplicación. La clave secreta nunca va al navegador. Si su front necesita los datos, quien llama a la API es el backend de su empresa; al navegador va solo la clave publicable del widget.

Genere una clave y pruébela en diez minutos

La cuenta de prueba ya viene con acceso a la API y a la especificación completa.