Skip to content

API HTTP ​

La API para llamar a ur desde tu backend: ejecutar inferencias, buscar en tus RAGs y consultar el estado de indexación de tus documentos.

RecursoPara qué
InferenciasEjecutar un prompt, con o sin tus documentos como contexto
RAGsBuscar fragmentos relevantes, listar ficheros, acotar el alcance
WebhooksQue otros sistemas avisen a ur de que hay cambios
AgentesListar los agentes del token, con sus tools

Base URL y autenticación ​

Todo cuelga de /api en el origen de tu instancia. Salvo los webhooks —que llevan el secreto de su propia fuente de ficheros—, cada llamada va con un access token en la cabecera Authorization:

bash
curl https://ur.tuempresa.com/api/inferences \
  -H "Authorization: Bearer ur-Ah7kQ2mZ..."

No hay CORS ​

Esta API no se llama desde un navegador

/api/* no emite cabeceras CORS, a propósito: el token Bearer no debe llegar nunca a un navegador, porque cualquiera que abra las devtools se lo lleva.

Llámala solo desde tu servidor. Si lo que necesitas es hablar desde el navegador del usuario final, la vía es el canal de agentes, que está diseñado para ser público.

Permisos ​

El token declara sobre qué recursos puede actuar, en tres grupos: agents, inferences y rags. Ver Credenciales.

Los webhooks quedan fuera de estos grupos: no se autentican con el access token, sino con el secreto de la file source. Ver Webhooks.

Hay dos comportamientos distintos según cómo llegues al recurso:

  • Listados — filtran en silencio. GET /api/agents o GET /api/inferences devuelven solo los permitidos.
  • Acceso directo — 403 {"error":"Forbidden"} si el recurso existe pero no está permitido.

Qué tiene disponible tu token ​

Un listado por recurso, de solo lectura. Cada uno devuelve únicamente lo que permite el token, así que con los tres sabes todo lo que puede usar una integración sin mirar el panel:

ListadoQué trae de cada elemento
GET /api/agentsNombre, identifier y los nombres de sus tools
GET /api/inferencesNombre, identifier, URL, los RAGs y fuentes que consulta, los adjuntos que admite su modelo y los nombres de sus tools
GET /api/ragsNombre, identifier, estado de indexación, contadores y su fuente de ficheros

Las tools son las que el agente o la inferencia pueden llamar de verdad: si un administrador desactiva la plantilla de una tool en el catálogo, deja de salir aunque siga asignada. Sin tools, []. Cada una sale por el nombre de su instancia; una de búsqueda en RAG (rag_retrieve) le ofrece además al modelo <nombre>_list_paths, _list_tags, _process_file y _get_link.

bash
curl https://ur.tuempresa.com/api/agents -H "Authorization: Bearer $UR_TOKEN"
curl https://ur.tuempresa.com/api/inferences -H "Authorization: Bearer $UR_TOKEN"
curl https://ur.tuempresa.com/api/rags -H "Authorization: Bearer $UR_TOKEN"

Errores ​

CódigoCuerpoCuándo
400{"error":"..."}Cuerpo inválido. El mensaje describe qué falla, pero no siempre nombra el campo: si tienes dudas, contrasta con el esquema de /api/docs
401{"error":"Unauthorized"}Falta el token o no existe. Con {"error":"Token expired"}, el token existe pero ya caducó: hay que renovarlo
403{"error":"Forbidden"}El token no cubre ese recurso. Con "code":"manage_required" (los scopes de un RAG), el dueño del token lo ve pero no lo administra
404{"error":"Not found"}No existe ese recurso — o el identifier del padre, o un sub-recurso (un fichero) que sí pediste por id
409{"error":"Scope already exists"}Ese scope ya está dado de alta en el RAG
413{"error":"..."}El cuerpo de la petición pasa del máximo: al ejecutar una inferencia con adjuntos
422{"error":"RAG is not in scoped mode"}La operación no aplica al estado actual del recurso — o el modelo de la inferencia no admite el tipo de adjunto enviado
429{"error":"Too many requests"}Superado el límite por minuto del usuario dueño del token. Retry-After dice cuántos segundos esperar. Con {"error":"Too many failed authentication attempts"}, demasiados intentos con un token que no vale desde esa IP
502{"error":"...","errorId":"..."}Falló el proveedor del modelo. El mensaje es genérico: el error completo queda en el log del servidor bajo ese errorId
503{"error":"Rate limiting unavailable"}El backend no puede hablar con Redis

Límites de peticiones ​

/api/inferences, /api/agents y /api/rags cuentan por usuario, en ventanas de 60 segundos y en un contador compartido por las tres:

  • Todos los tokens de un mismo usuario comparten cupo, y lo comparten también con sus conexiones MCP y con el probador de inferencias del panel. Crear más tokens no da más cupo.
  • Por defecto son 60 peticiones por minuto. Un administrador cambia el número general en Ajustes → API, y puede dar uno más alto a un usuario o a un grupo desde su ficha. A cada usuario se le aplica el mayor de los que le tocan; cada uno ve el suyo en Mi cuenta.
  • Cada respuesta lleva X-RateLimit-Limit (el límite) y X-RateLimit-Remaining (lo que queda en la ventana). Al pasarse, 429 con Retry-After: los segundos hasta que vuelve a haber cupo.

Las cabeceras ​

bash
curl -i https://ur.tuempresa.com/api/rags \
  -H "Authorization: Bearer ur-Ah7kQ2mZ..."
http
HTTP/1.1 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57

Y al pasarte, hasta que acaba la ventana:

http
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0

{"error":"Too many requests"}

La ventana es fija: empieza con la primera petición y dura 60 segundos, y reintentar antes de tiempo no la alarga ni la acorta. X-RateLimit-Remaining sirve para ir más despacio antes de llegar al 429.

Qué hacer con un 429 ​

Espera los segundos de Retry-After y repite la petición una vez. No reintentes en bucle: hasta que pase la ventana, cada intento vuelve a dar 429.

js
async function callUr(url, init) {
  const res = await fetch(url, init);
  if (res.status !== 429) return res;
  const seconds = Number(res.headers.get('Retry-After')) || 60;
  await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
  return fetch(url, init);
}

Si una integración vive pegada al límite, pide a un administrador que suba el de su usuario, o mejor, crea un usuario solo para ella: así no comparte cupo con nadie.

Intentos fallidos, por IP ​

Por IP solo cuentan los intentos fallidos: tras 30 peticiones en un minuto sin token, con uno que no existe o con uno caducado, esa IP recibe 429 {"error":"Too many failed authentication attempts"} con Retry-After (sin las X-RateLimit-*, que son del cupo de un usuario) hasta que pasa la ventana, aunque luego llegue con uno bueno.

Otras superficies ​

El resto cuenta por IP, sin cabeceras X-RateLimit-*. Su 429 también lleva Retry-After, y en /embed se puede leer desde el navegador (va en Access-Control-Expose-Headers):

SuperficieLímite
/api/webhooks/*20 por minuto
/embed/* (widget y SDK)180 por minuto para cada agente (se cambia en su sección Seguridad), con un tope de 600 sumando todos los agentes (Ajustes → API)

El 503 es a propósito

Si Redis no está disponible, las rutas con límite devuelven 503 en vez de dejar pasar el tráfico. Falla cerrado. Un 503 aquí apunta a la infraestructura, no a tu petición.

Campos solo de administrador ​

La API acepta también la cookie de sesión del panel, y esto tiene una consecuencia que muerde al pasar a producción:

Probar en el navegador enseña campos que luego no están

Con sesión del panel (cualquier usuario con acceso al recurso, no solo un administrador) la respuesta trae campos de diagnóstico que con un token Bearer no aparecen:

  • timings — desglose de tiempos (contexto, reranking, LLM)
  • usage — tokens consumidos y coste
  • toolCalls[].debug — detalle interno de cada tool
  • message dentro de degraded
  • la cabecera X-Inference-Timings

Si construyes tu integración probando desde el navegador con sesión abierta y luego cambias a un token, esos campos desaparecen sin previo aviso. No los des por hechos.

Referencia navegable ​

Tu propia instancia publica la especificación OpenAPI, generada del código y siempre al día:

URLQué es
https://<tu-instancia>/api/docsReferencia navegable, campo a campo
https://<tu-instancia>/api/openapi.jsonLa especificación en crudo, para generar clientes

Las dos son públicas: no hacen falta credenciales para leerlas (sí para llamar a los endpoints).

Los webhooks no están en la especificación

Todo /api está en el OpenAPI —inferencias, RAGs y agentes— menos los webhooks, que no se llaman con el access token sino con el secreto de su fuente: su documentación es la de este sitio.