Third-AI-Uniandes — Flujos HTTP para APIM

Documentación de cómo el CLI de AI Uniandes consume las APIs para integración con APIM.

Base URL: Sustituya https://{apim-host}/{api-suffix} por la URL de su APIM.

Servicios del CLI

Servicio

Uso

Scope OAuth2

Nota

UploadDocument

Upload, estado, eliminación

UploadDocument

Principal de ingesta

DocumentClassifier

DocumentGroups + batch

DocumentClassifier

Visibilidad restringida

ClientAssistant

Chat con asistentes

ClientAssistant

Preguntas RAG

OnBase

Navegación de archivos

OnBase

Requiere bearer

1. Autenticación OAuth2 client_credentials

Diagrama: 1. Autenticación OAuth2 client_credentials

POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token

Scopes por servicio

Servicio

Scope

UploadDocument

api://FA-<env>-AIUniandes-UploadDocument/.default

DocumentClassifier

api://FA-<env>-AIUniandes-DocumentClassifier/.default

ClientAssistant

api://FA-<env>-AIUniandes-ClientAssistant/.default

OnBase

api://FA-<env>-AIUniandes-OnBase/.default

Ejemplo de obtención de token

HTTP Request

POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id={client_id}
&client_secret={client_secret}
&scope=api://FA-QA-AIUniandes-UploadDocument/.default

Respuesta satisfactoria · 200 OK

{
    "token_type": "Bearer",
    "expires_in": "<segundos>",
    "ext_expires_in": "<segundos>",
    "access_token": "<token>"
}

Headers comunes

HTTP Headers

Accept: application/json
Authorization: Bearer {access_token}
Content-Type: application/json

2. Flujo de ingesta para asistentes RAG

Para agregar un archivo de contexto a un asistente existente, el consumidor ejecuta tres operaciones: subir el archivo, solicitar su procesamiento y consultar el estado. Conserve el file_id retornado por la carga y utilícelo como document_id al consultar el estado.

Alcance de este ejemplo: ingesta directa con UploadDocument. Requiere el ID del asistente de destino. Los valores de los ejemplos son ilustrativos; los campos y respuestas se contrastaron con el código de UploadDocument entregado. Las rutas y la autenticación externas de APIM siguen pendientes de contrastar con su configuración.

Diagrama: 2. Flujo de ingesta para asistentes RAG

1. Subir el archivo

POST /api/v1/documents/upload/assistant

Formato: multipart/form-data. Envíe un archivo por petición. Permita que cURL genere el header Content-Type con su boundary.

Campo

Tipo

Valor

Requerido

file

binario

Contenido del archivo; el ejemplo usa un PDF con MIME application/pdf

Sí

source

texto

CONTEXT_ASSISTANT

Sí

conversation_id

texto

ID de conversación, si aplica

No

cURL · carga

curl --request POST "{base_url}/api/v1/documents/upload/assistant" \
  --header "Authorization: Bearer {upload_token}" \
  --header "Accept: application/json" \
  --form "file=@./documento.pdf;type=application/pdf" \
  --form "source=CONTEXT_ASSISTANT"

Respuesta · 200 OK

{
  "file_name": "documento.pdf",
  "file_id": "2da40ce5-4c9f-4cce-a76d-7ff7304c4fd1",
  "status": "success"
}

success describe el resultado de la carga HTTP. El archivo queda registrado con estado UPLOADED; aún requiere solicitar su procesamiento. La asociación al asistente se realiza en el siguiente paso.

2. Solicitar el procesamiento

POST /api/v1/documents/process

Envíe JSON con los tres campos. id_application identifica el asistente al que se asociará el documento; type debe ser exactamente context_assistant. El documento debe estar en estado UPLOADED.

Campo

Tipo

Valor

Requerido

file_id

texto

ID del archivo retornado por la carga

Sí

id_application

texto

ID del asistente al que se asociará el documento

Sí

type

texto

context_assistant

Sí

cURL · procesamiento con JSON

curl --request POST "{base_url}/api/v1/documents/process" \
  --header "Authorization: Bearer {upload_token}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data '{
    "file_id": "2da40ce5-4c9f-4cce-a76d-7ff7304c4fd1",
    "id_application": "{assistant_id}",
    "type": "context_assistant"
  }'

Respuesta · 200 OK

{
  "file_id": "2da40ce5-4c9f-4cce-a76d-7ff7304c4fd1",
  "application_id": "{assistant_id}",
  "status": "processing_started"
}

Operación asíncrona: este endpoint devuelve 200 OK al iniciar el procesamiento. Esa respuesta todavía no indica que el archivo esté listo para las consultas RAG.

3. Consultar el estado

GET /api/v1/document/{document_id}/status

Sustituya document_id por el file_id recibido. Repita la consulta hasta alcanzar READY o un estado terminal de error/eliminación. Si vence el tiempo de espera del cliente, conserve el ID y consulte de nuevo; el vencimiento no demuestra que el procesamiento haya fallado.

Campo

Tipo

Valor

Requerido

document_id

texto · ruta

El file_id retornado por la carga; se incluye en la URL

Sí

cURL · estado

curl --request GET "{base_url}/api/v1/document/2da40ce5-4c9f-4cce-a76d-7ff7304c4fd1/status" \
  --header "Authorization: Bearer {upload_token}" \
  --header "Accept: application/json"

Ejemplo de respuesta · 200 OK

{
  "id": "2da40ce5-4c9f-4cce-a76d-7ff7304c4fd1",
  "filename": "documento.pdf",
  "status": "READY",
  "source": "CONTEXT_ASSISTANT",
  "blob_name": "container/documento.pdf",
  "application_id": "{assistant_id}",
  "id_conversation": null,
  "origin": "PORTAL_WEB",
  "error": false,
  "schedule_frequency": null
}

Cómo interpretar el estado

Estado

Significado para el consumidor

Acción

UPLOADED

Archivo recibido; no confirma disponibilidad RAG

Solicitar procesamiento si aún no se ha solicitado

PROCESSED y demás estados intermedios

El documento todavía figura en procesamiento

Continuar consultando

READY

Documento listo según el servicio

Finalizar el seguimiento con éxito

ERROR o INTERRUPTED

Procesamiento fallido o interrumpido

Detener el seguimiento y revisar el incidente con el ID del archivo

DELETED

Documento eliminado

Detener el seguimiento; no es una carga exitosa

El CLI entregado consulta cada 5 segundos y espera hasta 300 segundos por defecto para este flujo. Son ajustes del cliente, no un tiempo garantizado de procesamiento. Su implementación detiene el seguimiento también en PROCESSED; para confirmar disponibilidad, esta guía utiliza READY, coherente con los estados del backend.

3. Flujo de chat con asistentes

Diagrama: 3. Flujo de chat con asistentes

POST /api/v1/ai-assistant/chat/{assistant_id}

Modelos disponibles

Alias

model

model_label

gpt-5

GPT_5_CHAT_UNIANDES

Open AI gpt-5-chat

gpt-4.1

GPT_4_1_CHAT_UNIANDES

Open AI gpt-4.1-chat

gpt-4o

GPT_4o_CHAT_UNIANDES

Open AI gpt-4o-chat

deepseek

DEEPSEEK_R1_CHAT_UNIANDES

DeepSeek R1 chat

Payload completo

JSON Request

{
  "id": "{message_uuid}",
  "userName": "script-rag-chat",
  "roles": "ADMINISTRATIVE,STUDENT,TEACHER,ADMINISTRATOR-ASSISTANT,OWNER-ASSISTANT,USER-TD",
  "state": "INITIALIZED",
  "category": "",
  "question": "Cual es la politica de homologaciones?",
  "answer": "   ",
  "answerTyping": "   ",
  "answerRating": 0,
  "reasonRating": "",
  "refinedAnswer": "",
  "academicCategory": null,
  "keyWords": [],
  "links": [],
  "restrictionService": null,
  "idConversation": "{conversation_uuid}",
  "files": [],
  "model": "GPT_5_CHAT_UNIANDES",
  "model_label": "Open AI gpt-5-chat",
  "is_open": "NO"
}

Campos de respuesta

Campo

Tipo

Descripción

answer

string

Texto de respuesta

id

UUID

ID del mensaje

idConversation

UUID

Reutilizar para el hilo

keyWords

array

Palabras clave

links

array

Referencias citadas

4. Descarga de metadata desde OnBase

Diagrama: 4. Descarga de metadata desde OnBase

Listado por navegación

GET /api/v1/onbase/files?path={path}&page_size={n}

HTTP Request

GET /api/v1/onbase/files?path=Secretaria/Actas/&page_size=50
Authorization: Bearer {onbase_token}
Accept: application/json

Búsqueda paginada

GET /api/v1/onbase/files?search={texto}&page_size={n}&cursor={cursor}

Mapeo OnBase → Excel

Campo Excel

Origen

Transformación

source

—

Fijo: ONBASE

document_onbase_id

file_id

Directo

name

name

Directo

typology

document_type

Directo

category

path

Directo

visibility

visibility

CLASSIFIED → RESTRICTED

action

—

Fijo: NEW

5. Ingesta RAG Institutional simple

Para agregar un archivo local a un RAG institucional existente, conserve su application_id y el file_id devuelto por la carga. El consumidor sube el archivo, configura permisos si es restringido, solicita clasificación y consulta el avance hasta que el documento esté disponible. En las peticiones de este flujo, envíe application_id únicamente al solicitar la clasificación.

Caso

Permisos del documento

Secuencia

PUBLIC

Sin restricción adicional por DocumentGroup en este flujo

Carga → clasificación → estado del trabajo → estado del documento

RESTRICTED

Grupos y/o usuarios definidos en un DocumentGroup

Carga → DocumentGroup → clasificación → estado del trabajo → estado del documento

En los ejemplos, {upload_base_url} es la base de UploadDocument expuesta en APIM y {classifier_base_url} la de DocumentClassifier. Sustituya cada una por el host y sufijo configurados para ese servicio. Los tokens también corresponden al servicio de cada llamada.

La visibilidad del documento y la autenticación del servicio son conceptos distintos: PUBLIC no significa que la API permita peticiones anónimas.

Diagrama: 5. Ingesta RAG Institutional simple

1. Subir el archivo local

POST /api/v1/document/upload/institutional

Use multipart/form-data y envíe un archivo por petición. cURL genera automáticamente el Content-Type y su boundary. Para varios documentos, repita la carga y reúna los identificadores devueltos.

Campo

Tipo

Valor

Requerido

file

binario

Contenido del archivo; el ejemplo utiliza un PDF con MIME application/pdf

Sí

visibility

texto

PUBLIC o RESTRICTED. Por defecto: PUBLIC

No

cURL · carga pública

curl --request POST "{upload_base_url}/api/v1/document/upload/institutional" \
  --header "Authorization: Bearer {upload_token}" \
  --header "Accept: application/json" \
  --form "file=@./politica-institucional.pdf;type=application/pdf" \
  --form "visibility=PUBLIC"

Respuesta · 200 OK

{
  "file_name": "politica-institucional.pdf",
  "file_id": "7e121456-3ef6-48ce-847d-c01e91ce88af",
  "status": "success"
}

La respuesta confirma la carga. El documento queda en UPLOADED; success todavía no indica que pueda utilizarse en consultas RAG. El servicio asigna source=CONTEXT_INSTITUTIONAL cuando se omite la fuente, y registra origin=PORTAL_WEB para la carga local.

Para un documento restringido, cambie el formulario a visibility=RESTRICTED y complete el paso de permisos antes de clasificarlo. El campo visibility por sí solo no define quiénes pueden acceder.

2. Configurar permisos cuando el documento sea restringido

POST /api/v1/document-groups

Envíe JSON con los grupos y/o usuarios autorizados. En este caso de uso debe existir al menos un grupo o usuario permitido. Sustituya los nombres ilustrativos por identidades válidas de su organización. Para un documento público puede omitir este paso.

Campo

Tipo

Valor

Requerido

file_id

texto · UUID

ID del archivo retornado por la carga

Sí

allowed_groups

arreglo de objetos

Grupos autorizados: {"name_group": "Secretaria-General"}

Condicional: grupos y/o usuarios para restringir

allowed_users

arreglo de objetos

Usuarios autorizados: {"username": "[email protected]"}

Condicional: grupos y/o usuarios para restringir

cURL · crear DocumentGroup con JSON

curl --request POST "{classifier_base_url}/api/v1/document-groups" \
  --header "Authorization: Bearer {classifier_token}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data '{
  "file_id": "7e121456-3ef6-48ce-847d-c01e91ce88af",
  "allowed_groups": [
    {
      "name_group": "Secretaria-General"
    }
  ],
  "allowed_users": [
    {
      "username": "[email protected]"
    }
  ]
}'

Respuesta: 201 Created, con el DocumentGroup en data. El servicio configura la restricción del archivo a partir de las identidades indicadas. No envíe allowed_groups ni allowed_users como partes del formulario de carga.

Si el archivo ya tiene un DocumentGroup, volver a ejecutar el POST devuelve el existente y no modifica sus permisos. Utilice PUT /api/v1/document-groups/{file_id} para actualizarlos; el ejemplo se conserva al final de esta sección.

3. Solicitar clasificación

POST /api/v1/document-groups/classify/batch

La misma operación se utiliza para uno o varios archivos del RAG institucional. Incluya los archivos ya cargados y, para los restringidos, con sus permisos configurados.

Campo

Tipo

Valor

Requerido

file_ids

arreglo de textos

Identificadores retornados por la carga; un elemento para un solo archivo

Sí

application_id

texto

ID del RAG institucional de destino

Sí

cURL · clasificación con JSON

curl --request POST "{classifier_base_url}/api/v1/document-groups/classify/batch" \
  --header "Authorization: Bearer {classifier_token}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data '{
  "file_ids": [
    "7e121456-3ef6-48ce-847d-c01e91ce88af"
  ],
  "application_id": "{application_id}"
}'

Respuesta · 202 Accepted

{
  "data": {
    "job_id": "7bfa2132-9a41-45dd-a0bd-a6e3cd4fb8e2",
    "status_url": "/api/v1/document-groups/classify/status/7bfa2132-9a41-45dd-a0bd-a6e3cd4fb8e2"
  }
}

202 Accepted confirma que se inició el trabajo asíncrono. Conserve data.job_id. La ruta data.status_url es relativa al servicio DocumentClassifier; úsela con la base correspondiente de APIM.

El clasificador solicita el procesamiento institucional de los archivos nuevos que pasan sus validaciones. En esta secuencia, la continuación del consumidor es consultar el estado del trabajo.

4. Consultar el trabajo y revisar sus errores

GET /api/v1/document-groups/classify/status/{job_id}

Campo

Tipo

Valor

Requerido

job_id

texto · ruta

Identificador data.job_id recibido al solicitar clasificación

Sí

cURL · estado de clasificación

curl --request GET "{classifier_base_url}/api/v1/document-groups/classify/status/7bfa2132-9a41-45dd-a0bd-a6e3cd4fb8e2" \
  --header "Authorization: Bearer {classifier_token}" \
  --header "Accept: application/json"

Ejemplo de respuesta · 200 OK · un archivo sin errores

{
  "job_id": "7bfa2132-9a41-45dd-a0bd-a6e3cd4fb8e2",
  "status": "Completed",
  "created_at": "2026-09-17T14:00:00+00:00",
  "last_updated_at": "2026-09-17T14:00:10+00:00",
  "custom_status": {
    "job_id": "7bfa2132-9a41-45dd-a0bd-a6e3cd4fb8e2",
    "total_files": 1,
    "total_batches": 1,
    "batches_completed": 1,
    "validated_ok": 1,
    "validated_fail": 0,
    "classified_ok": 1,
    "classified_fail": 0,
    "classified_already_indexed": 0,
    "errors": [],
    "current_phase": "COMPLETED"
  },
  "output": null
}

Esta respuesta contiene status y custom_status directamente en la raíz del JSON. Revise custom_status para conocer el resultado por archivo; output puede ser null.

Dato

Qué indica

Acción

status=Running

Trabajo en curso

Continuar consultando

status=Completed

Terminó la orquestación de clasificación; puede incluir fallos por archivo

Revisar contadores y errors; seguir el estado de los archivos sin errores

status=Failed

Falló la orquestación

Detener el seguimiento del trabajo y revisar el incidente

custom_status.validated_fail, classified_fail y errors

Fallos de validación o clasificación; los errores identifican el file_id, la fase y el detalle

Resolver los fallos de esos archivos antes de considerarlos exitosos

Clasificación y disponibilidad: Completed no garantiza que el documento esté listo para consultas. Para los archivos sin errores, complete el siguiente paso hasta READY.

5. Confirmar disponibilidad del documento

GET /api/v1/document/{document_id}/status

Esta consulta corresponde a UploadDocument. Use el file_id recibido en la carga; el job_id identifica el trabajo de clasificación y no se utiliza en esta ruta.

Campo

Tipo

Valor

Requerido

document_id

texto · ruta

El file_id del documento que se desea consultar

Sí

cURL · estado del documento

curl --request GET "{upload_base_url}/api/v1/document/7e121456-3ef6-48ce-847d-c01e91ce88af/status" \
  --header "Authorization: Bearer {upload_token}" \
  --header "Accept: application/json"

Ejemplo de respuesta · 200 OK

{
  "id": "7e121456-3ef6-48ce-847d-c01e91ce88af",
  "filename": "politica-institucional.pdf",
  "status": "READY",
  "source": "CONTEXT_INSTITUTIONAL",
  "blob_name": "container/politica-institucional.pdf",
  "application_id": "{application_id}",
  "id_conversation": null,
  "origin": "PORTAL_WEB",
  "error": false,
  "schedule_frequency": null
}

Estado del documento

Significado

Acción

READY

Documento listo según el servicio

Finalizar con éxito para ese archivo

UPLOADED, PROCESSING, PROCESSED y otros estados intermedios

Disponibilidad todavía no confirmada

Seguir consultando; si permanece en UPLOADED, revisar el resultado del trabajo de clasificación

ERROR o INTERRUPTED

Procesamiento fallido o interrumpido

Detener el seguimiento y revisar el incidente con el ID del archivo

DELETED

Documento eliminado

Detener el seguimiento; no es una carga exitosa

Defina un intervalo y un tiempo máximo de espera en el cliente. Si este tiempo vence, conserve job_id y file_id para retomar las consultas; el vencimiento local no demuestra que el servicio haya cancelado el procesamiento.

Actualizar DocumentGroup

PUT /api/v1/document-groups/{file_id}

JSON Request

{
  "allowed_groups": [{ "name_group": "Secretaria-General" }],
  "allowed_users": [{ "username": "[email protected]" }]
}

Upload desde OnBase

POST /api/v1/documents/upload/onbase

JSON Request

{
  "file_id": "{document_onbase_id}",
  "source": "CONTEXT_INSTITUTIONAL"
}

6. Eliminación de archivo institucional

Diagrama: 6. Eliminación de archivo institucional

7. Recomendaciones APIM

Producto APIM

Endpoints

Ingesta asistentes

upload assistant, process, status, delete

Chat asistentes

/ai-assistant/chat/{id}

Ingesta institucional

upload institutional, upload onbase, document-groups, classify

Consulta OnBase

/onbase/files

8. Diferencias importantes

1. type en POST /documents/process = context_assistant (guión bajo)
2. Ingesta institucional usa DocumentClassifier batch, NO /document/process/institutional
3. OnBase requiere bearer token (no es anónimo)