Autenticación y scopes
Cada endpoint protegido del contrato de lectura de Tarno está controlado por una clave de API. Esta guía
cubre cómo presentar la clave, los dos scopes, el ciclo de vida de la clave y la semántica exacta de 401 / 403 /
429 — todo en concordancia con los handlers en vivo.
El encabezado X-API-Key
Envía tu clave en el encabezado de solicitud X-API-Key en cada llamada a una ruta protegida:
curl -sS "$TARNO_BASE_URL/v1/brands?limit=1" -H "X-API-Key: $TARNO_API_KEY"
La clave es una cadena opaca emitida por el operador (marcador de posición <API_KEY> en esta documentación). El
servidor la verifica en cada solicitud; la clave en crudo nunca se registra en logs.
El servidor MCP usa el mismo encabezado X-API-Key, enviado por solicitud sobre el transporte Streamable HTTP
— consulta la guía de MCP. (Para el transporte stdio, la clave se lee de
la variable de entorno TARNO_API_KEY en su lugar.)
Rutas públicas que no necesitan clave
/health, /docs y /metrics son las únicas rutas que funcionan sin clave. Todo
lo que está bajo /v1 requiere una.
Scopes
Una clave lleva un conjunto de scopes que determinan qué partes del contrato puede leer:
| Scope | Otorga acceso a |
|---|---|
brands:read |
El contrato de marcas: GET /v1/brands, GET /v1/brands/:nroSolicitud. |
insights:read |
El contrato operacional: GET /v1/freshness, GET /v1/sync-runs. |
watch:read |
Lecturas de Vigilancia: GET /v1/watch, GET /v1/watch/:id, GET /v1/watch/:id/hits. |
watch:write |
Escrituras de Vigilancia: POST /v1/watch, PATCH /v1/watch/:id, DELETE /v1/watch/:id. |
Un arreglo de scopes vacío no tiene restricción — una clave emitida sin scopes recibe todos los scopes
de lectura. Una clave con un arreglo de scopes no vacío recibe solo los scopes listados; llamar a
una ruta cuyo scope requerido está ausente se rechaza con 403 forbidden.
Los scopes watch:* requieren además que la clave tenga una org dueña (consumerId); consulta la
guía de Vigilancia para la tenencia, la entrega dual y la firma de los webhooks.
Las herramientas de MCP siguen la misma regla: tanto search_brands como get_brand_detail requieren
brands:read (o una clave sin restricción, con scopes vacíos).
Ciclo de vida de la clave (gestionado por el operador)
Las claves se crean, rotan, revocan y expiran por el operador a través de la CLI de administración. Como integrador, tú no gestionas las claves por tu cuenta; solicitas los cambios a tu operador.
- Rotar — el operador te emite una clave nueva y da de baja la antigua. Cambia el
valor
X-API-Keyque tu cliente envía; sin cambios de código más allá del secreto. - Revocar — una clave revocada deja de funcionar de inmediato: las llamadas posteriores devuelven
401 unauthorized, exactamente como con una clave desconocida. - Expiración — una clave puede llevar una fecha de expiración. Una vez pasada la expiración se trata como inválida y
devuelve
401 unauthorized. Pídele a tu operador que la reemita antes de la expiración para evitar caídas.
Cada clave también pertenece a un consumidor y lleva una cuota mensual (ver más abajo).
Semántica de estados
Estos son los resultados exactos que producen las capas de autenticación y cuota:
401 unauthorized
Se devuelve cuando la clave está ausente, malformada, es desconocida o está revocada/expirada.
{ "error": { "code": "unauthorized", "message": "Missing or invalid API key", "requestId": "..." } }
403 forbidden
Se devuelve cuando la clave es válida y está activa, pero le falta el scope que la ruta requiere. El mensaje nombra el scope faltante:
{ "error": { "code": "forbidden", "message": "API key lacks required scope: insights:read", "requestId": "..." } }
429 quota_exceeded
Se devuelve cuando la cuota mensual de la clave está agotada. Lleva un encabezado Retry-After con los
segundos hasta que la ventana de cuota se reinicia:
HTTP/1.1 429 Too Many Requests
Retry-After: 1209600
{ "error": { "code": "quota_exceeded", "message": "Monthly quota exceeded", "requestId": "..." } }
429 rate_limited
Existen dos límites de tasa, ambos aditivos a la cuota mensual y ambos devuelven 429 con un
encabezado Retry-After (segundos a esperar):
- Ráfaga por clave (
code: rate_limited) — un segundo nivel por hash de la clave que acota a un solo inquilino: por defecto 300 solicitudes cada 60 s. Aplica de forma idéntica en REST y en el MCP (ambos transportes comparten el mismo contador), es independiente de la IP del cliente (por lo que un pool de IP rotatorio no lo esquiva) y no cambia el esquema del contrato/v1— es una nueva condición429puramente aditiva.
```text HTTP/1.1 429 Too Many Requests Retry-After: 42
{ "error": { "code": "rate_limited", "message": "Too many requests (per-key burst limit)", "requestId": "..." } } ```
- Defensa anti-inundación por IP (
code: rate_limited) — un límite por IP de cliente (por defecto 100 solicitudes/minuto) que frena una avalancha previa a la autenticación (claves rotatorias). Es independiente del nivel por clave.
Acción del consumidor: respeta el Retry-After y reintenta después de ese número de segundos. La cuota
mensual (quota_exceeded) y ambos límites de tasa (rate_limited) aplican de forma idéntica en REST y en
el MCP, ya que ambos transportes se autentican contra las mismas claves y comparten los mismos contadores.
El sobre de error uniforme
{ error: { code, message, requestId } }se describe en la guía de primeros pasos. UsarequestId(también reflejado en el encabezado de respuestax-request-id) al reportar un problema a tu operador.
CORS y acceso desde el navegador
IRIS es server-side-only por defecto: la clave X-API-Key es una credencial de servidor y
nunca debe incrustarse en un cliente de navegador. Por eso, de forma predeterminada la API no emite
ningún encabezado Access-Control-Allow-Origin — un fetch desde el navegador de un tercero no puede
leer las respuestas. Este es el comportamiento por defecto y no cambia nada respecto a versiones previas.
El acceso cross-origin desde navegador es opt-in por despliegue mediante la variable de entorno
IRIS_CORS_ALLOWLIST (lista de orígenes exactos separados por comas):
IRIS_CORS_ALLOWLIST=https://app.tarno.cl,https://docs.tarno.cl
- Vacía / sin definir → sin CORS (sin encabezado
Access-Control-Allow-Origin) — el default no-op. - Con orígenes → sólo esos orígenes exactos reciben el encabezado
Access-Control-Allow-Origin(nunca un comodín ni reflejo arbitrario delOrigin); no se envían credenciales (credentials:false). Las peticiones preflightOPTIONSde esos orígenes se responden con los encabezados de permiso.
El servidor MCP no usa CORS. El MCP es un transporte servidor-a-servidor (lo consumen agentes de IA por la red, no un
fetchde navegador), así que CORS —una salvaguarda del navegador— no aplica ahí.
Ver también
- Primeros pasos — URL base, primera llamada, paginación, sobre de error.
- Conecta tu agente de IA (MCP) — misma clave, mismos scopes, sobre MCP.
- La referencia OpenAPI en vivo en
/docs— seguridad y esquema por endpoint.