Skip to content

Inferencias ​

Una inferencia es una llamada suelta y sin estado: entra un prompt, sale una respuesta. No recuerda nada entre llamadas. Es la herramienta para clasificar, extraer, resumir o generar JSON estructurado — si lo que quieres es conversar, ve a Agentes.

Se configura en el panel (prompt de sistema, modelo, RAGs vinculados) y se ejecuta desde tu backend con un token de acceso. También puede pedir, en vez del token, el JWT que tu aplicación firma para cada usuario: ver Con el JWT de tu usuario.

Listar las disponibles ​

bash
curl https://ur.tuempresa.com/api/inferences \
  -H "Authorization: Bearer $UR_TOKEN"
json
[
  {
    "name": "Clasificador de tickets",
    "identifier": "clasificador-tickets",
    "url": "https://ur.tuempresa.com/api/inferences/clasificador-tickets",
    "createdAt": "2026-03-01T09:00:00.000Z",
    "fileSources": [
      {
        "ragId": "6f1c...",
        "ragIdentifier": "ventas-docs",
        "ragName": "Documentación de ventas",
        "id": "9a22...",
        "name": "Drive de ventas",
        "identifier": "drive-ventas",
        "provider": "google_drive"
      }
    ],
    "attachments": {
      "supported": true,
      "image": { "mimeTypes": ["image/png", "image/jpeg", "image/webp", "image/gif"] },
      "pdf": { "mimeTypes": ["application/pdf"] },
      "maxCount": 5,
      "maxAttachmentBytes": 8388608,
      "maxTotalBytes": 20971520
    },
    "tools": [{ "name": "calculadora" }],
    "auth": { "mode": "access_token", "issuer": null }
  }
]

Devuelve solo las que tu token tiene permitidas. El campo fileSources te dice qué RAGs lleva vinculados cada una — eso determina si tienes que mandar semanticSearch. El campo attachments dice qué puede recibir el modelo de esa inferencia — ver Adjuntos. Y tools, los nombres de las tools que puede llamar el modelo: sin las de una plantilla que un administrador desactivó en el catálogo, y [] si no tiene ninguna. auth dice con qué se llama: con "mode": "jwt", tu token de acceso no la abre, y issuer dice qué JWT acepta (iss, aud y algoritmos).

Ejecutar una inferencia ​

bash
curl -X POST https://ur.tuempresa.com/api/inferences/clasificador-tickets \
  -H "Authorization: Bearer $UR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Clasifica este ticket: no me llega la factura de marzo",
    "semanticSearch": ["facturación", "envío de facturas"]
  }'

prompt y semanticSearch son cosas distintas ​

Este es el error más común

prompt es lo que se le manda al modelo. semanticSearch es lo que se busca en tus documentos. El prompt no interviene en la búsqueda.

Si la inferencia tiene RAGs vinculados y no mandas semanticSearch, la respuesta es 400. Y si no los tiene, mandarlo también suele ser 400: los campos de búsqueda solo se aceptan con el RAG nativo activo, y el panel no deja tener RAGs vinculados sin él ni activarlo sin ninguno. Mira fileSources en el listado para saber en cuál de los dos casos estás.

Puedes mandar hasta 10 queries. Cada una se busca por separado y los resultados se deduplican. Es útil cuando una sola formulación no cubre el tema: ["plazo de devolución", "política de reembolso"].

Ojo al multiplicar: topK se aplica a cada query y dentro de cada RAG vinculado, así que 10 queries con topK: 10 sobre dos RAGs dan hasta 200 fragmentos. Tras deduplicar, la respuesta se corta en 60 fragmentos —el tope global de la instalación— sin avisar en el cuerpo: no cuenta como degradación y no aparece en degraded.

Cuerpo ​

CampoTipoPor defectoDescripción
promptstring—Obligatorio. Lo que recibe el modelo, hasta 1.000.000 caracteres (400 si te pasas)
attachmentsarray—Imágenes o PDF para el modelo, máximo 5. Ver Adjuntos
semanticSearchstring[]—Queries de búsqueda, máximo 10. Obligatorio si hay RAGs vinculados
topKint 1–1005Fragmentos a recuperar por cada query y por cada RAG
useRerankingboolfalseReordena los resultados, si el RAG tiene reranker
candidateMultiplierint 2–102Candidatos antes de reordenar (topK × este valor)
similarityThresholdnumber 0–1—Descarta fragmentos por debajo de este parecido (similitud coseno). No aplica a los RAGs solo BM25; ver el score
searchModeauto · bm25 · semantic · hybridautoCómo buscar. auto: cada RAG usa lo que tiene. El resto es una orden: si algún RAG no puede cumplirla (semantic/hybrid en un RAG sin embeddings, o bm25/hybrid mientras su índice BM25 se construye), 422 nombrando esos RAGs, sin buscar nada
includeDuplicatesboolfalseIncluye fragmentos marcados como duplicados
jsonSchemastring—Fuerza la forma de la respuesta. Ver abajo
useAllFilesbooltrueA false, restringe a selectedFiles/selectedFolders
selectedFilesarray—Ficheros concretos por RAG
selectedFoldersarray—Carpetas por RAG; se expanden a sus ficheros
providerFilterarray—Filtro por metadatos del proveedor (etiquetas…)
includeSystemPromptboolfalseDevuelve el prompt base de la inferencia en la respuesta (sin el contexto RAG). Ver El prompt de sistema no es secreto

Los campos de RAG solo valen si la inferencia los usa

semanticSearch, similarityThreshold, searchMode, selectedFiles, selectedFolders y providerFilter solo se aceptan si la inferencia tiene activado el RAG nativo. Mandarlos si no, devuelve 400 — explícito, en vez de ignorarlos en silencio.

Adjuntos (imágenes y PDF) ​

Junto al prompt puedes mandar hasta 5 adjuntos, en base64:

json
{
  "prompt": "¿Qué importe total suma esta factura?",
  "attachments": [
    {
      "mimeType": "application/pdf",
      "data": "JVBERi0xLjQKJc...",
      "filename": "factura-marzo.pdf"
    }
  ]
}
CampoTipoDescripción
mimeTypestringObligatorio. Uno de image/png, image/jpeg, image/webp, image/gif o application/pdf
datastringObligatorio. El contenido en base64 estándar con padding — el que produce Buffer.toString('base64') o btoa
filenamestringOpcional y solo informativo: el tipo lo decide mimeType, no la extensión

Quita el prefijo data: que devuelve FileReader

FileReader.readAsDataURL da data:application/pdf;base64,JVBERi0…. En data va solo lo que hay después de la coma. Con el prefijo delante, el base64 no valida y la respuesta es 400.

Qué admite cada modelo ​

Quién decide si se puede adjuntar algo es el modelo configurado en la inferencia, no ur. No lo adivines: cada elemento de GET /api/inferences trae un bloque attachments con lo que acepta el suyo, y es lo que debes usar para montar la UI de subida — ocultar el botón si supported es false, y restringir el accept del input a los mimeTypes que salgan ahí.

Con supported: false (o con image y pdf a null) esa inferencia no acepta ningún adjunto. Un modelo de un proveedor propio (un servidor compatible con OpenAI dado de alta en el panel) admite imágenes solo si en el panel tiene activado «Admite imágenes», y nunca PDF.

Los límites de tamaño se miden sobre el contenido ya decodificado, no sobre la cadena base64: 8 MB por adjunto y 20 MB sumando todos los de la misma petición.

Errores ​

CódigoCuándo
400El mimeType no es uno de los cinco, el base64 está mal formado, hay más de 5 adjuntos, o el contenido no se corresponde con el mimeType declarado (se comprueban los bytes de cabecera del fichero)
413Un adjunto pasa de 8 MB decodificados, el total pasa de 20 MB, o el cuerpo entero de la petición es demasiado grande
422El modelo configurado no admite ese tipo de adjunto

El 422 llega antes de recuperar contexto y antes de llamar al proveedor: una petición que se va a rechazar por sus adjuntos no gasta ni una búsqueda RAG ni una llamada al modelo.

Con adjuntos no hay fallback ​

Si la inferencia tiene un modelo de fallback configurado, se omite en las llamadas que lleven attachments, y la respuesta trae fallbackSkipped: true. El motivo: el reintento aplana el mensaje a texto plano, así que el adjunto se perdería por el camino y el modelo de fallback respondería a media pregunta sin que nadie se entere.

La consecuencia práctica es que esa llamada concreta no tiene red de seguridad: si el modelo principal falla, recibes el 502 directamente. En un proceso desatendido que mande adjuntos, el reintento lo pones tú.

Acotar la búsqueda a parte de los documentos ​

Con useAllFiles: false, los tres campos de acotado se agrupan por RAG (el ragIdentifier sale del campo fileSources del listado):

json
{
  "prompt": "...",
  "semanticSearch": ["plazo de devolución"],
  "useAllFiles": false,
  "selectedFiles": [{ "ragIdentifier": "ventas-docs", "filePaths": ["documentos/informe.pdf"] }],
  "selectedFolders": [{ "ragIdentifier": "ventas-docs", "folderPaths": ["documentos/informes"] }],
  "providerFilter": [
    {
      "ragIdentifier": "ventas-docs",
      "filter": {
        "tags": {
          "entities": [{ "id": "abc", "name": "Confidencial" }],
          "scopeCombinator": "and"
        }
      }
    }
  ]
}

En filePaths van exactamente los valores filePath que devuelve Ficheros indexados —la ruta dentro de la fuente, también en Google Drive y SharePoint— y en folderPaths, un prefijo de esas rutas: el backend lo expande a todos sus ficheros indexados. scopeCombinator decide cómo se combina el filtro de metadatos con los ficheros seleccionados: and interseca, or une. En entities, lo que se compara es el name.

Respuesta estructurada ​

jsonSchema es un JSON Schema serializado como string, no un objeto:

json
{
  "prompt": "Clasifica este ticket: no me llega la factura de marzo",
  "jsonSchema": "{\"type\":\"object\",\"properties\":{\"categoria\":{\"type\":\"string\"}}}"
}

Con él, response es un objeto que sigue ese esquema. Sin él, es un array de bloques de contenido.

Un objeto a medias es un 502, nunca un 200

En el panel, la sección Modelo LLM de la inferencia tiene un Máximo de tokens de salida: lo más que puede generar el modelo en cada llamada (vacío = el valor por defecto del proveedor). Una respuesta que llega a él se corta. Sin jsonSchema eso es texto a medias. Con él, el JSON no se llega a cerrar, y la respuesta es un 502 en la primera llamada, sin reintentos, con un code que dice qué pasó:

json
{
  "error": "The model reached its output-token cap before finishing the structured response. …",
  "code": "output_truncated",
  "errorId": "…"
}
  • output_truncated: el modelo llegó al tope antes de cerrar el objeto. Sube el máximo de la inferencia (o déjalo vacío) o pide menos. Reintentar igual volverá a cortarse.
  • structured_output_missing: el modelo no devolvió ningún objeto (por ejemplo, contestó en prosa).

Un 502 sin code es que falló la llamada al modelo. Un 200 con jsonSchema trae un objeto completo, con una excepción: un modelo que no marca el motivo del corte al transmitir (OpenAI) y cuyo máximo ur no conoce, con el campo vacío. Con ese, pon un máximo.

Respuesta ​

json
{
  "response": { "categoria": "facturacion" },
  "inference": "clasificador-tickets",
  "params": { "prompt": "...", "topK": 5 },
  "items": [
    {
      "text": "<untrusted_document source=\"documentos/facturacion.pdf, lines 12-31\">\nLas facturas se envían el día 5 de cada mes...\n</untrusted_document>",
      "score": 0.82
    }
  ],
  "toolCalls": []
}
CampoDescripción
responseObjeto si usaste jsonSchema (no siempre si la respuesta llega al tope de tokens de salida: ver el aviso de Respuesta estructurada); array de bloques de contenido si no
inferenceEl identifier ejecutado
paramsLos parámetros que recibió, ya con los valores por defecto aplicados. Si mandaste attachments, aquí vuelve un resumen (count, mimeTypes, totalBytes), no el base64
itemsFragmentos usados como contexto, con su parecido (0–1). El text va envuelto en <untrusted_document> — ver abajo
toolCallsUna entrada por invocación de tool
systemPromptEl prompt base configurado en el panel, sin el contexto RAG ni el aviso de contenido no confiable que sí recibe el modelo. Solo si pediste includeSystemPrompt
fallbackSkippedSolo si la inferencia tiene fallback y se omitió por llevar adjuntos. Ver Con adjuntos no hay fallback
degradedSolo si algo se degradó. Ver abajo

Inferencias que devuelven una imagen ​

Si la inferencia tiene un modelo de imagen (en el panel, «Qué devuelve: Imagen»), la llamada es la misma y lo que vuelve en response es la imagen:

bash
curl -X POST https://<tu-dominio>/api/inferences/cambio-de-cara \
  -H "Authorization: Bearer $UR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Pon la cara de la segunda imagen en el personaje central de la primera.",
    "attachments": [
      { "mimeType": "image/jpeg", "data": "<base64 del personaje>", "filename": "personaje.jpg" },
      { "mimeType": "image/jpeg", "data": "<base64 de la cara>", "filename": "cara.jpg" }
    ]
  }'
json
{
  "response": [{ "type": "image", "mimeType": "image/png", "data": "<base64>" }],
  "inference": "cambio-de-cara",
  "params": { "attachments": { "count": 2, "mimeTypes": ["image/jpeg"], "totalBytes": 285000 } },
  "items": [],
  "toolCalls": []
}
  • Los adjuntos van al modelo en el orden en que los mandas. Por eso el prompt puede hablar de «la primera» y «la segunda». Se admiten PNG, JPEG y WebP; un PDF da 422.
  • Sin adjuntos, la genera desde cero. Con ellos, la edita.
  • El prompt del panel va delante del tuyo. Las APIs de imagen no tienen prompt de sistema.
  • Tamaño, proporción y calidad se configuran en el panel. Por defecto, la proporción es la de la primera imagen adjunta.
  • No hay jsonSchema, RAG ni tools. Mandar jsonSchema o un campo de búsqueda da 422 con code: "not_for_image_models".
  • Si el proveedor rechaza la imagen por su contenido, la respuesta es un 422 con code: "image_rejected" y, si lo dio, su motivo en reason (moderation_blocked, IMAGE_SAFETY…). No es un error del modelo: reintentar con lo mismo dará lo mismo.
  • Una imagen tarda bastante más que un texto, de unos segundos a más de un minuto. Si pasa del timeout de la inferencia, 502 con code: "timeout". Ten en cuenta también el timeout de tu cliente y de los proxies que haya por medio.

Para guardarla, decodifica data:

js
const { response } = await res.json();
const image = response.find((block) => block.type === 'image');
fs.writeFileSync('resultado.png', Buffer.from(image.data, 'base64'));

Degradación ​

La recuperación de documentos nunca lanza un error. Si el reranker está caído, la clave del proveedor agotada o se supera el tiempo máximo, se devuelve lo que se pudo recuperar y aparece el campo degraded.

Mira degraded antes de fiarte del resultado

Una respuesta con degraded es válida, pero se construyó con menos contexto del pedido. Si tu proceso depende de la calidad de la recuperación, compruébalo.

El detalle textual de cada degradación (message) solo aparece con sesión del panel. Con un token Bearer ves qué etapa falló y por qué (type y cause, abajo), pero no el texto del proveedor.

Cada entrada de degraded trae:

CampoQué dice
typeQué etapa falló: reranker; embeddings, el cálculo del vector de la query (o un modelo o una key de embeddings que ya no existen); vector_store, la búsqueda en el índice o el tiempo máximo agotado; o query_expansion, las búsquedas alternativas de una tool de búsqueda con estrategia multi_query, que entonces busca solo con la pregunta original
causerate_limit, auth, timeout, unavailable o config
severitysoft si el contexto llegó igualmente, aunque peor (sin reordenar, sin la parte literal de la búsqueda híbrida o con una sola query); hard si ese RAG o esa query no aportó nada
ragIdentifierEl RAG afectado, cuando la degradación es de uno concreto

Con el JWT de tu usuario ​

Un token de acceso es un secreto: va en tu servidor, y todo lo que llega con él es tuyo. Si quien llama a la inferencia es la aplicación de tus usuarios —un frontal, una app móvil—, no puedes darle tu token. En su lugar, la inferencia puede pedir el JWT que tu backend firma para cada usuario, el mismo que usan los agentes con usuarios identificados.

Se activa en el panel, en la inferencia → Acceso → JWT de tu app, eligiendo el emisor que firma los tokens. Desde que se guarda:

  • solo vale un JWT válido de ese emisor en Authorization: Bearer: con su aud, su iss si el emisor lo pide, exp y sin pasar de la vida máxima del emisor;
  • se ignoran todos los tokens de acceso, también los que tienen permiso sobre esta inferencia: reciben 401. El MCP tampoco puede ejecutarla (403);
  • el botón Probar del panel sigue funcionando, con la sesión de quien la administra;
  • el límite de peticiones por minuto cuenta por usuario (el sub del token), con el límite general de la API.

Afecta a las cuatro rutas de la inferencia (ejecutar, retrieve, files y el estado de un fichero). El listado GET /api/inferences sigue siendo con token de acceso: es para tu backend.

bash
curl -X POST https://ur.tuempresa.com/api/inferences/clasificador-tickets \
  -H "Authorization: Bearer $USER_JWT" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "Clasifica este ticket: no me llega la factura de marzo" }'

Cómo firmar ese token, en Firmar el token en tu backend. ur nunca lo firma: solo lo verifica.

Un emisor, todo lo que lo usa

Un token de un emisor abre todas las inferencias y todos los agentes que usan ese emisor. Si no quieres que el token que firmas para el chat abra también una inferencia, usa emisores distintos, con audiencias (aud) distintas.

Desde el navegador ​

/api no responde al CORS salvo en estas inferencias, y solo para las webs que pongas en Webs que pueden llamarla desde el navegador (una por línea, como https://app.tuempresa.com). Con la lista vacía, solo se puede llamar desde un servidor. Desde una web de la lista es la misma petición:

js
const res = await fetch('https://ur.tuempresa.com/api/inferences/clasificador-tickets', {
  method: 'POST',
  headers: { Authorization: `Bearer ${await getUserToken()}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ prompt: 'Clasifica este ticket: no me llega la factura de marzo' }),
});

getUserToken() es tuyo: le pide el token a tu backend con la sesión del usuario. Nunca se envían cookies (Access-Control-Allow-Credentials no sale), y el origen es una protección más, no la autenticación: un cliente que no es un navegador puede omitirlo.

Si no pasa ​

RespuestaQué pasa
401 {"error":"token_missing"}No vino Authorization: Bearer.
401 {"error":"token_invalid"}No vale: mala firma, otra audiencia, otro emisor… o un token de acceso de ur.
401 {"error":"token_expired"}Caducó: pide otro a tu backend y repite.
403La llamada viene de una web que no está en la lista, o del MCP.
429Ese usuario agotó su cupo por minuto, o hubo demasiados fallos desde esa IP. Espera los segundos de Retry-After.

Los 401 llevan WWW-Authenticate y nunca dicen el motivo exacto: para saberlo, pega el token en Probar un token, en el emisor.

Las tools de la inferencia no reciben al usuario: el JWT solo abre la puerta. Una tool que necesita usuario identificado sigue sin poder engancharse a una inferencia.

Solo recuperar contexto, sin LLM ​

Si únicamente quieres los fragmentos relevantes, sin gastar una llamada al modelo:

bash
curl -X POST https://ur.tuempresa.com/api/inferences/clasificador-tickets/retrieve \
  -H "Authorization: Bearer $UR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"semanticSearch": ["plazo de devolución"], "topK": 10}'

Acepta el mismo cuerpo que ejecutar, menos prompt y jsonSchema, y devuelve:

json
{
  "systemPrompt": "...",
  "chunks": [
    {
      "text": "<untrusted_document source=\"documentos/facturacion.pdf, lines 12-31\">\nLas facturas se envían el día 5 de cada mes...\n</untrusted_document>",
      "score": 0.87
    }
  ]
}

Cada text llega envuelto en <untrusted_document source="…">…</untrusted_document>. El atributo source es la URL de origen en fuentes web y la ruta del fichero en el resto; según el fragmento puede llevar además el rango de líneas y un ref interno. Si se lo pasas a tu propio modelo, déjalo tal cual: ese envoltorio es lo que le dice que son datos, no instrucciones. Si vas a enseñarle el fragmento a una persona, quítalo tú. Para que un documento no pueda cerrar el bloque antes de tiempo, una etiqueta <untrusted_document o </untrusted_document que venga dentro del propio texto llega como &lt;untrusted_document, y en el source las comillas y los < > van como &quot;, &lt; y &gt;.

systemPrompt es el prompt base de la inferencia, sin los fragmentos: eres tú quien compone los dos al llamar a tu modelo.

Si lo que quieres es buscar en un RAG sin pasar por una inferencia, la vía directa es POST /api/rags/{identifier}/retrieve.

El prompt de sistema no es secreto ​

Cualquier token con permiso sobre la inferencia puede leer su prompt de sistema: lo trae siempre /retrieve y, al ejecutar, includeSystemPrompt. Esconderlo ahí no serviría de mucho, porque con permiso para ejecutar basta con pedirle al modelo que lo repita dentro de un jsonSchema hecho a medida. Así que no pongas en él nada que no deba ver quien integra: credenciales, datos de otros clientes o reglas internas que no quieras enseñar.

Ficheros indexados ​

Qué documentos respaldan una inferencia y en qué estado están:

bash
curl "https://ur.tuempresa.com/api/inferences/clasificador-tickets/files?page=1&limit=20" \
  -H "Authorization: Bearer $UR_TOKEN"
ParámetroPor defectoNotas
page—Obligatorio
limit20Máximo 100
ragIdentifier—Restringe a un RAG

total cuenta ficheros, no grupos

La respuesta agrupa por RAG, pero la paginación es por fichero. Un RAG grande puede aparecer partido entre dos páginas: si recorres todas las páginas, agrupa tú por ragIdentifier al juntar los resultados.

json
{
  "data": [
    {
      "ragIdentifier": "ventas-docs",
      "ragName": "Documentación de ventas",
      "files": [
        {
          "filePath": "documentos/informe.pdf",
          "name": "informe.pdf",
          "status": "indexed",
          "indexedAt": "2026-03-01T10:00:00.000Z",
          "size": 182344,
          "mimeType": "application/pdf",
          "externalId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs",
          "metadata": { "tag": ["Confidencial"] },
          "errorMessage": null
        }
      ]
    }
  ],
  "total": 128,
  "page": 1,
  "limit": 20
}

Los estados posibles son pending, processing, indexed, error y deleted. Cuando es error, errorMessage dice por qué. deleted es un fichero pendiente de purga (ya fuera del RAG): no sale en ninguna búsqueda y sus vectores se borran en el primer escaneo de su fuente pasadas 24 h (por defecto).

externalId es el identificador del fichero en el proveedor —el que pide Estado de un fichero concreto—: el fileId en Google Drive, el id del ítem (el driveItem de Microsoft Graph) en SharePoint y OneDrive, la URL en una fuente web y null en sistema de ficheros. En Drive y SharePoint sigue al fichero aunque lo renombres o lo muevas dentro de la fuente. metadata trae las etiquetas del proveedor que puedes usar en providerFilter; hoy solo Google Drive las aporta, y en el resto llega null.

El enlace a un fichero de SharePoint

La API no lo devuelve. La función get_link de la tool rag_retrieve lo construye con la URL de la carpeta raíz de la fuente y la ruta del fichero, así que abrirlo pide iniciar sesión en Microsoft 365 con una cuenta que tenga acceso a ese fichero: es un enlace a SharePoint, no una copia pública.

Estado de un fichero concreto ​

Para comprobar si un documento llegó a indexarse, sin recorrer páginas:

bash
curl "https://ur.tuempresa.com/api/inferences/clasificador-tickets/file-sources/drive-ventas?file=1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs" \
  -H "Authorization: Bearer $UR_TOKEN"

El parámetro file es el identificador externo del fichero: el campo externalId que devuelve Ficheros indexados — el fileId en Google Drive, el id del ítem en SharePoint y OneDrive, y la URL absoluta en una fuente web. Cópialo de ahí, no lo construyas a mano.

En fuentes de sistema de ficheros no hay externalId

Ahí este endpoint no localiza un fichero por su ruta: usa Ficheros indexados acotado con ragIdentifier y busca por filePath. Y no le pases una ruta de carpeta: puede devolver 200 con el estado de un fichero cualquiera de dentro.

json
{
  "name": "informe.pdf",
  "size": 182344,
  "status": "indexed",
  "indexedAt": "2026-03-01T10:00:00.000Z",
  "errorMessage": null
}

Es el endpoint natural para un flujo "he subido un documento, ¿ya puedo preguntar por él?".