Autenticación
Cómo funcionan los tokens de API de SETTO — la cabecera bearer, los prefijos live y test, el alcance por organización, expiración, rotación y revocación, y la diferencia entre 401 y 403.
Cada petición a la API externa lleva una sola credencial: un token de API de
organización, enviado en la cabecera Authorization como bearer token. Los
tokens se emiten desde el panel de organizador de SETTO, pertenecen a una
organización y no a una persona, son de solo lectura y se muestran completos
exactamente una vez. Esta página cubre el formato de la cabecera, los dos
prefijos de token, qué puede y qué no puede ver un token, y cómo rotarlo o
revocarlo.
La cabecera
GET /v1/external/tournaments HTTP/1.1
Host: api.setto.io
Authorization: Bearer setto_live_YOUR_TOKEN_HERENo hay alternativa. La API no acepta un token en la query string, en una cookie
ni en una cabecera X-Api-Key — solo Authorization: Bearer. Una cabecera
ausente o mal formada es un 401, nunca una lectura anónima silenciosa.
Formato del token
Un token es un prefijo más un secreto. Los primeros 16 caracteres son el prefijo, que SETTO guarda en claro para que el panel pueda mostrarte cuál token es cuál; el resto es el secreto, que SETTO guarda solo como hash.
| Prefijo | Significado |
|---|---|
setto_live_… | Token de producción. Funciona contra la API de producción. |
setto_test_… | Token no productivo. La API de producción lo rechaza. |
Usa tokens setto_test_ cuando apuntes una integración a una API de SETTO de
staging o local; usa setto_live_ para cualquier cosa real. Ambos son de solo
lectura.
El prefix es lo que ves en todos los lugares donde el token se muestra — en
la lista del panel y en el campo token.prefix de GET /v1/external/me.
Registra el prefijo cuando necesites distinguir dos tokens. Nunca registres el
token completo.
Crear un token
En app.setto.io ve a Organización, selecciona la organización, abre la pestaña API y elige Crear token.
- Solo el creador de la organización o un miembro con el rol
ADMINpuede crear, listar o revocar tokens. Los demás miembros reciben un403de los endpoints de gestión; la pestaña se los indica. - El nombre es obligatorio. Nombra los tokens según quién los consume
(
Club website,Airtable sync), no según una persona. - La expiración es opcional: nunca, 30, 90 o 365 días. Un token expirado
devuelve
401conEXPIRED_API_TOKEN. - Una organización puede tener como máximo 10 tokens activos a la vez. Revoca uno antes de crear el número once.
Copia el secreto de inmediato
El token completo aparece una sola vez, en el diálogo posterior a la creación. SETTO conserva solo un hash, así que nadie — ni tú, ni el soporte de SETTO — puede recuperarlo después. Si se pierde, revoca y vuelve a crear.
Qué puede ver un token
Un token está limitado a una organización. Lee:
- todos los torneos cuya
organizationsea esa organización — incluidos los que están enDRAFTyARCHIVED, y los torneos cuya página pública está apagada (isPublic: false); - las categorías, equipos, rondas, grupos, cuadros, partidos, marcadores y
clasificaciones que cuelgan de esos torneos — incluidos los marcados con
isVisible: false.
No lee:
- torneos personales — los torneos creados por un usuario fuera de una organización son invisibles para cualquier token, incluso el de su dueño;
- datos de otras organizaciones, aunque seas miembro de ambas. Un token, una organización; usa un token por organización;
- datos personales de contacto — correos, teléfonos, redes sociales y similares se eliminan de todas las respuestas;
- datos de pago o facturación — cuotas de inscripción pagadas, métodos de pago, identificadores de Stripe y notas del organizador no forman parte del contrato.
Como el material oculto y en borrador sí se devuelve, trata el payload como
interno hasta que lo filtres. Si estás renderizando una página pública, filtra
tú mismo por status y por isVisible.
Mantén los tokens del lado del servidor
Un token setto_live_ da acceso de lectura a toda tu organización. Su lugar es
una variable de entorno del servidor, un gestor de secretos o una función
serverless — nunca un bundle del navegador, una app móvil, un repositorio
público o una URL.
Si necesitas datos de torneo en el navegador, pon una pequeña ruta de servidor delante de la API:
export async function GET() {
const res = await fetch(
'https://api.setto.io/v1/external/rounds/9d3c6a84-7e15-4b02-8f6d-1c4a9e7b53f2',
{
// SETTO_API_TOKEN es solo de servidor. Nunca le pongas el prefijo NEXT_PUBLIC_.
headers: { Authorization: `Bearer ${process.env.SETTO_API_TOKEN}` },
next: { revalidate: 60 },
},
);
// Revisa el STATUS antes que el cuerpo. Un payload de error no trae
// `isVisible` ni `pools`, así que proyectarlo respondería 200 con un
// resultado vacío y escondería un token expirado detrás de "esta ronda no
// tiene clasificaciones".
if (res.status === 404) {
return new Response('Not found', { status: 404 });
}
if (!res.ok) {
// El problema de tu credencial no es el de tu visitante. Registra el
// detalle y devuelve un fallo genérico — nunca reenvíes el cuerpo ni el
// status de arriba.
console.error(`SETTO API ${res.status} al cargar la clasificación`);
return Response.json(
{ error: 'upstream_unavailable' },
{ status: 502 },
);
}
const round = await res.json();
// Tu token ve material oculto y en borrador; esta ruta no pide ninguno, así
// que todo lo que devuelvas aquí es público. Una ronda oculta responde 404
// igual que una inexistente — nunca confirmes que existe.
if (round.isVisible === false) {
return new Response('Not found', { status: 404 });
}
// ...y luego publica una proyección explícita en lugar del payload de arriba,
// para que un campo que la API agregue después no se filtre por defecto.
return Response.json({
name: round.name,
pools: (round.pools ?? []).map((pool) => ({
name: pool.name,
standings: (pool.standings ?? []).map((row) => ({
rank: row.rank,
team: row.team?.name,
points: row.awardedPoints,
})),
})),
});
}Cachea la proyección, nunca la respuesta de arriba — un payload completo cacheado es una filtración esperando a la siguiente persona que lo reutilice.
La misma regla aplica al panel Try it de la referencia: dispara la petición desde tu propio navegador, así que pega un token desechable o que vayas a rotar pronto en lugar del de producción.
Rotación y revocación
Los tokens no se rotan solos. Para rotar:
- Crea un segundo token con la misma intención (
Website widget (new)). - Despliega el nuevo valor en el consumidor.
- Confirma que el tráfico se movió —
token.lastUsedAtdel token nuevo empieza a avanzar. - Revoca el token viejo desde la pestaña API.
La revocación surte efecto de inmediato: la siguiente petición con ese token es
un 401 con INVALID_API_TOKEN. Si un token se filtra, revoca primero y
pregunta después — nada de la API tiene estado, así que un token revocado y
reemplazado no te cuesta más que un redeploy.
Rota con calendario si puedes, y siempre que alguien con acceso se vaya.
401 contra 403
Significan cosas distintas y piden respuestas distintas.
| Estado | Códigos | Qué pasó | Qué hacer |
|---|---|---|---|
401 | MISSING_API_TOKEN | No hay cabecera Authorization, o no era Bearer setto_… | Corrige la petición |
401 | INVALID_API_TOKEN | Token desconocido, revocado o de otro entorno (un setto_test_ en producción) | Vuelve a emitir el token |
401 | EXPIRED_API_TOKEN | El expiresAt del token ya pasó | Crea un token nuevo |
403 | INSUFFICIENT_SCOPE | El token es válido pero no lleva el alcance que la ruta necesita | No reintentes |
En corto: 401 significa no sabemos quién eres — detente y consigue una
credencial que funcione. 403 significa sabemos exactamente quién eres y la
respuesta sigue siendo no — reintentar con el mismo token nunca va a funcionar.
Un recurso que pertenece a otra organización no es un 403. Es un 404
(TOURNAMENT_NOT_FOUND / ROUND_NOT_FOUND), idéntico a la respuesta para un id
que no existe en ningún lado — la API nunca confirma la existencia de datos que
no tienes permitido leer. Consulta Errores.
Inicio rápido
Crea un token de API de organización en el panel de SETTO y haz tus primeras tres peticiones a la API externa con curl, JavaScript o Python.
Modelo de datos
El árbol de dominio de SETTO — organización, torneo, categoría, ronda, grupo, cuadro y partido — más las convenciones de identificadores y los valores de enum sobre los que vas a ramificar.