SETTO API

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.

Todo lo que devuelve la API externa cuelga de un mismo árbol: una organización posee torneos; un torneo tiene categorías (divisions) y equipos; una categoría tiene rondas; una ronda contiene grupos (pools, con clasificación) para el juego de todos contra todos y cuadros (draws) para la eliminación directa; ambos terminan conteniendo partidos, y un partido terminado tiene un marcador (score) con sus sets. Aprende esta forma una vez y los seis endpoints dejan de parecer seis cosas sin relación.

El árbol

En prosa:

  • Una Organization posee torneos. Tu token está ligado a exactamente una.
  • Un Tournament es una competencia. Lleva el formato (type), el deporte, el status del ciclo de vida, las fechas y una publicUrl.
  • Una Division es lo que organizadores y jugadores llaman categoría: un segmento por nivel y rama dentro del torneo (Cuarta Fuerza Varonil). Es dueña de las rondas y del precio.
  • Un Round es una fase — juego de grupos o una etapa de eliminación.
  • Un Pool es un grupo dentro de una ronda de todos contra todos; contiene los equipos de ese grupo y su clasificación (standings).
  • Un Draw es un cuadro. Contiene draw rounds (Quarterfinals, Semifinals, …) en su order, y cada draw round contiene sus partidos.
  • Un Game es un partido. Los partidos terminados llevan un score, que a su vez lleva sus sets.
  • Un Team es una inscripción registrada: una pareja en dobles, un jugador único en singles, el equipo completo en fútbol, y en las ligas por equipos una escuadra ligada a un league team.

Identificadores

Cada recurso expone un UUID v4 como idx. Ese es el id que pasas en una ruta (/v1/external/tournaments/{idx}) y el id que guardas de tu lado. Las llaves primarias numéricas que SETTO usa internamente nunca se exponen.

Los torneos llevan dos identificadores extra:

CampoEjemploUso
slugtorneo-apertura-2026Legible, único, estable
publicUrlhttps://www.setto.io/t/torneo-apertura-2026Página pública canónica, lista para enlazar

Los endpoints toman idx, no slug. Guarda el idx de la llamada de listado; usa el slug para mostrar y la publicUrl para enlazar.

Torneo

CampoNotas
typeFormato de competencia — ver abajo
sportPADEL, TENNIS, PICKLEBALL o FUTBOL
statusCiclo de vida — ver abajo
startDate, endDateMarcas de tiempo ISO 8601 en UTC
timezoneZona IANA en la que se armó el calendario (America/Monterrey), nullable
isPublicSi la página pública es accesible — false no la oculta de la API
isFormatCompleteSi el organizador terminó de configurar el formato
matchDaysNúmero de jornadas, para torneos con forma de liga
standingColumnsQué estadísticas muestra la tabla de clasificación — en fútbol, las de goles
sportSettingsSolo fútbol: modalidad, tiempo extra, walkover — ver abajo. null en el resto
publicUrlhttps://www.setto.io/t/{slug}
organization{ idx, name, slug } — siempre presente

type

Los cuatro formatos que te vas a encontrar más seguido:

ValorForma
TOURNAMENTUn evento único: fase de grupos y/o un cuadro
LEAGUEUna temporada de jornadas entre parejas
TEAM_LEAGUEUna temporada entre escuadras; una ronda puede tener division: null
INDIVIDUAL_LEAGUEUna temporada entre jugadores individuales

Los formatos especializados (Americano, express/lucky-loser y las ligas individuales de pickleball) llevan sus propios valores de type. Trata type como una cadena abierta: ramifica sobre los valores que te importen y deja pasar el resto, en lugar de dar por hecho que el conjunto está cerrado.

status

El ciclo de vida corre en una sola dirección:

DRAFT → UPCOMING → IN_PROGRESS → COMPLETED → ARCHIVED

Los cinco se devuelven. Los torneos DRAFT y ARCHIVED son visibles para tu token aunque el sitio público los oculte — fíltralos con el parámetro de consulta status, o descártalos del lado del cliente, antes de renderizar nada público.

sportSettings

Un torneo de fútbol (soccer) lleva un bloque sportSettings con las reglas que eligió el organizador. En PADEL, TENNIS y PICKLEBALL el campo es null.

CampoNotas
modalityF5, F7, F9, F11 o FUTSAL — tamaño de equipo y cancha
extraTimeSi un empate en eliminatoria se va a tiempo extra antes de los penales
matchMinutesMinutos de tiempo reglamentario
h2hRequiresCompleteSubsetOmitir la mini-liga si algún par empatado aún no se enfrentó
forfeitScoreGoles que se le otorgan al equipo que sí se presentó, en un walkover
fairPlayWeights{ yellow, secondYellow, directRed, yellowThenRed }, nullable

Los torneos de fútbol siempre son type: TOURNAMENT, siempre se registran por equipo (un capitán inscribe a la escuadra) y nunca forman parte de un circuito: circuit y circuitCategory quedan en null.

Categoría (division)

CampoNotas
nameCuarta Fuerza Varonil
numberOrden de despliegue; las listas se ordenan por él, ascendente
colorColor hexadecimal que eligió el organizador, usado en toda la UI de SETTO
isDoublestrue para parejas, false para singles y para equipos de fútbol
isVisiblefalse significa que el organizador ocultó esta categoría en el sitio público
pricePrecio de inscripción de esta categoría, nullable
minParticipants, maxParticipants, maxRegistrationsCupo, todos nullable
tournamentReferencia inversa { idx }

Lo oculto se devuelve, no se filtra

Una categoría oculta regresa con isVisible: false en lugar de omitirse. El trabajo de la API es decirte la verdad; decidir qué mostrar es tuyo. Lo mismo aplica a las rondas.

Ronda

CampoNotas
namePool Play, Playoffs o Qualifiers
typeROUND_ROBIN_ROUND, SINGLE_ELIMINATION_ROUND o QUALIFIERS_ROUND
numberOrden dentro de la categoría
isVisibleMisma semántica que en una categoría
isSetupSi el organizador ya generó los partidos de la ronda
numberOfSets, proSets, playAllSets, pointsPerSetReglas de puntuación
drawSize, numQualifiers, placementsDimensiones del cuadro
division{ idx, name } — nullable: una ronda de TEAM_LEAGUE puede abarcar todo el torneo

Una ronda de todos contra todos llena pools; una ronda de eliminación directa llena draws. Muchas rondas llenan tanto games (la lista plana) como la estructura anidada del cuadro — así que el mismo partido puede aparecer dos veces en un payload, una bajo games y otra bajo draws[].rounds[].games[]. Elimina duplicados por game.idx.

Una ronda de fútbol siempre es de todos contra todos o de eliminación directa, nunca de clasificación, y siempre es de un solo set: numberOfSets es 1, proSets y playAllSets son false, y pointsPerSet es null.

Grupo, clasificación y estadísticas de equipo

Un pool es un grupo: { idx, name, number }, más teams y standings cuando los populas. Una standing lleva rank, awardedPoints, su referencia team, y un objeto teamStats con points, wins, losses, ties, forfeits, pointsFor / pointsAgainst, setsPointsFor / setsPointsAgainst y las dos diferencias calculadas.

En fútbol esos mismos contadores son goles: pointsFor son los goles a favor, pointsAgainst los goles en contra y pointsDifference la diferencia de goles. Las estadísticas de sets — setsPointsFor, setsPointsAgainst y setsPointsDifference — nunca se escriben en fútbol y se quedan en 0.

tournament.standingColumns elige cuáles de esas estadísticas muestra la tabla. Un torneo de fútbol agrega GOALS_FOR, GOALS_AGAINST y GOAL_DIFFERENCE — tres columnas que leen los campos pointsFor / pointsAgainst / pointsDifference de arriba — en lugar de las columnas SETS_* / POINTS_*, que no puede usar. Los contadores de partidos quedan igual: un torneo de fútbol nuevo nace con GAMES_PLAYED, GAMES_WON, GAMES_TIED, GAMES_LOST y esas tres columnas de goles. Los deportes de raqueta conservan sus columnas de sets y puntos, y nunca reciben las de goles.

Sobre rank

rank es el rango almacenado, tal como SETTO lo calculó por última vez. El sitio público aplica encima el head-to-head y los demás desempates configurados al renderizar una tabla de clasificación, así que una tabla que armes solo con rank puede diferir de la de setto.io. Si necesitas paridad exacta, ordena con las reglas de desempate del propio torneo (populate=rankedTiebreakRules en el torneo) en lugar de hacerlo por rank.

El fútbol agrega un criterio a ese orden: H2HL, la mini-liga de enfrentamientos directos. Los equipos que siguen empatados se reordenan con una sub-tabla armada solo con los partidos que jugaron entre ellos — primero puntos, luego diferencia de goles y luego goles a favor dentro de esa sub-tabla. Se omite mientras esos equipos no se hayan enfrentado todos, salvo que el organizador desactive sportSettings.h2hRequiresCompleteSubset.

Cuadro y ronda de cuadro

Un draw es un cuadro: { idx, placement }. placement distingue el cuadro principal de los cuadros de consolación y de tercer lugar. Sus draw rounds llevan un label (Quarterfinals, Semifinals, Final) y un order; ordena por order para acomodar el cuadro de izquierda a derecha.

Partido

CampoNotas
number, displayNumberNumeración del partido; displayNumber es la que muestran los organizadores
statusUPCOMING, FINISHED, CANCELLED, FORFEIT o BYE
timeHora programada de inicio, ISO 8601 en UTC, nullable
courtNumber, courtNúmero de cancha y, cuando se popula, el objeto de la cancha
matchDayNúmero de jornada, para ligas
homeTeam, awayTeam, winnerReferencias { idx, name }, cada una nullable
homeTeamDetails, awayTeamDetailsLa etiqueta del lugar mientras no se conoce su equipo — ver abajo
score{ home, away, sets[] } cuando se popula — ver abajo
isRetirementSi el partido terminó por retiro

Etiquetas de los lugares del cuadro

En un cuadro, un partido suele existir antes de que se conozcan sus participantes. Entonces homeTeam es null y homeTeamDetails lleva la etiqueta del lugar, que dice de dónde va a salir el equipo:

{
  "label": "Winner of Game 3",
  "labelEs": "Ganador del juego 3",
  "teamNumber": null,
  "poolNumber": null,
  "poolRank": null,
  "sourceGameNumber": 3,
  "sourceResult": "WINNER"
}

label es la clave almacenada, casi siempre en inglés; labelEs es la misma etiqueta tal como la escribe el panel de SETTO en español («Ganador del juego 3», «1ro Grupo A»). Para otro idioma, ármala con sourceGameNumber / sourceResult (o poolNumber / poolRank) en lugar de imprimir label.

Marcador y sets

{
  "idx": "1b9d7c36-4e58-40af-92c1-6d3f8a05b7e2",
  "home": 2,
  "away": 1,
  "sets": [
    { "idx": "…", "number": 1, "home": 6, "away": 4, "isTieBreak": false },
    { "idx": "…", "number": 2, "home": 3, "away": 6, "isTieBreak": false },
    { "idx": "…", "number": 3, "home": 7, "away": 5, "isTieBreak": false }
  ]
}

score.home / score.away son sets ganados, no puntos. Los puntos por set viven en sets[], ordenados por number.

Marcadores de fútbol

Un resultado de fútbol reutiliza esa misma forma con otra lectura. score.home y score.away son goles del tiempo reglamentario — el marcador al final del reglamentario, no el del partido si hubo tiempo extra — y sets trae exactamente un elemento que los repite, con isTieBreak: false. Ese set sintético es a propósito: una integración que suma sets[] sigue funcionando, nada más que suma goles en lugar de puntos por set.

{
  "idx": "7d2c9a41-0b63-4f18-9e57-3a4c8d015f6b",
  "home": 2,
  "away": 2,
  "sets": [
    { "idx": "…", "number": 1, "home": 2, "away": 2, "isTieBreak": false }
  ],
  "extraTime": { "home": 1, "away": 0 },
  "penalties": null,
  "decisionMethod": "EXTRA_TIME"
}

Tres campos que solo llena el fútbol; en un marcador de raqueta los tres vienen en null:

CampoNotas
extraTime{ home, away } — goles anotados durante el tiempo extra, o null
penalties{ home, away } — penales convertidos en la tanda, o null
decisionMethodREGULATION, EXTRA_TIME, SHOOTOUT o WALKOVER

El tiempo extra no se acumula, los penales no son goles

extraTime cuenta solo lo que se anotó en el tiempo extra, así que súmalo a score.home / score.away para el total: el ejemplo de arriba es 2-2 al final del tiempo reglamentario y una victoria 3-2 tras el tiempo extra. Y la tanda de penales no es anotación — penalties nunca llega a la tabla de clasificación, así que ganar 4-3 en penales deja el pointsFor de los dos equipos igual.

Un partido de fútbol de fase de grupos puede terminar empatado: el resultado queda como empate y winner es null. Uno de eliminatoria no — el empate se va a tiempo extra (si el organizador lo activó) y luego a penales, y SETTO deriva el winner del desempate que lo resolvió. Lee winner y decisionMethod en lugar de comparar score.home con score.away, que se quedan en los goles del tiempo reglamentario.

Equipo

CampoNotas
nameÁlvarez / Peña en pareja, el nombre del jugador en singles, el equipo en fútbol
seed, seedNumberSiembra; nullable, y ordenada con los nulos al final en las respuestas de lista
division{ idx, name }, nullable
players[{ idx, firstName, lastName, avatar }] cuando se popula — nunca datos de contacto
captainProfileIdxEl idx del perfil de jugador del capitán, cuando se popula
leagueTeam{ idx, name, color, logo, position, pointsAdjustment } para ligas por equipos
isWildCard, qualifierStatus, drawAssignmentControl de wildcards y clasificados
picture, club, ranking, descriptionCampos opcionales de presentación

En un TEAM_LEAGUE, un equipo pertenece a un league team — la escuadra (Alemania, Brasil) que acumula puntos a lo largo de la temporada.

Fechas y zonas horarias

Cada marca de tiempo es ISO 8601 en UTC con sufijo Z (2026-09-18T17:00:00.000Z). El campo timezone del torneo te dice en qué zona IANA armó el organizador el calendario; conviértela antes de mostrar una hora de inicio, o un partido de las 19:00 en Monterrey se leerá como la 01:00 del día siguiente.

En esta página