Documentación técnicaAPI · 1.7.4
AGOS Agentic OS — Referencia de la API REST
Referencia completa de la API REST de AGOS Agentic OS para equipos que implementan e integran la plataforma.
En este artículo
- Conceptos básicos
- URL base
- Explorador interactivo (Swagger)
- Autenticación
- Obtener un token
- Reglas del token
- Sesión del navegador (panel)
- Permisos y roles
- Catálogo de permisos
- Roles base
- Cómo se evalúan los permisos
- Convenciones de la API
- Límites de uso y protección
- Catálogo de endpoints
- 1. Autenticación (/api/auth)
- 2. Chat (/api/chat)
- 3. Agentes
- 4. Conocimiento: documentos y FAQs
- 5. Enrutadores
- 6. Widgets web (administración)
- 7. Widgets públicos (/api/public/widgets)
- 8. Licencias de uso de widgets
- 9. Conectores de fuentes
- 10. Servidores MCP (herramientas)
- 11. Memoria compartida
- 12. Skills compartidas
- 13. Modelos de IA
- 14. Voz y dictado
- 15. Usuarios
- 16. Roles y permisos
- 17. Límites por plan
- 18. Identidad visual (branding)
- 19. Seguridad: guardrails y plantillas de respuesta
- 20. Licencia de la instalación
- 21. Métricas, auditoría e índices
- 22. Salud del servicio
- Guías de integración
- Integrar un ERP o un portal con el chat (backend a backend)
- Incrustar el widget en un sitio web o en el ERP
- Construir su propio frontend de chat
- Sincronizar documentos desde otro sistema
- Consultar datos en tiempo real (precios, existencias)
- Códigos de estado y errores
- Preguntas frecuentes
- Documentos relacionados
Esta guía documenta todos los endpoints de la API de AGOS Agentic OS: autenticación, permisos, formatos, límites, errores y ejemplos de uso. Está dirigida a los equipos que implementan AGOS en un cliente y a los integradores que conectan AGOS con un ERP, un portal web u otro sistema.
Nota: Versión de la API: v1 (AGOS 1.7.3 o superior). La especificación OpenAPI 3.0 completa, legible por máquina, está en api/agos-openapi.json. Puede importarse en Postman, Insomnia, Azure API Management o cualquier generador de clientes OpenAPI.
Conceptos básicos
| Concepto | Descripción |
|---|---|
| Agente | Asistente especializado en un dominio (por ejemplo, “Medicamentos” o “Talento humano”). Tiene instrucciones, identidad, memoria, skills, su propio índice de conocimiento y, opcionalmente, herramientas MCP y un modelo propio. Se identifica por id (entero) y key (clave técnica en minúsculas, por ejemplo soporte-app). |
| Conocimiento | Documentos PDF, guiones de video (.md/.txt) y FAQs indexados para un agente. El agente responde solo con esa información. |
| Enrutador | Grupo aislado de agentes. Decide qué agente responde según las palabras de enrutamiento; si ninguno coincide, responde el agente de respaldo. |
| Widget | Chat embebible en cualquier sitio web. Puede publicarse para un agente o para un enrutador. Se identifica por un publicationId público. |
| Licencia de uso | Clave asignada a cada usuario externo (por ejemplo, un cliente del ERP) para usar un widget, con plan, cupo mensual y vencimiento opcional. |
| Plan | Free, Standard o Premium. Define cuotas, tamaño máximo de mensaje, longitud de respuesta y prioridad en la cola. |
| Licencia de la instalación | Token firmado por SAV Informática que habilita la instalación de AGOS. Sin licencia vigente, el chat y los widgets responden 402. |
URL base
La API se publica en el mismo origen que el panel de administración, bajo el prefijo /api:
http(s)://<servidor-agos>/api/...
En una instalación estándar el panel escucha en el puerto 3000 (http://<servidor-agos>:3000) y su proxy reenvía /api/ al orquestador. El puerto interno del orquestador (8080) no se publica fuera del servidor.
Explorador interactivo (Swagger)
La documentación interactiva está en:
http(s)://<servidor-agos>/api/docs
- Solo la pueden abrir usuarios con el rol Administrador que hayan iniciado sesión en el panel desde el mismo navegador. Sin sesión responde
401; con otro rol,403. - Los endpoints con candado exigen autenticación. Cada uno documenta en su respuesta
403el permiso que necesita (desde AGOS 1.7.4). - Try it out funciona con la sesión del panel. Para probar como lo haría un sistema externo, use el botón Authorize y pegue un token obtenido con
POST /api/auth/login. - La especificación JSON está en
/api/docs/v1/swagger.json, con la misma restricción de acceso.
Autenticación
AGOS usa JWT (JSON Web Tokens) firmados por el servidor. Hay dos formas de enviarlos:
| Cliente | Mecanismo | Cuándo usarlo |
|---|---|---|
| Sistemas e integraciones (ERP, backend, scripts) | Encabezado Authorization: Bearer <token> | Siempre que quien llama no sea un navegador con sesión del panel. |
| Panel de administración (navegador) | Cookie agos_session (HttpOnly, SameSite=Strict) + encabezado X-Agos-Csrf en POST/PUT/DELETE | Uso interno del panel. No se recomienda para integraciones. |
Los endpoints públicos del widget (/api/public/widgets/...) no usan JWT: se autorizan con el licenseId del usuario final (ver Widgets públicos).
Obtener un token
POST /api/auth/login
Content-Type: application/json
{
"email": "integracion@empresa.com",
"password": "********",
"useCookie": false
}
Respuesta 200 OK:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"plan": "Standard"
}
Use el token en cada llamada:
GET /api/admin/agents
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Reglas del token
| Regla | Detalle |
|---|---|
| Algoritmo | HS256, firmado con la clave secreta de la instalación. |
| Vigencia | 8 horas por defecto (configurable por el operador con Jwt__ExpirationHours). Al vencer, la API responde 401: vuelva a llamar a login. |
| Revocación inmediata | En cada petición el servidor comprueba que el usuario siga existiendo, no esté bloqueado y no haya cambiado su sello de seguridad. Cambiar la contraseña, bloquear al usuario o modificar sus roles invalida al instante todos sus tokens. |
| Contenido | Identificador del usuario, correo, plan, roles y todos los permisos (permission) de sus roles. Si cambian los permisos de un rol, el usuario debe volver a iniciar sesión para recibirlos. |
| Bloqueo por intentos | Las contraseñas incorrectas cuentan para el bloqueo temporal de la cuenta (ASP.NET Identity). |
| Límite de intentos | POST /api/auth/* admite 10 peticiones por minuto por dirección IP. |
Importante: Recomendación para integraciones: cree un usuario exclusivo para cada sistema integrado (por ejemplo,
erp-integracion@cliente.com) y asígnele un rol personalizado solo con los permisos que necesita (ver Roles y permisos). No use la cuenta de un administrador. Guarde la contraseña en un almacén de secretos y renueve el token antes de que venga.
Sesión del navegador (panel)
Con "useCookie": true el servidor no devuelve el token en el cuerpo: lo guarda en la cookie agos_session y responde el perfil de la sesión:
{
"plan": "Standard",
"session": {
"id": "6f1c...",
"email": "admin@empresa.com",
"roles": ["Administrador"],
"plan": "Standard",
"expiresAt": "2026-10-13T23:15:00+00:00"
}
}
Con la cookie, las peticiones POST, PUT y DELETE deben incluir el encabezado X-Agos-Csrf: 1; sin él se rechazan con 401. Si una petición trae Authorization, la cookie se ignora.
Permisos y roles
AGOS aplica mínimo privilegio: cada endpoint exige un permiso concreto. Los permisos se agrupan en roles y viajan dentro del token.
Catálogo de permisos
| Módulo | Permiso | Permite |
|---|---|---|
| Agentes | agents.read | Ver agentes y su configuración |
| Agentes | agents.write | Crear, editar y activar o desactivar agentes |
| Conocimiento | knowledge.read | Ver documentos, FAQs e índices |
| Conocimiento | knowledge.write | Subir y eliminar documentos y FAQs |
| Enrutadores | routers.read | Ver enrutadores |
| Enrutadores | routers.write | Crear, editar y publicar enrutadores y sus widgets |
| Conectores | connectors.read | Ver conectores |
| Conectores | connectors.write | Crear, editar y sincronizar conectores |
| Herramientas MCP | mcp.read | Ver servidores MCP |
| Herramientas MCP | mcp.write | Registrar, editar y probar servidores MCP |
| Memoria | memory.read | Ver perfiles de memoria compartidos |
| Memoria | memory.write | Crear y editar perfiles de memoria |
| Skills | skills.read | Ver skills compartidas |
| Skills | skills.write | Crear y editar skills compartidas |
| Modelos | models.read | Ver proveedores, modelos y configuración de voz |
| Modelos | models.write | Configurar proveedores, modelos y voz |
| Planes | planlimits.read | Ver límites por plan y licencias de uso de widgets |
| Planes | planlimits.write | Editar límites por plan y licencias de uso de widgets |
| Identidad | branding.read | Ver la configuración de marca |
| Identidad | branding.write | Editar logo, nombre y favicon |
| Usuarios | users.read | Ver cuentas de usuario |
| Usuarios | users.write | Crear, bloquear y eliminar cuentas, y restablecer claves |
| Roles y permisos | roles.read | Ver roles y asignaciones |
| Roles y permisos | roles.write | Crear roles personalizados y asignar o revocar roles |
| Auditoría | audit.read | Ver el registro de auditoría de seguridad |
| Métricas | metrics.read | Ver métricas y exportar el historial de conversaciones |
| Licencia | license.read | Ver el estado de la licencia de la instalación |
| Licencia | license.write | Cargar o quitar el token de licencia |
| Guardrails | guardrails.read | Ver las reglas de seguridad globales |
| Guardrails | guardrails.write | Editar las reglas de seguridad globales |
| Plantilla de respuesta | prompttemplate.read | Ver las plantillas de respuesta (RAG y agéntica) |
| Plantilla de respuesta | prompttemplate.write | Editar las plantillas de respuesta |
Roles base
| Rol | Permisos |
|---|---|
| Administrador | Todos. |
| Contribuidor | Lectura y escritura en Agentes, Conocimiento, Enrutadores, Conectores, Herramientas MCP, Memoria, Skills y Modelos, más metrics.read. Sin acceso a usuarios, roles, planes, marca, auditoría, licencia ni guardrails. |
| Lector | Todos los permisos .read. |
Los roles base se resincronizan con el catálogo en cada arranque y no se pueden editar ni eliminar. Para otras combinaciones, cree roles personalizados.
Cómo se evalúan los permisos
- Algunos controladores exigen un permiso a nivel de clase y otro en la acción. Se exigen ambos. Por ejemplo,
POST /api/admin/connectors/{id}/syncrequiereconnectors.readyconnectors.write. En el catálogo de endpoints aparecen todos los permisos requeridos. - Los endpoints marcados como Sesión solo exigen un token válido, sin permiso específico (por ejemplo, el chat).
- Sin token o con token inválido la respuesta es
401; con token válido pero sin el permiso,403.
Convenciones de la API
| Tema | Convención |
|---|---|
| Formato | JSON UTF-8 (Content-Type: application/json), salvo cargas de archivos (multipart/form-data), audio (audio/wav), PDF y CSV. |
| Nombres de campos | camelCase. Mayúsculas y minúsculas no importan al enviar. |
| Enumeraciones | Se envían y reciben como texto: "Free", "OpenAi", "OAuth2ClientCredentials". |
| Fechas | ISO 8601 en UTC, por ejemplo 2026-10-13T15:30:00Z. Los campos de solo fecha usan yyyy-MM-dd. |
| Identificadores | Agentes, enrutadores, servidores MCP, proveedores, perfiles, skills y licencias de uso usan id entero. Usuarios y roles usan cadenas (GUID). Documentos y conectores usan GUID sin guiones. |
Claves técnicas (key) | Si no se envían, se generan a partir del nombre: minúsculas, sin tildes y con guiones (Canal Clínico → canal-clinico). Mínimo 2 caracteres y únicas por tipo. |
| Paginación | ?page=1&size=50 (página desde 1). Respuesta: { "total", "page", "size", "items": [] }. |
| Errores | Vea Códigos de estado y errores. |
Límites de uso y protección
| Control | Alcance | Límite | Respuesta |
|---|---|---|---|
| Intentos de autenticación | /api/auth/* | 10 peticiones/minuto por IP | 429 |
| Ráfagas de chat | POST /api/chat, POST /api/chat/stream | 20 peticiones/minuto por usuario (configurable por el operador con RateLimiting__ChatPerMinute) | 429 con Retry-After: 60 |
| Cuota diaria | POST /api/chat, POST /api/chat/stream | dailyMessages del plan del usuario | 429 con Retry-After: 86400 |
| Tamaño del mensaje | Chat y widget | maxInputChars del plan; el exceso se recorta, no se rechaza | — |
| Longitud de la respuesta | Chat y widget | maxOutputTokens del plan (0 = sin límite) | — |
| Espera en cola | Chat y widget | queueTimeoutSeconds del plan | 503 |
| Widget público | /api/public/widgets/* (chat, transcripción, voz) | 20 peticiones/minuto por IP | 429 |
| Cupo mensual del widget | POST /api/public/widgets/{id}/chat | monthlyInputTokenLimit del plan de la licencia de uso | 429 |
| Audio autenticado | POST /api/audio/transcribe, POST /api/audio/speak | 10 peticiones/minuto por usuario | 429 |
| Licencia de la instalación | /api/chat, /api/public, /api/audio | Licencia Valid, ExpiringSoon o GracePeriod | 402 |
| Tamaño de archivos | Documentos: 50 MB · Audio: 15 MB · Imágenes de chat: 5 MB · Recursos de marca: 5 MB · Avatar del widget: 100 KB | — | 400 / 413 |
Todas las respuestas incluyen cabeceras de seguridad OWASP: X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, Content-Security-Policy y, con HTTPS, Strict-Transport-Security.
Catálogo de endpoints
Leyenda de la columna Permiso: Público = sin autenticación · Sesión = token válido, sin permiso específico · x.read, x.write = se exigen todos los permisos listados.
1. Autenticación (/api/auth)
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
POST | /api/auth/login | Público | Inicia sesión. Body: { email, password, useCookie }. Devuelve { token, plan }, o con useCookie: true la cookie y { plan, session }. Credenciales inválidas: 401. |
POST | /api/auth/logout | Público | Borra la cookie de sesión del navegador. 204. Los tokens Bearer no se invalidan: caducan solos o al cambiar el sello de seguridad del usuario. |
POST | /api/auth/register | Público | Autorregistro con plan Free. Deshabilitado por defecto (404); el operador lo activa con Auth__AllowSelfRegistration=true. |
2. Chat (/api/chat)
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
POST | /api/chat | Sesión | Envía una pregunta y espera la respuesta completa. |
POST | /api/chat/stream | Sesión | Igual, pero devuelve la respuesta en fragmentos por Server-Sent Events. |
GET | /api/chat/queue | Sesión | Peticiones en cola: { "length": 3 }. |
POST | /api/chat/{id}/feedback | Sesión | Califica una respuesta propia. id = messageId. Body { "score": 1 } (útil) o { "score": -1 } (no útil). |
Petición (POST /api/chat y /api/chat/stream):
{
"message": "¿Cómo registro una devolución de mercancía?",
"agentKey": "soporte-app",
"imageBase64": null,
"history": [
{ "role": "user", "text": "Hola" },
{ "role": "assistant", "text": "Hola, ¿en qué te ayudo?" }
]
}
| Campo | Obligatorio | Descripción |
|---|---|---|
message | Sí | Pregunta del usuario. Si supera maxInputChars del plan, se recorta. |
agentKey | No | Envía la pregunta directamente a ese agente. Si se omite, decide el enrutador por defecto o, si no hay ninguno, la clasificación global por palabras clave. Una clave inexistente responde 400. |
imageBase64 | No | Imagen PNG, JPEG o WebP de hasta 5 MB, en base64 puro o como data URL (data:image/png;base64,...). El modelo de visión de la instalación la describe y esa descripción se suma a la pregunta. |
history | No | Conversación previa para dar contexto a preguntas de seguimiento. Roles user o assistant. Se usan los últimos 6 turnos, de hasta 1.500 caracteres cada uno. Un seguimiento sin palabras clave se queda con el agente que venía respondiendo. |
Respuesta 200 OK (POST /api/chat):
{
"text": "Para registrar una devolución...\n\n**Fuente:** Manual de devoluciones, pág. 4",
"personality": "soporte-app",
"tokensUsed": 412,
"elapsedMs": 2310.5,
"messageId": 98231,
"sources": [
{
"fileName": "Manual-Devoluciones.pdf",
"page": 4,
"score": 0.83,
"title": "Manual de devoluciones",
"videoUrl": null,
"videoId": null,
"startSeconds": null
}
]
}
textviene en Markdown (puede incluir tablas, listas y diagramas Mermaid).personalityes la clave del agente que respondió.- En
sources, los camposvideoUrl,videoIdystartSecondssolo vienen cuando la fuente es un guion de video; permiten abrir el video en el minuto citado.
Streaming (POST /api/chat/stream). La respuesta es text/event-stream:
data: {"event":"queue_position","length":0}
data: Para registrar
data: una devolución...
data: [DONE]
- El primer evento indica la posición en la cola.
- Cada evento siguiente trae un fragmento de texto plano que se concatena al anterior.
data: [DONE]cierra la respuesta.
El streaming no devuelve messageId ni sources. Si los necesita, use POST /api/chat.
Errores del chat: 400 (imagen inválida o agente inexistente), 401, 402 (licencia de la instalación), 429 (ráfaga o cuota diaria), 503 (cola llena):
{ "error": "Cuota diaria agotada", "plan": "Free", "retryAfter": "Mañana a las 00:00 UTC" }
{ "error": "Servidor ocupado. Intente nuevamente.", "queueTimeout": 90 }
Nota: Las respuestas de agentes sin herramientas MCP se guardan en caché 30 minutos para preguntas idénticas con el mismo contexto. Editar la persona del agente invalida la caché automáticamente.
3. Agentes
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/agents | agents.read | Lista los agentes con toda su configuración. |
POST | /api/admin/agents | agents.write | Crea un agente. |
PUT | /api/admin/agents/{id} | agents.write | Edita nombre, descripción, palabras de enrutamiento, instrucciones, identidad, memoria y skills propias. |
PUT | /api/admin/agents/{id}/model | agents.write | Asigna un modelo propio al agente. |
PUT | /api/admin/agents/{id}/active | agents.write | Activa o desactiva el agente. Body { "active": false }. El agente de respaldo global no se puede desactivar (400). |
Agente (elemento de GET /api/admin/agents):
{
"id": 12,
"key": "soporte-app",
"name": "Soporte de la aplicación",
"description": "Resuelve dudas de uso del ERP",
"keywords": "factura|inventario|devolución",
"systemPrompt": "Responde SOLO con la información de los manuales...",
"elasticIndex": "idx-soporte-app",
"isActive": true,
"isFallback": false,
"priority": 10,
"isPublished": true,
"publicationId": "3f9c0b7e4d1a4c40a2b1f0c6a9e7d512",
"textModel": null,
"modelProviderId": null,
"identity": "Eres Alicia, asistente virtual de...",
"memory": "- Horario de soporte: 8:00 a 18:00",
"skillsJson": "[{\"name\":\"Guía paso a paso\",\"description\":\"...\",\"content\":\"...\"}]"
}
Crear (POST):
{
"name": "Soporte de la aplicación",
"key": "soporte-app",
"description": "Resuelve dudas de uso del ERP",
"keywords": "factura, inventario, devolución",
"systemPrompt": "Responde SOLO con la información de los manuales indexados.",
"priority": 10
}
Editar (PUT /api/admin/agents/{id}):
{
"name": "Soporte de la aplicación",
"description": "Resuelve dudas de uso del ERP",
"keywords": "factura|inventario|devolución",
"systemPrompt": "## Reglas\n1. Responde solo con los documentos...",
"identity": "Eres **Alicia**, asistente virtual de ...",
"memory": "- Horario de atención: lunes a sábado 7:00-21:00",
"skillsJson": "[{\"name\":\"Consulta de medicamento\",\"description\":\"Formato de respuesta\",\"content\":\"[Saludo]. El [medicamento]...\"}]"
}
| Campo | Reglas |
|---|---|
name | Obligatorio. El panel lo limita a 120 caracteres. |
description | Obligatoria al crear. El panel la limita a 500 caracteres. |
keywords | Palabras o frases separadas por , o |. Se normalizan a minúsculas, sin duplicados, y se guardan separadas por |. El enrutador elige el agente si el mensaje contiene alguna. Con varias coincidencias gana la mayor priority. |
systemPrompt | Obligatorio. Instrucciones del agente en Markdown; el panel las limita a 4.000 caracteres. |
identity / memory | Markdown libre. La identidad se antepone a las instrucciones; la memoria son datos fijos que el agente recuerda siempre. |
skillsJson | Arreglo JSON de { name, description, content }, hasta 8.000 caracteres en total. |
priority | Desempate entre agentes cuando varios coinciden. Más alto = preferido. |
Cómo se compone la persona: en cada respuesta, AGOS arma el mensaje de sistema con las secciones # Identidad → # Instrucciones (el systemPrompt) → # Memoria (perfiles heredados más la memoria propia) → # Habilidades (skills compartidas más las propias). Luego aplica las reglas de seguridad y la plantilla de respuesta.
Modelo propio (PUT /api/admin/agents/{id}/model):
{ "providerId": 3, "textModel": null }
Use providerId para un proveedor externo registrado (Modelos de IA) o textModel para un modelo local de Ollama. Enviar ambos en null vuelve al modelo global. Respuesta: { id, key, name, textModel, modelProviderId }.
4. Conocimiento: documentos y FAQs
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
POST | /api/admin/agents/{id}/documents | knowledge.write | Sube un documento para indexar (asíncrono). |
GET | /api/admin/agents/{id}/documents | knowledge.read | Trabajos de indexación del agente y su estado. |
GET | /api/admin/agents/{id}/knowledge | knowledge.read | Contenido indexado del agente: documentos, FAQs, fragmentos y páginas. |
GET | /api/admin/agents/{id}/documents/{jobId}/file | knowledge.read | Descarga el PDF original (application/pdf, se muestra en el navegador). |
DELETE | /api/admin/agents/{id}/documents/{jobId} | knowledge.write | Elimina el documento del índice y del almacenamiento. |
POST | /api/admin/agents/{id}/faqs | knowledge.write | Crea una pregunta frecuente indexada. |
DELETE | /api/admin/agents/{id}/faqs/{faqId} | knowledge.write | Elimina una FAQ (faqId empieza por faq-). |
Subir un documento (multipart/form-data):
| Campo | Obligatorio | Descripción |
|---|---|---|
file | Sí | .pdf, .md o .txt, no vacío, hasta 50 MB. Los PDF escaneados se procesan con OCR. |
title | Sí | Nombre visible de la fuente; el agente lo cita en sus respuestas. |
source | Sí | Área, norma o proveedor de origen. |
tags | No | Etiquetas separadas por coma. |
metadataJson | No | Objeto JSON con metadata adicional. Por defecto {}. |
curl -X POST "https://agos.empresa.com/api/admin/agents/12/documents" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@Manual-Devoluciones.pdf" \
-F "title=Manual de devoluciones" \
-F "source=Operaciones" \
-F "tags=devoluciones,2026" \
-F 'metadataJson={"version":"3.1","actualizado":"2026-10-01"}'
Respuesta 202 Accepted. El indexador procesa el archivo en segundo plano:
{
"jobId": "a1b2c3d4e5f60718293a4b5c6d7e8f90",
"agentId": 12,
"agentKey": "soporte-app",
"elasticIndex": "idx-soporte-app",
"fileName": "Manual-Devoluciones.pdf",
"storedFileName": "a1b2c3d4e5f60718293a4b5c6d7e8f90.pdf",
"title": "Manual de devoluciones",
"source": "Operaciones",
"tags": ["devoluciones", "2026"],
"metadataJson": "{\"version\":\"3.1\",\"actualizado\":\"2026-10-01\"}",
"uploadedAt": "2026-10-13T15:30:00Z",
"status": "Pending",
"error": null,
"chunks": 0
}
Estados del trabajo: Pending → Processing → Indexed (con chunks > 0) o Failed (con error). Consulte GET .../documents para seguir el avance. Un documento fallido no se reintenta: elimínelo y vuelva a subirlo.
Guiones de video (.md/.txt). Encabezado opcional y marcas de tiempo:
---
video_url: https://www.youtube.com/watch?v=XXXXXXXXXXX
title: Cómo registrar una devolución
---
[00:00] Introducción al módulo de devoluciones...
[01:30] Para crear la devolución, abra el menú...
Las respuestas que citan el guion devuelven videoId y startSeconds para abrir el video en el minuto exacto. Las marcas admiten [mm:ss], [h:mm:ss] y (min 2:10).
Crear una FAQ:
{
"question": "¿Cuál es el horario de soporte?",
"answer": "De lunes a viernes de 8:00 a 18:00.",
"tags": ["soporte"],
"metadata": { "area": "mesa de ayuda" }
}
Respuesta 201 con { id: "faq-...", question, answer, tags, metadata }.
Conocimiento indexado (GET .../knowledge): { agentId, index, healthy, documents: [...] }. Cada documento trae jobId, title, sourceFile, source, tags, metadata, chunks, pages, preview, hasFile (si el original está disponible para descargar) e indexedChunks (chunkId, page, text).
5. Enrutadores
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/routers | routers.read | Lista los enrutadores. |
POST | /api/admin/routers | routers.read, routers.write | Crea un enrutador. |
PUT | /api/admin/routers/{id} | routers.read, routers.write | Edita un enrutador. |
DELETE | /api/admin/routers/{id} | routers.read, routers.write | Elimina un enrutador. 204. |
POST | /api/admin/routers/{id}/test | routers.read, routers.write | Simula qué agente respondería un mensaje, sin guardar nada. |
{
"name": "Canal clientes",
"key": "canal-clientes",
"description": "Atención a clientes de la droguería",
"isActive": true,
"isDefault": false,
"fallbackAgentId": 5,
"allowedAgentIds": [5, 12, 14]
}
Algoritmo de enrutamiento:
- Si la petición trae
agentKey, responde ese agente. - Se elige el enrutador: el indicado (widget de enrutador) o el marcado
isDefault. - Dentro de
allowedAgentIds, gana el primer agente cuyas palabras clave aparezcan en el mensaje (mayorpriorityprimero). Si el mensaje no coincide, se prueban los dos mensajes anteriores del usuario, para mantener el hilo. - Si nadie coincide, responde
fallbackAgentId; si no está definido, el agente de respaldo global. - Si no existe ningún enrutador, la clasificación se hace entre todos los agentes activos.
Solo puede haber un enrutador isDefault. Respuesta de test: { "agentKey": "soporte-app", "agentName": "Soporte de la aplicación", "isFallback": false }.
6. Widgets web (administración)
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/agents/{agentId}/widget | agents.read | Configuración del widget del agente. |
PUT | /api/admin/agents/{agentId}/widget | agents.read, agents.write | Publica o despublica el widget y guarda su apariencia. |
POST | /api/admin/agents/{agentId}/widget/rotate | agents.read, agents.write | Genera un publicationId nuevo; el enlace anterior deja de funcionar. |
GET | /api/admin/routers/{routerId}/widget | routers.read | Igual, para el widget de un enrutador. |
PUT | /api/admin/routers/{routerId}/widget | routers.read, routers.write | Igual, para un enrutador. |
POST | /api/admin/routers/{routerId}/widget/rotate | routers.read, routers.write | Igual, para un enrutador. |
Petición PUT:
{
"isPublished": true,
"settings": {
"title": "Alicia",
"subtitle": "Asistente de la droguería",
"welcomeMessage": "Hola, soy Alicia. ¿En qué puedo ayudarte?",
"placeholder": "Escribe tu pregunta...",
"avatarUrl": null,
"fontFamily": "manrope",
"primaryColor": "#0B6E75",
"accentColor": "#F2B84B",
"backgroundColor": "#F7FBFA",
"textColor": "#17313A",
"position": "bottom-right",
"shape": "soft",
"animation": "rise",
"width": 400,
"height": 680,
"voice": "ef_dora",
"customCredit": false,
"creditName": null,
"privacyUrl": null
}
}
| Campo | Valores permitidos |
|---|---|
title / placeholder | Obligatorios, hasta 80 caracteres. |
subtitle | Hasta 120 caracteres. |
welcomeMessage | Obligatorio, hasta 300 caracteres. |
fontFamily | manrope, space-grotesk, playfair, nunito. |
| Colores | Hexadecimal #RRGGBB. |
position | bottom-right, bottom-left, inline. |
shape | soft, rounded, sharp. |
animation | rise, fade, scale, none. |
width × height | 320–560 × 480–900 px. |
avatarUrl | URL HTTP(S) o data URI PNG/JPEG/WebP de hasta 100 KB. |
voice | Identificador de voz instalada (ver Voz y dictado). |
customCredit, creditName, privacyUrl | Pie de página propio del cliente. Requiere que la licencia de la instalación incluya widget_white_label; si no, 403. |
Respuesta: { publicationId, isPublished, settings, canCustomizeCredit }.
7. Widgets públicos (/api/public/widgets)
Estos endpoints los usa el widget embebido. No requieren JWT: se autorizan con la licencia de uso (licenseId) del usuario final. Solo funcionan si el agente o enrutador está publicado y activo; si no, 404.
| Método | Ruta | Autorización | Descripción |
|---|---|---|---|
GET | /api/public/widgets/{publicationId} | Público | Nombre y apariencia del widget: { agentName, settings, audioEnabled }. |
POST | /api/public/widgets/{publicationId}/validate-license | licenseId | Valida una licencia antes de abrir el chat: { "valid": true }. |
POST | /api/public/widgets/{publicationId}/chat | licenseId | Envía un mensaje. |
POST | /api/public/widgets/{publicationId}/transcribe | licenseId | Convierte audio en texto (dictado). |
POST | /api/public/widgets/{publicationId}/speak | licenseId | Convierte texto en voz (audio/wav). |
Chat del widget:
{
"message": "¿Tienen protector solar para niños?",
"licenseId": "cliente004218",
"history": [],
"voice": false
}
{
"text": "Sí, contamos con protectores solares...",
"inputTokensUsed": 12,
"outputTokensUsed": 180,
"inputTokensRemaining": 999788,
"monthlyInputTokenLimit": 1000000,
"videos": []
}
- Con
voice: true, el asistente responde breve y sin formato, pensado para leerse en voz alta. inputTokensRemainingesnullcuando el plan no tiene cupo mensual (monthlyInputTokenLimit = 0).- Por privacidad, el widget público solo devuelve citas de video; los nombres de documentos internos no se exponen.
Errores de licencia (401):
{ "error": "La licencia no está activa o no es válida." }
{ "error": "La licencia venció el 2026-12-31. Solicita su renovación a tu organización.", "expired": true }
Cupo agotado (429):
{
"error": "Se agotó el cupo mensual de tokens de entrada de esta licencia.",
"inputTokensRemaining": 0,
"monthlyInputTokenLimit": 1000000
}
Transcribir (multipart/form-data): audioFile (tipo audio/*, hasta 15 MB) y licenseId. Responde el texto reconocido. Voz: body { "text": "...", "voice": "ef_dora", "licenseId": "..." }, responde audio/wav. Ambos devuelven 404 si el audio no está habilitado en la instalación y 503 si el servicio de voz no está listo.
8. Licencias de uso de widgets
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/widget-licenses | planlimits.read | Lista las licencias de uso con su consumo del mes. |
GET | /api/admin/widget-licenses/{id} | planlimits.read | Detalle de una licencia. |
GET | /api/admin/widget-licenses/{id}/usage?days=30 | planlimits.read | Consumo diario: { license, daily: [{ date, inputTokens, outputTokens, messages, voiceMessages }] }. |
POST | /api/admin/widget-licenses | planlimits.read, planlimits.write | Crea una licencia de uso. |
PUT | /api/admin/widget-licenses/{id} | planlimits.read, planlimits.write | Cambia nombre, plan, estado o vencimiento. |
POST | /api/admin/widget-licenses/{id}/rotate | planlimits.read, planlimits.write | Genera una clave nueva; la anterior deja de funcionar. |
Crear:
{
"externalUserId": "CLIENTE-004218",
"licenseId": "cliente004218",
"displayName": "Droguería Centro",
"plan": "Standard",
"expiresAt": "2026-12-31T23:59:59Z"
}
| Campo | Reglas |
|---|---|
externalUserId | Identificador del usuario en el ERP. Único (409 si se repite). |
licenseId | Clave que el usuario final envía al widget, hasta 160 caracteres. Única (409). |
plan | Free, Standard o Premium. Define el cupo mensual y la prioridad. |
expiresAt | Opcional, fecha futura en UTC. null = no vence. |
isActive | Solo en PUT. false revoca la licencia al instante. |
Respuesta: { id, licenseId, externalUserId, displayName, plan, isActive, expiresAt, isExpired, monthlyInputTokenLimit, inputTokensUsed, outputTokensUsed, messageCount, createdAt, lastUsedAt }. El consumo se reinicia el día 1 de cada mes (UTC).
9. Conectores de fuentes
Los conectores importan PDF desde repositorios corporativos al conocimiento de un agente.
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/connectors | connectors.read | Lista los conectores (nunca devuelve credenciales). |
POST | /api/admin/connectors | connectors.read, connectors.write | Crea un conector. |
PUT | /api/admin/connectors/{id} | connectors.read, connectors.write | Edita un conector. Enviar credentials vacías conserva las guardadas. |
GET | /api/admin/connectors/{id}/preview | connectors.read | Lista lo que hay en el origen sin importar nada: [{ name, sizeBytes, lastModified, isSupported }]. |
POST | /api/admin/connectors/{id}/sync | connectors.read, connectors.write | Importa los PDF nuevos o modificados: { connector, imported }. |
{
"agentId": 12,
"name": "Manuales en SharePoint",
"type": "SharePoint",
"container": "b!AbC123...",
"endpoint": "",
"settings": { "folderId": "01ABCDEF..." },
"credentials": { "tenantId": "...", "clientId": "...", "clientSecret": "..." }
}
type | container | endpoint | settings | credentials |
|---|---|---|---|---|
BlobStorage | Contenedor | — | prefix | connectionString (si se omite, usa el almacenamiento de la instalación) |
AmazonS3 | Bucket | URL de servicio compatible con S3 (opcional) | region (por defecto us-east-1), prefix, forcePathStyle | accessKeyId, secretAccessKey, sessionToken (opcional) |
GoogleDrive | ID de carpeta | — | folderId | serviceAccountJson (compartir la carpeta con la cuenta de servicio) |
Dropbox | Ruta de carpeta | — | — | accessToken |
OneDrive / SharePoint | ID de la unidad (drive) | — | driveId, folderId (por defecto root) | tenantId, clientId, clientSecret (aplicación de Entra ID con permiso de lectura de archivos) |
WebSitemap | — | URL del sitemap XML | — | — |
Ftp | Carpeta | Host (ftp://host:21) | useSsl, recursive (por defecto true) | username, password |
- Las credenciales se cifran en el servidor y nunca se devuelven.
- La sincronización compara la versión de cada archivo (ETag, revisión o fecha), así que solo importa archivos nuevos o modificados.
- Cada archivo importado crea un trabajo de indexación igual que una carga manual.
- La sincronización se ejecuta a demanda: para hacerla periódica, programe un llamado a
POST .../syncdesde su orquestador de tareas.
Más detalle en Conectores externos.
10. Servidores MCP (herramientas)
Los servidores Model Context Protocol dan a los agentes herramientas para consultar sistemas en tiempo real, como inventario, precios o pedidos.
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/mcp-servers | mcp.read | Lista los servidores (sin secretos). |
POST | /api/admin/mcp-servers | mcp.read, mcp.write | Registra un servidor. |
PUT | /api/admin/mcp-servers/{id} | mcp.read, mcp.write | Edita un servidor. secret vacío conserva el guardado. |
DELETE | /api/admin/mcp-servers/{id} | mcp.read, mcp.write | Elimina un servidor. 204. |
PUT | /api/admin/mcp-servers/{id}/active | mcp.read, mcp.write | Activa o desactiva: { "active": true }. |
POST | /api/admin/mcp-servers/{id}/test | mcp.read, mcp.write | Conecta y lista herramientas: { success, error, tools: [{ name, description }] }. |
GET | /api/admin/mcp-servers/agents/{agentId} | mcp.read | Servidores asignados al agente: { "serverIds": [1, 4] }. |
PUT | /api/admin/mcp-servers/agents/{agentId} | mcp.read, agents.write | Reemplaza la asignación: { "serverIds": [1, 4] }. |
{
"name": "Inventario ERP",
"key": "inventario-erp",
"description": "Existencias y precios en tiempo real",
"transportType": "Http",
"url": "https://erp.empresa.com/mcp",
"authType": "OAuth2ClientCredentials",
"authHeaderName": null,
"oAuthTokenUrl": "https://login.empresa.com/oauth2/token",
"oAuthClientId": "agos",
"oAuthScope": "inventory.read",
"headers": { "X-Tenant": "centro" },
"secret": "<client-secret>"
}
| Campo | Valores |
|---|---|
transportType | Http (Streamable HTTP) o Sse (transporte heredado). |
authType | None, ApiKey (envía secret en authHeaderName, por defecto Authorization) u OAuth2ClientCredentials (obtiene y renueva el token automáticamente). |
secret | API key o client secret. Se cifra y nunca se devuelve. |
Un agente con servidores MCP asignados usa el modo agéntico: el modelo decide qué herramientas llamar, AGOS las ejecuta y redacta la respuesta con los resultados. Estas respuestas no se guardan en caché. Para usar el modo agéntico, el modelo del agente debe admitir llamadas a herramientas.
11. Memoria compartida
Perfiles de memoria reutilizables (contexto corporativo, horarios, políticas) que varios agentes heredan.
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/memory-profiles | memory.read | Lista los perfiles. |
POST | /api/admin/memory-profiles | memory.read, memory.write | Crea un perfil: { name, key, description, content } (content en Markdown). |
PUT | /api/admin/memory-profiles/{id} | memory.read, memory.write | Edita un perfil. |
DELETE | /api/admin/memory-profiles/{id} | memory.read, memory.write | Elimina un perfil. |
GET | /api/admin/memory-profiles/agents/{agentId} | memory.read | Perfiles heredados por el agente. |
PUT | /api/admin/memory-profiles/agents/{agentId} | memory.read, agents.write | Reemplaza los perfiles del agente: { "profileIds": [1, 2] }. |
12. Skills compartidas
Habilidades reutilizables (procedimientos, formatos de respuesta, escalamientos) que varios agentes usan.
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/skills | skills.read | Lista las skills. |
POST | /api/admin/skills | skills.read, skills.write | Crea una skill: { name, key, description, content }. |
PUT | /api/admin/skills/{id} | skills.read, skills.write | Edita una skill. |
DELETE | /api/admin/skills/{id} | skills.read, skills.write | Elimina una skill. |
GET | /api/admin/skills/agents/{agentId} | skills.read | Skills compartidas del agente. |
PUT | /api/admin/skills/agents/{agentId} | skills.read, agents.write | Reemplaza las skills del agente: { "skillIds": [3] }. |
Las skills propias de un agente se guardan en skillsJson del agente (ver Agentes).
13. Modelos de IA
Proveedores externos (OpenAI, Azure AI Foundry, Anthropic, Ollama remoto):
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/model-providers | models.read | Lista los proveedores. Indica hasApiKey, nunca la clave. |
POST | /api/admin/model-providers | models.read, models.write | Registra un proveedor. |
PUT | /api/admin/model-providers/{id} | models.read, models.write | Edita un proveedor. apiKey vacío conserva la guardada. |
DELETE | /api/admin/model-providers/{id} | models.read, models.write | Elimina un proveedor. |
PUT | /api/admin/model-providers/{id}/active | models.read, models.write | Lo convierte en el modelo global de generación: { "active": true }. |
POST | /api/admin/model-providers/{id}/test | models.read, models.write | Prueba la conexión: { success, sample } o { success: false, error }. |
{
"name": "Azure OpenAI producción",
"type": "AzureFoundry",
"baseUrl": "https://mi-recurso.openai.azure.com",
"model": "mi-despliegue",
"apiVersion": "2024-10-21",
"apiKey": "<clave>"
}
type: Ollama, OpenAi (o compatible con OpenAI), AzureFoundry, Anthropic. apiKey es obligatoria al crear, salvo para Ollama. Los embeddings (búsqueda semántica) siempre se calculan con el modelo local de la instalación.
Modelos locales (Ollama de la instalación):
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/models | models.read | Modelos instalados y modelo activo. |
PUT | /api/admin/models/active | models.read, models.write | Cambia el modelo local activo: { "model": "qwen2.5:7b" }. |
POST | /api/admin/models/pull | models.read, models.write | Descarga un modelo en segundo plano: { "model": "qwen2.5:7b" }. |
GET | /api/admin/models/pull-status | models.read | Progreso de las descargas en curso. |
14. Voz y dictado
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/audio/status | Sesión | { enabled, ready, sttModel, ttsModel }. |
POST | /api/audio/transcribe | Sesión | Dictado: multipart/form-data con audioFile (audio/*, hasta 15 MB). |
POST | /api/audio/speak | Sesión | Texto a voz: { "text": "...", "voice": "ef_dora" } → audio/wav. |
GET | /api/audio/voices | Sesión | Voces disponibles e instaladas. |
GET | /api/audio/config | models.read | Configuración: modelo de dictado, dispositivo (CPU/GPU) y voz por defecto. |
PUT | /api/audio/config | models.write | Cambia la configuración: { sttModel, sttDevice, defaultVoice }. |
POST | /api/audio/voices/{voiceId}/install | models.write | Descarga una voz adicional. |
DELETE | /api/audio/voices/{voiceId} | models.write | Elimina una voz descargada. |
Identificadores de voz: voces incluidas (ef_dora, em_alex, em_santa) y voces descargables piper:<nombre>. Si la instalación no tiene audio habilitado, estos endpoints responden 404. Más detalle en Voz y dictado.
15. Usuarios
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/users?page=1&size=50&search= | users.read | Lista paginada. Cada elemento: { id, email, userName, plan, createdAt, isActive, roles, quotaUsedToday, dailyLimit }. |
POST | /api/admin/users | users.write | Crea un usuario: { email, password, plan, isAdmin }. |
DELETE | /api/admin/users/{id} | users.write | Elimina un usuario. No se puede eliminar al último Administrador. |
PUT | /api/admin/users/{id}/admin | users.write | Concede o quita el rol Administrador: { "isAdmin": true }. |
PUT | /api/admin/users/{id}/password | users.write | Restablece la contraseña: { "newPassword": "..." }. Invalida sus sesiones. |
PUT | /api/admin/users/{id}/plan | users.write | Cambia el plan: { "plan": "Premium" }. |
PUT | /api/admin/users/{id}/active | users.write | Bloquea o desbloquea: { "active": false }. Invalida sus sesiones al instante. |
GET | /api/admin/users/{id}/quota | users.read | Cuota diaria: { id, plan, remaining, limit, used }. |
16. Roles y permisos
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/roles/permissions | roles.read | Catálogo de permisos agrupado por módulo. |
GET | /api/admin/roles | roles.read | Roles con sus permisos e indicador isSystem. |
POST | /api/admin/roles | roles.read, roles.write | Crea un rol personalizado: { "name": "Integración ERP", "claims": ["knowledge.read", "knowledge.write"] }. |
PUT | /api/admin/roles/{id} | roles.read, roles.write | Edita un rol personalizado. Los roles base no se editan. |
DELETE | /api/admin/roles/{id} | roles.read, roles.write | Elimina un rol personalizado sin usuarios asignados. |
GET | /api/admin/roles/assignments | roles.read | Asignaciones temporales vigentes. |
POST | /api/admin/roles/assign | roles.read, roles.write | Asigna un rol: { "userId": "...", "roleName": "Contribuidor", "expiresAt": "2026-10-20T00:00:00Z" }. Con expiresAt el rol se retira solo al vencer (acceso temporal). |
POST | /api/admin/roles/revoke | roles.read, roles.write | Revoca un rol: { "userId": "...", "roleName": "Contribuidor" }. No permite dejar la instalación sin Administradores ni que un administrador se quite su propio rol. |
17. Límites por plan
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/plan-limits | planlimits.read | Límites de los tres planes. |
GET | /api/admin/plan-limits/{plan} | planlimits.read | Límites de un plan (Free, Standard, Premium). |
PUT | /api/admin/plan-limits/{plan} | planlimits.read, planlimits.write | Edita los límites. |
{
"dailyMessages": 100,
"maxInputChars": 8000,
"monthlyInputTokenLimit": 1000000,
"maxOutputTokens": 1000,
"queueTimeoutSeconds": 30,
"queuePriority": 1
}
| Campo | Significado | Valores iniciales (Free / Standard / Premium) |
|---|---|---|
dailyMessages | Mensajes por usuario por día (chat autenticado). | 20 / 100 / 500 |
maxInputChars | Longitud máxima del mensaje; el exceso se recorta. | 2.000 / 8.000 / 16.384 |
maxOutputTokens | Longitud máxima de la respuesta. 0 = sin límite. | 300 / 1.000 / 2.048 |
queueTimeoutSeconds | Espera máxima en cola antes de responder 503. | 90 / 30 / 10 |
queuePriority | Prioridad en la cola: menor = antes. | 2 / 1 / 0 |
monthlyInputTokenLimit | Cupo mensual de tokens de entrada por licencia de uso de widget. 0 = sin límite. | Lo configura cada instalación |
18. Identidad visual (branding)
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/branding | Público | { productName, clientName, logoUrl, faviconUrl } (lo usa la pantalla de inicio de sesión). |
GET | /api/branding/assets/{fileName} | Público | Sirve un logo o favicon cargado. |
POST | /api/admin/branding/assets | branding.write | Carga una imagen (file: PNG, JPG, WebP o ICO, hasta 5 MB). Respuesta { "url": "/api/branding/assets/..." }. |
PUT | /api/admin/branding | branding.write | Actualiza { productName (≤120), clientName (≤160), logoUrl, faviconUrl }. |
19. Seguridad: guardrails y plantillas de respuesta
Configuración global que se aplica a todos los agentes. Todos responden { "text": "<vigente>", "defaultText": "<de fábrica>" }.
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/security/guardrails | guardrails.read | Reglas de seguridad (antiinyección, confidencialidad). |
PUT | /api/admin/security/guardrails | guardrails.write | Edita las reglas: { "text": "..." } (hasta 8.000 caracteres, no vacío). |
POST | /api/admin/security/guardrails/reset | guardrails.write | Restaura las reglas de fábrica. |
GET | /api/admin/security/prompt-template | prompttemplate.read | Plantilla RAG (respuestas con documentos). |
PUT | /api/admin/security/prompt-template | prompttemplate.write | Edita la plantilla. Debe contener {{system_prompt}}, {{context}} y {{message}}. |
POST | /api/admin/security/prompt-template/reset | prompttemplate.write | Restaura la plantilla de fábrica. |
GET | /api/admin/security/agentic-prompt-template | prompttemplate.read | Plantilla del modo agéntico (MCP). |
PUT | /api/admin/security/agentic-prompt-template | prompttemplate.write | Edita la plantilla. Debe contener {{system_prompt}} y {{context}}. |
POST | /api/admin/security/agentic-prompt-template/reset | prompttemplate.write | Restaura la plantilla de fábrica. |
Marcadores: {{system_prompt}} = persona completa del agente · {{context}} = fragmentos recuperados de los documentos · {{message}} = pregunta del usuario con el contexto de la conversación.
20. Licencia de la instalación
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/license | license.read | Estado de la licencia. |
POST | /api/admin/license | license.read, license.write | Aplica un token de licencia: { "token": "eyJ..." }. Token inválido: 400 { error }. |
DELETE | /api/admin/license | license.read, license.write | Quita la licencia. 204. |
{
"status": "Valid",
"productCode": "sav-agos",
"tenantId": "cliente-001",
"tenantName": "Empresa Cliente S.A.S.",
"licenseId": "LIC-2026-0001",
"seats": 50,
"maxAgents": 20,
"features": ["widget_white_label"],
"issuedAt": "2026-01-01T00:00:00Z",
"expiresAt": "2027-01-01T00:00:00Z",
"lastValidatedAt": "2026-10-13T15:00:00Z"
}
status | Servicio | Significado |
|---|---|---|
NotConfigured | Bloqueado | No hay licencia cargada. |
Valid | Activo | Licencia vigente. |
ExpiringSoon | Activo | Vence pronto; renovar. |
GracePeriod | Activo | Venció hace poco; periodo de gracia. |
Expired | Bloqueado | Venció y terminó la gracia. |
Invalid | Bloqueado | Firma o datos inválidos. |
La licencia se valida sin conexión (firma RS256 con la clave pública de SAV Informática). La administración sigue disponible aunque el servicio esté bloqueado, para poder cargar una licencia nueva.
21. Métricas, auditoría e índices
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /api/admin/metrics?days=7&agentKey=&tzOffsetMinutes=-300 | metrics.read | Panel de métricas (days de 1 a 365; tzOffsetMinutes = desfase del huso horario del visor). |
GET | /api/admin/conversations/export?from=2026-10-01&to=2026-10-13 | metrics.read | Historial de conversaciones en CSV (UTF-8 con BOM, apto para Excel). Rango máximo de un año; por defecto, los últimos 30 días. |
GET | /api/admin/audit-log?page=1&size=50 | audit.read | Registro de auditoría de seguridad (bloqueos, cambios de rol, restablecimientos, eliminaciones), paginado. |
GET | /api/admin/indices | knowledge.read | Índices de conocimiento y su estado. |
Métricas: { range, summary, previous, daily, heatmap, latencyBuckets, agents, topQuestions, topLicenses, agentOptions }. summary incluye conversaciones, respuestas, usuarios, tokens, tiempos (promedio, p50, p95, p99), calificaciones y consumo del widget. previous es el periodo anterior equivalente, para comparar. Más detalle en Métricas y consumo.
Columnas del CSV: conversation_id, message_id, created_at_utc, user_email, agent, role, content, tokens, response_ms, feedback. Los valores se protegen contra inyección de fórmulas.
22. Salud del servicio
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
GET | /health | Público | { "status": "healthy", "timestamp": "..." }. Solo se expone dentro del servidor (sondeos de Docker o del balanceador), no a través del panel. |
Guías de integración
Integrar un ERP o un portal con el chat (backend a backend)
sequenceDiagram
participant ERP as ERP / Backend
participant AGOS as AGOS API
ERP->>AGOS: POST /api/auth/login {email, password}
AGOS-->>ERP: { token }
loop Cada pregunta
ERP->>AGOS: POST /api/chat (Bearer token) {message, agentKey, history}
AGOS-->>ERP: { text, sources, messageId }
end
ERP->>AGOS: POST /api/chat/{messageId}/feedback {score}
- Cree un usuario de integración con un plan acorde al volumen (la cuota diaria es por usuario).
- Inicie sesión y guarde el token. Renuévelo ante un
401, o antes de que se cumplan 8 horas. - Envíe
historycon los últimos turnos para que el agente entienda los seguimientos. - Muestre
textcomo Markdown.
TOKEN=$(curl -s -X POST https://agos.empresa.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"erp-integracion@empresa.com","password":"'"$AGOS_PASSWORD"'"}' | jq -r .token)
curl -s -X POST https://agos.empresa.com/api/chat \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"message":"¿Cómo anulo una factura?","agentKey":"soporte-app"}' | jq .
using System.Net.Http.Json;
var http = new HttpClient { BaseAddress = new Uri("https://agos.empresa.com") };
var login = await http.PostAsJsonAsync("/api/auth/login",
new { email = "erp-integracion@empresa.com", password = Environment.GetEnvironmentVariable("AGOS_PASSWORD") });
login.EnsureSuccessStatusCode();
var token = (await login.Content.ReadFromJsonAsync<LoginResponse>())!.Token;
http.DefaultRequestHeaders.Authorization = new("Bearer", token);
var reply = await http.PostAsJsonAsync("/api/chat", new { message = "¿Cómo anulo una factura?", agentKey = "soporte-app" });
var chat = await reply.Content.ReadFromJsonAsync<ChatResponse>();
Console.WriteLine(chat!.Text);
record LoginResponse(string Token, string Plan);
record ChatResponse(string Text, string Personality, int TokensUsed, double ElapsedMs, int MessageId);
Incrustar el widget en un sitio web o en el ERP
- Publique el widget del agente o del enrutador (
PUT .../widgetconisPublished: true) y copie elpublicationId. - Cree una licencia de uso por cada usuario final (
POST /api/admin/widget-licenses). - Inserte el iframe y pase la licencia del usuario en
license-id:
<iframe
src="https://agos.empresa.com/widget/3f9c0b7e4d1a4c40a2b1f0c6a9e7d512?license-id=cliente004218"
title="Asistente"
allow="microphone"
style="position:fixed;bottom:24px;right:24px;width:min(400px,calc(100vw - 32px));height:min(680px,calc(100vh - 32px));border:0;background:transparent;z-index:2147483000"
loading="lazy"></iframe>
- Sin
license-id, el widget pide la clave al usuario. allow="microphone"solo es necesario si se usa la voz, y el navegador exige que el sitio use HTTPS.- Para un widget dentro de la página (posición
inline), usewidth:100%y la altura configurada.
Más detalle en Licencias de uso en widgets.
Construir su propio frontend de chat
Use los endpoints públicos del widget desde su backend, o directamente desde el navegador si el frontend se sirve en el mismo dominio que AGOS (la API no habilita CORS):
const base = 'https://agos.empresa.com/api/public/widgets/3f9c0b7e4d1a4c40a2b1f0c6a9e7d512';
await fetch(`${base}/validate-license`, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ licenseId: 'cliente004218' })
});
const res = await fetch(`${base}/chat`, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: '¿Tienen domicilios?', licenseId: 'cliente004218', history: [] })
});
const { text, inputTokensRemaining } = await res.json();
Sincronizar documentos desde otro sistema
Para mantener el conocimiento de un agente al día desde un sistema externo:
- Cargue cada documento con
POST /api/admin/agents/{id}/documents. Guarde eljobIddevuelto junto con el identificador del documento en su sistema. - Cuando el documento cambie, elimine la versión anterior (
DELETE .../documents/{jobId}) y cargue la nueva. - Siga el avance con
GET .../documentshasta verIndexedoFailed.
Si los documentos están en SharePoint, OneDrive, Blob Storage, S3, Google Drive, Dropbox, FTP o un sitemap, use un conector y programe POST .../sync.
Rol mínimo recomendado para el usuario de integración: agents.read, knowledge.read y knowledge.write.
Consultar datos en tiempo real (precios, existencias)
No sincronice datos que cambian a cada minuto como documentos. Exponga esas consultas como un servidor MCP y asígnelo al agente (Servidores MCP). El agente las consultará en el momento de responder.
Códigos de estado y errores
| Código | Significado en AGOS |
|---|---|
200 OK | Operación correcta. |
201 Created | Recurso creado (agentes, FAQs, enrutadores, licencias de uso, MCP, proveedores, roles, conectores). |
202 Accepted | Documento recibido; se indexará en segundo plano. |
204 No Content | Eliminación o cierre de sesión correctos. |
400 Bad Request | Datos inválidos. Incluye el motivo. |
401 Unauthorized | Sin token, token vencido o revocado, falta X-Agos-Csrf con la cookie, o licencia de uso del widget inválida o vencida. |
402 Payment Required | La licencia de la instalación no está vigente (chat, widgets y audio). |
403 Forbidden | El usuario no tiene el permiso requerido, o la licencia no incluye la función (marca blanca). |
404 Not Found | El recurso no existe, el widget no está publicado, el audio no está habilitado o el autorregistro está desactivado. |
409 Conflict | Clave o identificador duplicado. |
413 Payload Too Large | El archivo supera el tamaño máximo. |
429 Too Many Requests | Límite de ráfaga, cuota diaria o cupo mensual agotado. Respete Retry-After cuando venga. |
503 Service Unavailable | Cola de inferencia llena, o servicio de voz o modelo no disponible. Reintente con espera exponencial. |
Formato de los errores. La mayoría de los errores devuelven JSON con el campo error:
{ "error": "Mensaje legible para el usuario." }
Algunos traen campos adicionales: licenseStatus (402), expired (401 del widget), plan y retryAfter (cuota diaria), queueTimeout (503), inputTokensRemaining (cupo del widget).
Excepciones:
- Algunas validaciones de administración devuelven el mensaje como texto plano (
"El título y la fuente son obligatorios."). - Los errores de ASP.NET Identity (contraseñas, roles) devuelven un arreglo de mensajes.
- Los errores de formato del JSON (tipo o campo inválido) siguen el estándar ProblemDetails (
application/problem+json) con el detalle enerrors.
Los clientes deben tratar los tres formatos.
Preguntas frecuentes
¿La API exige autenticación?
Sí. Todos los endpoints, salvo login, logout, register (deshabilitado por defecto), /api/branding y los del widget público, exigen un token válido y, en la mayoría de los casos, un permiso específico. Los del widget público exigen una licencia de uso válida.
¿Hay API keys para sistemas? Hoy las integraciones se autentican con un usuario dedicado y su token JWT (8 horas). Están previstas API keys de servicio con permisos acotados y revocables; consulte las notas de versión.
¿Por qué recibo 401 en un POST desde el navegador si ya inicié sesión?
Con la cookie del panel, los métodos que modifican datos exigen el encabezado X-Agos-Csrf. Las integraciones deben usar Authorization: Bearer.
¿Por qué el chat responde 402?
La licencia de la instalación no está vigente. Un administrador puede revisarla en GET /api/admin/license y cargar una nueva con POST /api/admin/license.
¿Puedo llamar a la API desde JavaScript en otro dominio? No directamente: la API no habilita CORS. Llámela desde su backend, o sirva su frontend en el mismo dominio que AGOS mediante un proxy inverso.
¿Cómo obtengo la especificación para generar un cliente?
Use api/agos-openapi.json, o descárguela de /api/docs/v1/swagger.json en su instalación con sesión de administrador.
Docs Contactar