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:

Base URL
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

  1. Abre Perfil → Integraciones externas.
  2. Selecciona Nueva integración y ponle un nombre reconocible, por ejemplo “Codex — conocimiento de ventas”.
  3. Elige los permisos y los agentes a los que podrá acceder.
  4. Define cómo manejará los cambios: solo borradores, aprobación humana o aplicación directa.
  5. 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

PermisoUso
agents.readLista y consulta agentes autorizados.
agents.lifecycleCrea y archiva agentes.
fragments.readConsulta fragmentos y la revisión vigente.
fragments.draftPrepara borradores de configuración o conocimiento.
fragments.applyEnvía a aprobación o aplica según la política configurada.
files.uploadSube un archivo propio de la cuenta para vincularlo a fragmentos.
instances.assignConsulta canales de la cuenta y asigna o retira agentes autorizados.
catalog.readConsulta productos, variantes e IDs de la tienda vinculada al agente.
configuration.readDiagnostica instancias, tienda, departamentos, capacidades, calendarios y dependencias antes de editar.
chat_test.runUsa el Chat de pruebas con la versión activa o un borrador.
activity.readConsulta 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
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
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.

Respuesta abreviada
{
  "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étodoRutaResultado
GET/agentsAgentes visibles para el token.
GET/agents/AGENT_IDConfiguración pública y revisión.
GET/agents/AGENT_ID/configuration-contextRelaciones, estado de dependencias y advertencias previas a la edición.
GET/agents/AGENT_ID/fragmentsSnapshot de fragmentos y revision.
Leer fragmentos
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.

Diagnóstico previo
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.

POST /files
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:

Respuesta de carga
{
  "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."
  }
}
Fragmento con recursos ordenados
{
  "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.

Consultar canales
curl https://bulest.co/api/v1/external/instances \
  -H "Authorization: Bearer ACCESS_TOKEN"
Asignar un agente
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ó:

Respuesta abreviada
{
  "success": true,
  "instance": {
    "id": "57",
    "name": "Ventas principales",
    "active": true,
    "assigned_agent": { "id": "AGENT_ID", "name": "Ventas" }
  },
  "previous_agent": null,
  "assignment_changed": true
}

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.read y public_pages.write: listar, crear y configurar páginas, apariencia, publicación, tienda, calendarios y dominio.
  • memberships.read y memberships.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én memberships.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

POST /agents/AGENT_ID/fragments
{
  "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.

Programación opcional
{
  "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étodoRutaCuerpo mínimo
PATCH/agents/AGENT_ID/fragments/FRAGMENT_IDbase_revision y fragment parcial.
DELETE/agents/AGENT_ID/fragments/FRAGMENT_IDbase_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:

JSON
{
  "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.

POST /test-chat/messages
{
  "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.

Continuació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:

Imagen
{
  "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

Polling
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.

Actividad simulada
{
  "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"]
  }
}
Reiniciar memoria
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:

Aplicación
POST /drafts/DRAFT_ID/apply
PolíticaComportamiento
draft_onlyEl borrador queda disponible para aplicación manual desde Perfil.
approval_requiredPasa a pendiente de aprobación humana en Bulest.
direct_applySe 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:

Actividad
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étodoRutaPermiso
GET/guideToken activo
POST/filesfiles.upload
GET/instancesinstances.assign
PUT/instances/INSTANCE_DB_ID/agentinstances.assign
GET/agentsagents.read
POST/agentsagents.lifecycle
DELETE/agents/AGENT_IDagents.lifecycle
GET/agents/AGENT_ID/catalogcatalog.read
GET/agents/AGENT_ID/configuration-contextconfiguration.read
GET/agents/AGENT_ID/fragmentsfragments.read
POST/agents/AGENT_ID/fragmentsfragments.draft
PATCH/agents/AGENT_ID/fragments/FRAGMENT_IDfragments.draft
POST/agents/AGENT_ID/draftsfragments.draft
GET/draftsfragments.read
POST/drafts/DRAFT_ID/applyfragments.apply
POST/test-chat/messageschat_test.run
GET/test-chat/sessions/SESSION_ID/messageschat_test.run
POST/test-chat/sessions/SESSION_ID/resetchat_test.run
GET/activityactivity.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.

Continuar con la referencia OpenAPIContrato machine-readable para herramientas y agentes.