API · Guía oficial
Integraciones externas para agentes de IA
Conecta Codex u otra herramienta con tus agentes de Bulest sin compartir tu contraseña. El token define la cuenta, los agentes y las acciones permitidas; cada cambio queda aislado y trazable.
Qué permite esta integración
Una Integración externa es una credencial revocable asociada a la cuenta activa de Bulest. Puede limitarse a agentes concretos y a capacidades específicas. La API pública usa como base:
https://bulest.co/api/v1/external
Dependiendo de los permisos concedidos, una herramienta puede:
- Consultar agentes y su configuración pública.
- Explorar productos y variantes de la tienda vinculada a cada agente.
- Subir archivos y vincular varios recursos ordenados a un mismo fragmento.
- Leer fragmentos y preparar cambios sin tocar inmediatamente al agente activo.
- Asignar un agente autorizado a un canal concreto de la cuenta.
- Probar un borrador con texto, imágenes, audio, video o archivos en el Chat de pruebas.
- Solicitar aprobación o aplicar un borrador de acuerdo con la política elegida.
- Consultar en la Caja Negra la actividad atribuida a esa integración.
La cuenta es implícita
Nunca envíes user_id ni account_id. Bulest deriva ambos del token y vuelve a verificar el alcance en cada solicitud.
1. Crear el acceso en Bulest
- Abre Perfil → Integraciones externas.
- Selecciona Nueva integración y ponle un nombre reconocible, por ejemplo “Codex — conocimiento de ventas”.
- Elige los permisos y los agentes a los que podrá acceder.
- Define cómo manejará los cambios: solo borradores, aprobación humana o aplicación directa.
- Copia la clave de conexión. Bulest la muestra completa una sola vez; vence como máximo en 30 días.
Trata el token como una contraseña
No lo publiques, no lo guardes en el repositorio y no lo envíes en la URL. Si se pierde o se expone, rótalo desde Perfil; el anterior dejará de funcionar inmediatamente.
Permisos disponibles
| Permiso | Uso |
|---|---|
| agents.read | Lista y consulta agentes autorizados. |
| agents.lifecycle | Crea y archiva agentes. |
| fragments.read | Consulta fragmentos y la revisión vigente. |
| fragments.draft | Prepara borradores de configuración o conocimiento. |
| fragments.apply | Envía a aprobación o aplica según la política configurada. |
| files.upload | Sube un archivo propio de la cuenta para vincularlo a fragmentos. |
| instances.assign | Consulta canales de la cuenta y asigna o retira agentes autorizados. |
| catalog.read | Consulta productos, variantes e IDs de la tienda vinculada al agente. |
| configuration.read | Diagnostica instancias, tienda, departamentos, capacidades, calendarios y dependencias antes de editar. |
| chat_test.run | Usa el Chat de pruebas con la versión activa o un borrador. |
| activity.read | Consulta la actividad de esa integración. |
2. Autenticación con sesión temporal
La clave de conexión se usa para solicitar una sesión, no para consultar o modificar recursos directamente. Envía las credenciales en el encabezado Authorization; nunca en la URL ni dentro del cuerpo.
Solicitar la sesión
curl -X POST https://bulest.co/api/v1/external/session \ -H "Authorization: Bearer CLAVE_DE_CONEXION" \ -H "Accept: application/json"
La respuesta contiene access_token, token_type y expires_in. La sesión dura como máximo 15 minutos y puede terminar antes si vence su clave de origen.
Usar el acceso temporal
curl https://bulest.co/api/v1/external/guide \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Accept: application/json"
Cuando venza la sesión, solicita otra con la clave de conexión. Una sesión no sirve para emitir otra sesión. Rotar o revocar la clave invalida sus accesos; los permisos se vuelven a comprobar en cada llamada.
Las credenciales normales ya están vinculadas a una cuenta. Si utilizas una credencial administrativa de plataforma, selecciona el negocio con X-Bulest-Owner-Id y, cuando corresponda, X-Bulest-Account-Id en las operaciones que lo requieren.
Para solicitudes JSON añade Content-Type: application/json. Para POST /files usa multipart/form-data y deja que tu cliente HTTP establezca el límite de formulario. Este acceso administrativo es independiente del inicio de sesión de los clientes finales.
3. Descubrir capacidades
El primer llamado recomendado es GET /guide. Devuelve los permisos, la política, los agentes visibles y un mapa de las operaciones disponibles para ese token. GET /capabilities es un alias compatible.
{
"success": true,
"integration": {
"id": "INTEGRATION_ID",
"name": "Codex — conocimiento de ventas",
"permissions": ["agents.read", "fragments.read", "fragments.draft"],
"agent_scope_mode": "selected",
"change_policy": "approval_required"
},
"agents": [
{ "id": "AGENT_ID", "name": "Ventas", "revision": "REVISION_SHA256" }
],
"guide": { "base_path": "/api/v1/external", "endpoints": {} }
}
Una herramienta debe tratar esta respuesta como la autoridad del acceso y no intentar operar sobre agentes o capacidades ausentes.
4. Leer agentes y fragmentos
| Método | Ruta | Resultado |
|---|---|---|
| GET | /agents | Agentes visibles para el token. |
| GET | /agents/AGENT_ID | Configuración pública y revisión. |
| GET | /agents/AGENT_ID/configuration-context | Relaciones, estado de dependencias y advertencias previas a la edición. |
| GET | /agents/AGENT_ID/fragments | Snapshot de fragmentos y revision. |
curl https://bulest.co/api/v1/external/agents/AGENT_ID/fragments \ -H "Authorization: Bearer ACCESS_TOKEN"
Conserva la revisión
La respuesta incluye revision. Debes enviarla como base_revision al preparar un cambio. Si alguien editó el agente entre ambos pasos, Bulest rechazará el borrador en lugar de pisar el cambio humano.
Comprueba el contexto antes de editar
Con GET /agents/AGENT_ID/configuration-context la integración puede detectar, por ejemplo, una instancia desconectada, una tienda ausente, un calendario eliminado o un departamento sin asesores disponibles. Los IDs se incluyen para operaciones precisas, pero los diagnósticos usan nombres y mensajes legibles.
curl https://bulest.co/api/v1/external/agents/AGENT_ID/configuration-context \ -H "Authorization: Bearer ACCESS_TOKEN"
5. Subir recursos y vincularlos en orden
Un fragmento puede incluir varios archivos o imágenes. Primero sube cada archivo a la cuenta de la integración y después copia, sin modificarlo, el objeto attachment de la respuesta dentro de meta.attachments. La posición en el arreglo define la secuencia en la que Bulest entrega los recursos al agente.
La carga admite hasta 25 MB por archivo. Bulest devuelve el recurso ya normalizado: no inventes ni cambies su ID, ruta o URL.
curl -X POST https://bulest.co/api/v1/external/files \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Accept: application/json" \ -F "file=@/ruta/ficha-tecnica.pdf" \ -F "description=Ficha técnica de la colección"
La ruta requiere files.upload y responde 201 Created:
{
"success": true,
"file": {
"id": "184",
"filename": "ficha-tecnica.pdf",
"filetype": "application/pdf",
"size_bytes": 348120,
"url": "https://bulest.co/static/uploads/.../ficha-tecnica.pdf"
},
"attachment": {
"file_id": "184",
"filename": "ficha-tecnica.pdf",
"filepath": "USER_ID/files/uuid_ficha-tecnica.pdf",
"filetype": "application/pdf",
"image_url": "https://bulest.co/static/uploads/.../ficha-tecnica.pdf"
},
"usage": {
"meta_path": "meta.attachments",
"order": "La posición cero se entrega primero."
}
}
{
"base_revision": "REVISION_SHA256",
"fragment": {
"title": "Material de la colección",
"type": "file",
"content": "Usa estos recursos en este mismo orden cuando sea útil.",
"active": true,
"meta": {
"attachments": [
{
"file_id": "181",
"filename": "frontal.jpg",
"filepath": "USER_ID/files/uuid_frontal.jpg",
"filetype": "image/jpeg",
"image_url": "https://bulest.co/static/uploads/.../frontal.jpg"
},
{
"file_id": "184",
"filename": "ficha-tecnica.pdf",
"filepath": "USER_ID/files/uuid_ficha-tecnica.pdf",
"filetype": "application/pdf",
"image_url": "https://bulest.co/static/uploads/.../ficha-tecnica.pdf"
}
]
}
}
}
El orden forma parte del cambio
meta.attachments es la lista canónica. Al editarla, envía la lista completa en el orden final deseado; no dependas de los antiguos campos individuales de archivo o imagen. Producto y Visión IA (type: "product" y type: "image") solo aceptan imágenes; Multimedia (type: "file") admite los recursos soportados. Las plantillas de catálogo pueden conservar sus recursos remotos. Al leer un fragmento antiguo, Bulest añade esta lista canónica para que puedas manejar todos con el mismo formato.
6. Asignar un agente a un canal
Con instances.assign, la integración puede descubrir los canales de la cuenta y asociar uno de los agentes que tiene autorizados. La API entrega únicamente IDs y nombres operativos; no expone números, claves ni detalles internos del canal.
curl https://bulest.co/api/v1/external/instances \ -H "Authorization: Bearer ACCESS_TOKEN"
PUT /instances/INSTANCE_DB_ID/agent
{
"agent_id": "AGENT_ID"
}
Para retirar una asignación, envía { "agent_id": null }. Si la lista marca assignment_editable: false, el canal ya usa un agente fuera del alcance de esa credencial y no debe modificarse. La respuesta confirma el canal actualizado, el agente anterior y si la asignación cambió:
{
"success": true,
"instance": {
"id": "57",
"name": "Ventas principales",
"active": true,
"assigned_agent": { "id": "AGENT_ID", "name": "Ventas" }
},
"previous_agent": null,
"assignment_changed": true
}
7. Consultar el catálogo y crear fragmentos de producto
Usa GET /agents/AGENT_ID/catalog para consultar exclusivamente la tienda vinculada al agente. La ruta admite q, limit y cursor; no acepta un store_id elegido por el cliente.
curl "https://bulest.co/api/v1/external/agents/AGENT_ID/catalog?q=camiseta&limit=30" \ -H "Authorization: Bearer ACCESS_TOKEN"
Cada producto distingue claramente sus IDs y entrega una plantilla válida para el endpoint de fragmentos:
{
"product_id": "9123456789",
"shopify_product_gid": "gid://shopify/Product/9123456789",
"title": "Camiseta clásica",
"variants": [{
"variant_id": "4987654321",
"shopify_variant_gid": "gid://shopify/ProductVariant/4987654321",
"title": "Negra / M",
"price": "79.90",
"fragment_meta_patch": {
"variant_id": "4987654321",
"variant_title": "Negra / M"
}
}],
"fragment_template": {
"title": "Camiseta clásica",
"content": "Camiseta de algodón...",
"type": "product",
"active": true,
"meta": {
"store_id": "12",
"store_domain": "tienda.myshopify.com",
"product_id": "9123456789",
"product_title": "Camiseta clásica",
"attachments": [{
"file_id": null,
"filename": "camiseta-clasica.jpg",
"filepath": null,
"filetype": "image/jpeg",
"image_url": "https://cdn.shopify.com/..."
}],
"product_url": "https://tienda.myshopify.com/products/camiseta-clasica"
}
}
}
Para crear el fragmento, copia fragment_template en el campo fragment y añade la base_revision vigente. Si el fragmento debe representar una variante concreta, combina su fragment_meta_patch con fragment_template.meta.
Páginas públicas y área de clientes
Las cuentas de clientes finales pertenecen al negocio y son independientes de los usuarios de Bulest. Cada página mantiene su identidad separada por defecto; compartirla entre páginas es una opción explícita.
Consulta GET /api/v1/external/public-pages/schema o public_pages_api en la respuesta de capacidades. Allí encontrarás los campos, versiones, permisos y ejemplos actualizados. La especificación OpenAPI también incluye estas operaciones.
public_pages.readypublic_pages.write: listar, crear y configurar páginas, apariencia, publicación, tienda, calendarios y dominio.memberships.readymemberships.write: configuración de registro y acceso, clientes, planes, asignaciones, contenido privado, auditoría e identidad compartida.memberships.recovery: emitir enlaces privados de invitación y recuperación; invitar requiere tambiénmemberships.write. Estos permisos no se añaden automáticamente a las credenciales existentes; concédelos expresamente desde Integraciones.
Las escrituras requieren también la política direct_apply. Con draft_only o approval_required se conservan las lecturas autorizadas, pero no existe un flujo de borrador para estas operaciones.
Empieza por listar /public-pages. Para editar, consulta el recurso y envía data.version de ese mismo registro. Página, configuración, plan, cliente, contenido e identidad tienen versiones distintas. Un conflicto 409 exige consultar nuevamente.
PATCH /api/v1/external/public-pages/ID_PAGINA/memberships
{"data":{"version":0,"enabled":true,"registration_mode":"approval"}}
Los recursos están bajo /public-pages/ID_PAGINA/memberships: plans, members, content, identity, invitations y audit. Las creaciones de páginas, planes y contenido requieren un operation_id único, reutilizable solo para el mismo reintento. Para retirar planes o contenido usa active:false; los clientes se suspenden o revocan.
Conserva las asignaciones y reglas existentes al enviar una lista de membresías o las reglas de secciones: cada conjunto enviado sustituye al anterior. Cambiar páginas que comparten identidad exige confirm:true, permisos sobre todas las páginas afectadas y puede invalidar sesiones y accesos anteriores.
El registro y el inicio de sesión funcionan sin correo transaccional. Aprobar un cliente no verifica su correo ni enlaza automáticamente su historial del CRM. La recuperación manual genera un enlace privado de un solo uso; requiere memberships.recovery y confirm:true. Cada llamada emite un enlace nuevo: no reintentes automáticamente ni publiques ese enlace. La API no permite leer o establecer contraseñas ni iniciar sesión como el cliente.
8. Preparar cambios como borradores
Las operaciones sobre fragmentos nunca cambian por sí solas al agente activo. Construyen un borrador con el snapshot completo resultante. Esto permite probarlo y revisarlo antes de aplicarlo.
Crear un fragmento
{
"base_revision": "REVISION_SHA256",
"summary": "Añade la política de envíos nacionales",
"fragment": {
"title": "Envíos nacionales",
"type": "text",
"content": "Los envíos tardan entre 2 y 5 días hábiles.",
"active": true,
"meta": {}
}
}
Programar un fragmento por fecha
Para promociones, temporadas o días concretos, añade fechas opcionales al fragmento. Se aplica a todos los tipos y también puedes configurarlo desde Bulest Bot o el Entrenador.
{
"base_revision": "REVISION_SHA256",
"fragment": {
"activate_at": "2026-12-01T08:00:00-05:00",
"deactivate_at": "2026-12-26T00:00:00-05:00",
"schedule_timezone": "America/Bogota"
}
}
Usa fechas completas con zona horaria. Puedes definir solo el inicio o el fin; omitir una fecha conserva la anterior y enviar null la elimina. El fin debe ser posterior al inicio. Antes del inicio el fragmento queda fuera del conocimiento; al comenzar se activa aunque se haya creado desactivado, y al terminar se excluye sin borrarse. Las lecturas incluyen effective_active y schedule_status para consultar el estado que aplica al responder. Un cambio manual de activación elimina la fecha de inicio; activar manualmente también elimina un fin ya vencido.
Editar o eliminar un fragmento
| Método | Ruta | Cuerpo mínimo |
|---|---|---|
| PATCH | /agents/AGENT_ID/fragments/FRAGMENT_ID | base_revision y fragment parcial. |
| DELETE | /agents/AGENT_ID/fragments/FRAGMENT_ID | base_revision y resumen opcional. |
Snapshot completo
Para cambiar varios fragmentos o también la configuración pública del agente, usa POST /agents/AGENT_ID/drafts:
{
"base_revision": "REVISION_SHA256",
"summary": "Reorganiza el conocimiento comercial",
"agent": {
"description": "Asistente comercial de la tienda",
"delay": 2000
},
"fragments": [
{
"id": "FRAGMENT_ID_EXISTENTE",
"title": "Envíos nacionales",
"type": "text",
"content": "Los envíos tardan entre 2 y 5 días hábiles.",
"active": true,
"meta": {}
}
]
}
Cuando envíes un snapshot completo, conserva todos los fragmentos que no deseas eliminar. Bulest fija la cuenta, autoría y fechas; el cliente no debe suplantar esos campos.
9. Probar el borrador en el Chat de pruebas
El envío es asíncrono. La API responde 202 Accepted con un session_id y un message_id.
{
"agent_id": "AGENT_ID",
"draft_id": "DRAFT_ID",
"client_message_id": "scenario-shipping-001",
"message": {
"type": "text",
"content": "¿Cuánto tarda mi envío?"
}
}
Para continuar, envía el session_id. Bulest recuerda y revalida el mismo borrador; no permite cambiarlo dentro de esa conversación.
{
"session_id": "SESSION_ID",
"message": {
"type": "text",
"content": "¿Y para Medellín?"
}
}
Multimedia
Los tipos admitidos son image, audio, video y file. El mensaje puede llevar una leyenda y el archivo en base64:
{
"agent_id": "AGENT_ID",
"draft_id": "DRAFT_ID",
"message": {
"type": "image",
"caption": "¿Este producto está disponible?",
"filename": "producto.jpg",
"mime_type": "image/jpeg",
"base64": "/9j/4AAQSkZJRgABAQ..."
}
}
Consultar respuestas
GET /test-chat/sessions/SESSION_ID/messages?after=0
Usa el cursor devuelto como próximo valor de after. Continúa consultando mientras is_terminal sea falso; estados como waiting_for_tool indican que todavía llegarán resultados. Cada sesión aísla su memoria por integración, agente y session_id.
Las herramientas con posibles escrituras pueden añadir mensajes tool_activity cuando se ejecutan en modo de prueba. Son evidencia creada por Bulest —API alcanzada, datos seguros, validaciones y efectos omitidos— y no forman parte de conversation ni del texto del agente. simulated_success indica una simulación válida y simulated_rejected una petición recibida pero rechazada; cada evidencia resuelve una acción pendiente y el turno cierra cuando se resuelve la última.
{
"sender": "system",
"type": "tool_activity",
"visibility": "tester",
"tool_activity": {
"operation": "checkout.create",
"status": "simulated_success",
"title": "Checkout simulado",
"summary": "El checkout fue validado y no se creó un pedido real.",
"validated": ["Catálogo y precios vigentes"],
"suppressed_effects": ["Crear el pedido", "Modificar inventario"]
}
}
POST /test-chat/sessions/SESSION_ID/reset
client_message_id evita duplicados si debes reintentar un envío. Dentro de una sesión se procesa un turno a la vez; sesiones diferentes sí pueden ejecutarse en paralelo.
10. Aplicar o enviar a aprobación
Cuando el resultado sea correcto, llama:
POST /drafts/DRAFT_ID/apply
| Política | Comportamiento |
|---|---|
| draft_only | El borrador queda disponible para aplicación manual desde Perfil. |
| approval_required | Pasa a pendiente de aprobación humana en Bulest. |
| direct_apply | Se aplica inmediatamente si la revisión base sigue vigente. |
Las dos últimas políticas requieren el permiso fragments.apply. Un conflicto de revisión debe resolverse leyendo de nuevo al agente y reconstruyendo el borrador; nunca se fuerza la escritura.
11. Actividad y Caja Negra
Consulta la actividad atribuida exclusivamente a la integración:
GET /activity?limit=50
Bulest registra la preparación y aplicación de borradores, creación o archivado de agentes y ejecuciones del Chat de pruebas. La Caja Negra identifica a la integración por nombre, pero no guarda el token ni copia el contenido completo de fragmentos o conversaciones.
Referencia rápida de endpoints
| Método | Ruta | Permiso |
|---|---|---|
| GET | /guide | Token activo |
| POST | /files | files.upload |
| GET | /instances | instances.assign |
| PUT | /instances/INSTANCE_DB_ID/agent | instances.assign |
| GET | /agents | agents.read |
| POST | /agents | agents.lifecycle |
| DELETE | /agents/AGENT_ID | agents.lifecycle |
| GET | /agents/AGENT_ID/catalog | catalog.read |
| GET | /agents/AGENT_ID/configuration-context | configuration.read |
| GET | /agents/AGENT_ID/fragments | fragments.read |
| POST | /agents/AGENT_ID/fragments | fragments.draft |
| PATCH | /agents/AGENT_ID/fragments/FRAGMENT_ID | fragments.draft |
| POST | /agents/AGENT_ID/drafts | fragments.draft |
| GET | /drafts | fragments.read |
| POST | /drafts/DRAFT_ID/apply | fragments.apply |
| POST | /test-chat/messages | chat_test.run |
| GET | /test-chat/sessions/SESSION_ID/messages | chat_test.run |
| POST | /test-chat/sessions/SESSION_ID/reset | chat_test.run |
| GET | /activity | activity.read |
La referencia machine-readable está disponible en /docs/openapi.json.
Errores y reglas de seguridad
- 401: token ausente, inválido, vencido o revocado.
- 403: permiso, agente autorizado o política insuficiente.
- 409: conflicto de revisión, versión, sesión o estado del borrador.
- 410: borrador o sesión de prueba vencida.
- 429: demasiadas solicitudes; respeta el tiempo de espera antes de reintentar.
No reintentes automáticamente una mutación si no sabes si el servidor la alcanzó a procesar. Vuelve a consultar el recurso y decide con su estado actual.
Datos que nunca debes enviar
No envíes contraseñas de Bulest, credenciales de tiendas, claves internas del sistema, user_id, account_id ni tokens de otras integraciones.