Autenticación
Cómo funcionan los tokens de API de SETTO — tokens personales y de organización, la cabecera bearer, los prefijos live y test, los seis permisos, qué alcanza cada token, 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
SETTO, enviado en la cabecera Authorization como bearer token. Un token es
personal — te pertenece y alcanza todos los torneos que administras — o de
una organización — le pertenece a una organización y solo alcanza sus
torneos. Los tokens se crean en el panel de organizador de SETTO, por defecto
solo leen y se muestran completos exactamente una vez. Esta página cubre los dos
tipos de token, el formato de la cabecera, los dos prefijos de token, qué puede y
qué no puede ver un token, los seis permisos que puede llevar, y cómo rotarlo o
revocarlo.
¿Vas a conectar un asistente de IA?
claude.ai, ChatGPT, Codex y Claude Code pueden saltarse el token: inician sesión con tu cuenta de SETTO y obtienen su propio token de acceso, que también es un token de API (misma cabecera, mismo prefijo) y actúa como tú. Consulta Entrar con tu cuenta de SETTO.
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 llevan los
mismos scopes.
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.
Dos tipos de token
| Token personal («Token personal») | Token de organización («Token de la organización») | |
|---|---|---|
| Dueño | Tú | Una organización |
| Dónde se crea | Configuración → Tokens de API, con Personal en el selector | Configuración → Tokens de API con la organización en el selector, o la página de la organización, pestaña API |
| Quién puede crearlo | Cualquier usuario de SETTO, para sí mismo | El creador de la organización o un miembro con el rol ADMIN |
| Qué lee | Todos los torneos que administras hoy: los que creaste (incluidos los personales), los que aceptaste administrar por invitación y los de cada organización a la que perteneces, incluidos los compartidos con ella | Los torneos de la organización, incluidos los compartidos con ella |
| Límite | 10 tokens activos por usuario | 10 tokens activos por organización |
| Cuando cambia el acceso | Si dejas una organización o pierdes una invitación, la siguiente petición a esos torneos es un 404 | Sigue leyendo; cada permiso aparte de read deja de funcionar en cuanto quien lo creó ya no es ADMIN de la organización |
GET /v1/external/me | owner.type: "user", organization: null | owner.type: "organization", organization lleno |
Cuál usar
- Un token de organización para sistemas que son de la organización: la web del club, una sincronización, un asistente que comparten varias personas. No alcanza nada fuera de la organización y sigue leyendo aunque la gente entre y salga.
- Un token personal para tu propio asistente (Claude Code, Codex, Cursor, VS Code — mira el servidor MCP) o un script que corres tú. Alcanza todo lo que administras y sigue tu acceso cuando cambia.
- Ningún token para claude.ai, ChatGPT, Codex o Claude Code: pueden entrar con tu cuenta de SETTO y actuar como tú, con los permisos que apruebes.
Crear un token
En app.setto.io abre Configuración → Tokens de API. El selector de cuenta u organización, arriba de Configuración, decide de quién es el token: déjalo en Personal para un token personal, o elige una organización para un token de organización. Luego elige Crear token.
- Cualquiera puede crear tokens personales para sí mismo, y solo esa persona los
ve — ni siquiera los
ADMINde sus organizaciones. - Solo el creador de la organización o un miembro con el rol
ADMINpuede crear, listar o revocar los tokens de una organización. Los demás miembros reciben un403de los endpoints de gestión; el panel se los indica. La página de la organización, pestaña API, muestra los mismos tokens. - El nombre es obligatorio. Nombra los tokens según quién los consume
(
Club website,Claude Desktop), no según una persona. - En Permisos, «Leer» siempre va marcado; marca cualquier otro permiso que necesite quien lo consume (mira Qué puede cambiar un token).
- La expiración es opcional: nunca, 30, 90 o 365 días. Un token expirado
devuelve
401conEXPIRED_API_TOKEN. - Un usuario puede tener como máximo 10 tokens personales activos, y una organización como máximo 10 tokens de organización activos; son límites separados. 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 cambiar un token
Un token lleva uno o más de seis permisos, sus scopes. Todo token lleva
read, y es todo lo que la mayoría necesita. Los demás los marcas en
Permisos al crear el token; la lista de tokens muestra una insignia por cada
uno que lleva (schedule dice «Programa partidos»).
| Permiso | Scope | Qué permite | Rutas de la API hoy |
|---|---|---|---|
| «Leer» | read | Ver torneos, categorías, equipos, resultados, horarios y la actividad. Siempre incluido | Todos los GET, la propuesta de programación y las vistas previas (no escriben nada) |
| «Programar partidos» | schedule | Asignar y mover el día, la hora y la cancha de los partidos que no se han jugado | POST /v1/external/tournaments/{idx}/schedule/placements |
| «Gestionar torneos» | manage | Crear y editar torneos, categorías, cabezas de serie, equipos y jugadores; inscribir equipos; sustituir a un jugador («Sustitución») o dar de baja a un equipo («Baja»); fijar el formato de una categoría, sus grupos y su cuadro | POST /v1/external/tournaments y las demás escrituras de configuración y de cuadros (referencia) |
| «Cargar resultados» | results | Registrar, corregir y borrar resultados de partidos | POST y DELETE /v1/external/tournaments/{idx}/games/{gameIdx}/result |
| «Página pública» | landing | Cambiar el diseño, las secciones, los patrocinadores y la visibilidad de la página pública | Ninguna todavía |
| «Enviar comunicaciones» | communications | Enviar correos a los participantes de tus torneos | Ninguna todavía |
Hoy la API escribe tres tipos de cosas: la configuración de torneos (crear y
editar torneos y sus categorías, inscribir y editar equipos y jugadores,
«Sustitución», «Baja») y sus cuadros (el formato de una categoría, sus grupos,
sus eliminatorias y «Confirmar cuadro»), que requieren manage; los resultados
de los partidos, que requieren results; y la hora de inicio, la cancha y la
duración de los partidos de un torneo, que requiere schedule. Los otros dos
permisos ya se pueden otorgar y están reservados para las escrituras que
vienen; un token que solo lleva esos no puede hacer más que leer. Ningún permiso
cambia ningún precio, marca de pago, registro de pago ni reembolso; una baja
cierra los enlaces de pago sin pagar del equipo. Un token sin el permiso que una ruta
necesita recibe 403 INSUFFICIENT_SCOPE. GET /v1/external/me lista los
scopes de un token.
Además, cada permiso está limitado por lo que la persona detrás del token puede hacer en el panel, y quién es esa persona depende del tipo de token:
- un token personal escribe en cualquier torneo que su dueño administre en el momento de la petición;
- un token de organización con cualquier permiso aparte de
readsolo lo puede crear unADMINde la organización, y escribe solo mientras esa persona siga siendoADMINde la organización. Cuando deja de serlo, la escritura es403 INSUFFICIENT_SCOPE, y unADMINactual crea un token nuevo; - un token de acceso de OAuth — el que obtienen claude.ai, ChatGPT, Codex o Claude Code cuando entras con tu cuenta de SETTO — actúa como tú, con los permisos que aprobaste en la pantalla de consentimiento.
Qué puede ver un token
Qué torneos alcanza un token depende de su tipo:
- un token personal alcanza todos los torneos que su dueño administra en
el momento de la petición — los que creó (incluidos los personales), los que
aceptó administrar por invitación y los de cada organización a la que
pertenece, incluidos los compartidos con ella. Se calcula de nuevo en cada
petición: si dejas una organización, sus torneos responden
404en la siguiente llamada; - un token de organización alcanza los torneos cuya organización principal es esa organización, más los compartidos con ella.
De cada torneo que alcanza, un token lee:
- el torneo — incluidos los que están en
DRAFTyARCHIVED, 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.
La organization de un torneo dice dónde vive. Con un token de organización es
siempre la organización del token. Con un token personal es la organización
principal del torneo, o null para un torneo personal.
Ningún token lee:
- datos de otras organizaciones con un token de organización, aunque quien lo creó sea miembro de ambas. Un token de organización, una 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 todo lo que alcanza: una
organización entera o — si es personal — todos los torneos que administras. 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 en Configuración → Tokens de API, con el selector en la cuenta u organización donde lo creaste.
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 permiso que la ruta necesita (o, en un token de organización, quien lo creó ya no es ADMIN) | 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 token de acceso de OAuth responde 401 en cuanto su aplicación se desconecta
en Configuración → Conexiones o se cumplen sus 30 días; la aplicación lo
renueva o te pide iniciar sesión otra vez. Su 403 INSUFFICIENT_SCOPE se
arregla conectando la aplicación otra vez y marcando el permiso que faltaba.
Un recurso que este token no alcanza — de otra organización, o un torneo que ya
no administras — 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 SETTO en el panel 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.