Primeros pasos
IRIS expone un contrato de lectura neutral sobre el corpus de marcas de INAPI: una API REST versionada más un servidor MCP, ambos respaldados por la misma capa de consultas y los mismos datos. Esta guía te lleva desde cero hasta una primera llamada autenticada contra la API REST.
El esquema completo y siempre actualizado por campo vive en la referencia OpenAPI interactiva en
/docs(Scalar). Esta guía explica cómo hacer la puesta en marcha y enlaza a esa referencia — no reformula el esquema. Cuando un campo no está documentado aquí,/docses autoritativo.
1. URL base y el prefijo /v1
La API REST la sirve tu operador sobre HTTPS. Cada endpoint del contrato de lectura vive
bajo el prefijo de versión /v1, p. ej. https://<iris-host>/v1/brands. A lo largo de esta guía
la URL base se escribe como la variable de entorno IRIS_BASE_URL — sustitúyela por el host que tu operador
te haya entregado.
export IRIS_BASE_URL="https://<iris-host>"
Un puñado de rutas son intencionalmente públicas (no requieren clave):
| Path | Propósito |
|---|---|
/health |
Sonda de liveness / readiness (200 ok / 503 degradado) |
/docs |
Referencia OpenAPI (Scalar) interactiva |
/metrics |
Métricas de Prometheus (solo red interna) |
Todo lo que está bajo /v1 está protegido y requiere una clave de API (ver más abajo y la guía de autenticación).
2. Obtén una clave de API
Las claves de API las emite el operador, fuera de banda, a través de la CLI de administración. No hay
endpoint de registro de autoservicio — tú no creas tu propia clave. Pídele a tu operador una clave de
lectura; te entregará una cadena de clave opaca y te dirá qué scopes lleva
(brands:read, insights:read, o sin restricción). Consulta la guía de autenticación para los scopes,
el ciclo de vida (rotar / revocar / expiración) y la semántica exacta de errores.
Guarda la clave como una variable de entorno y nunca la subas al control de versiones:
export IRIS_API_KEY="iris_xxx" # the opaque key string your operator issued
Todos los ejemplos de este portal usan el marcador de posición obvio
iris_xxx. Reemplázalo por tu clave real en tiempo de ejecución; nunca escribas una clave de forma fija en un archivo versionado.
3. Tu primera llamada autenticada: GET /v1/brands
Envía la clave en el encabezado de solicitud X-API-Key. GET /v1/brands busca o lista resúmenes
de marcas.
curl
curl -sS "$IRIS_BASE_URL/v1/brands?q=cafe&limit=5" \
-H "X-API-Key: $IRIS_API_KEY"
TypeScript (fetch)
const baseUrl = process.env.IRIS_BASE_URL!;
const apiKey = process.env.IRIS_API_KEY!; // "iris_xxx"
const res = await fetch(`${baseUrl}/v1/brands?q=cafe&limit=5`, {
headers: { "X-API-Key": apiKey },
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${res.status} ${error.code}: ${error.message} (requestId=${error.requestId})`);
}
const page = await res.json(); // { items: BrandSummary[], nextCursor: string | null }
console.log(page.items.length, "results; nextCursor =", page.nextCursor);
Una respuesta exitosa es una página por keyset:
{
"items": [
{
"nroSolicitud": "123456",
"nroRegistro": null,
"denominacion": "CAFE EXAMPLE",
"estado": "...",
"tipoSigno": "...",
"fechaPresentacion": "2023-01-15",
"fechaVencimiento": null,
"score": 0.0163
}
],
"nextCursor": "b2Zmc2V0OjUw"
}
score es el puntaje de relevancia de fusión (RRF) y está presente solo en la ruta de búsqueda
de texto libre (q=); se omite en un listado filtrado simple. Para el conjunto exacto de campos de
BrandSummary y BrandDetail, consulta la referencia /docs.
4. Filtrado y paginación por keyset
GET /v1/brands acepta estos parámetros de consulta:
| Param | Type | Notas |
|---|---|---|
q |
string | Búsqueda de texto libre (full-text + fuzzy). Cuando está presente, los resultados se rankean y llevan score. Omítelo para un listado filtrado simple. |
clase |
integer | Filtro de clase de Niza, 1–45. |
estado |
string | Código de estado (catálogo controlado). |
tipoSigno |
string | Código de tipo de signo (catálogo controlado). |
fechaDesde |
YYYY-MM-DD |
Límite inferior de la fecha de presentación (fecha_presentacion >=). |
fechaHasta |
YYYY-MM-DD |
Límite superior de la fecha de presentación (fecha_presentacion <=). |
limit |
integer | Tamaño de página. Por defecto 20, máximo 100. |
cursor |
string | Cursor de keyset opaco (ver más abajo). Trátalo como una caja negra. |
La paginación se basa en keyset, no en offset. Cada respuesta lleva un nextCursor:
- Para obtener la página siguiente, pásalo de vuelta sin cambios como el parámetro de consulta
cursor. nextCursor: nullsignifica fin de los resultados — detente.
# page 1
curl -sS "$IRIS_BASE_URL/v1/brands?q=cafe&limit=20" -H "X-API-Key: $IRIS_API_KEY"
# page 2 — pass the nextCursor from page 1
curl -sS "$IRIS_BASE_URL/v1/brands?q=cafe&limit=20&cursor=<nextCursor>" -H "X-API-Key: $IRIS_API_KEY"
Para obtener una marca completa (clases + personas + anotaciones del Estado-Diario), llama a
GET /v1/brands/:nroSolicitud:
curl -sS "$IRIS_BASE_URL/v1/brands/123456" -H "X-API-Key: $IRIS_API_KEY"
Un número de solicitud desconocido devuelve 404 not_found.
La familia insights:read (GET /v1/freshness, GET /v1/sync-runs) está documentada en la
guía de autenticación y en la referencia /docs.
5. El sobre de error uniforme
Cada error — validación, autenticación, no encontrado, límite de tasa y errores inesperados del servidor — se devuelve con una única forma uniforme:
{ "error": { "code": "unauthorized", "message": "Missing or invalid API key", "requestId": "..." } }
code— un token estable y neutral sobre el que puedes ramificar (ver la tabla siguiente).message— una descripción legible por humanos. Las respuestas5xxusan un mensaje genérico y nunca filtran detalles internos.requestId— correlaciona tu reporte con el log del servidor. También se refleja en el encabezado de respuestax-request-id; puedes suministrar el tuyo propio mediante el encabezado de solicitudX-Request-Id.
| HTTP | code |
Cuándo |
|---|---|---|
| 400 | validation_error |
Consulta / parámetros inválidos (falló la validación de Zod). |
| 401 | unauthorized |
Clave de API ausente, malformada, desconocida o revocada. |
| 403 | forbidden |
Clave válida, pero le falta el scope que la ruta requiere. |
| 404 | not_found |
Número de solicitud de marca desconocido, o una ruta desconocida. |
| 429 | rate_limited |
Se excedió el límite de ráfaga de corto plazo (ver más abajo). |
| 429 | quota_exceeded |
Cuota mensual agotada (ver más abajo). Lleva Retry-After. |
| 500 | internal_error |
Error inesperado del servidor (no se filtran detalles internos). |
6. Límites de tasa y cuota
Dos límites independientes protegen el contrato de lectura:
- Límite de ráfaga de corto plazo — un tope de tasa de solicitudes por clave (por defecto 100 solicitudes / minuto). Excederlo devuelve HTTP 429.
- Cuota mensual — un presupuesto mensual de solicitudes por clave. Cuando lo agotas, la API devuelve
HTTP 429 con
code: "quota_exceeded"y un encabezadoRetry-After(segundos hasta que la ventana de cuota se reinicia al final del mes). Esta misma cuota aplica de forma idéntica en REST y en el MCP — consulta la guía de MCP.
HTTP/1.1 429 Too Many Requests
Retry-After: 1209600
Content-Type: application/json
{ "error": { "code": "quota_exceeded", "message": "Monthly quota exceeded", "requestId": "..." } }
Respeta Retry-After: espera el número indicado de segundos antes de reintentar.
Próximos pasos
- Autenticación y scopes —
X-API-Key,brands:read/insights:read, ciclo de vida de la clave y la semántica completa de401/403/429. - Conecta tu agente de IA (MCP) — el endpoint
mcp.obviouy.comy las herramientassearch_brands/get_brand_detail. - Ejemplos de código — clientes REST y MCP listos para copiar y pegar.
- La referencia OpenAPI en vivo en
/docs— el esquema autoritativo por campo.