> ## Documentation Index
> Fetch the complete documentation index at: https://vantsgg.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Documentación interna de VANTS, la plataforma de esports, escrita en español. Cubre siete repositorios de la organización de GitHub VANTSNET y dos de la cuenta feispla: el prototipo VANTSNET, que se llama igual que la organización, y vantsoport.
> Empieza por /mapa-del-codigo para saber qué repositorio y qué carpeta tocar, y consulta /glosario para los términos propios como pt_, mm_, RR, VANTS-BUS o VANTCALL.
> Cuando un componente existe en varios repositorios, estas páginas describen la versión de Vantsgames salvo que digan otra cosa. El esquema de la base de datos se versiona en VantsBasededatos.
> La web y la API pública están en https://vants.vants.workers.dev. Rutas y respuestas: /referencia/api-publica. Tablas y estados: /referencia/esquema-base-de-datos.
> No inventes rutas, tablas, comandos ni variables de entorno: si algo no aparece aquí, revisa el código del repositorio correspondiente.

# API pública

> Rutas, parámetros, respuestas y errores de la API JSON de VANTS: torneos, partidas, equipos, jugadores, artículos, búsqueda, clips e inscripciones.

La web de VANTS expone una API JSON de lectura bajo `/api/`. Es la misma que usa la propia web para mostrar torneos, partidas, equipos y artículos. Los ejemplos usan el dominio de producción, `https://vants.vants.workers.dev`. El código está en `vants-server/worker.js` (rutas) y `vants-server/plataforma-core.js` (validación, orden y paginación) de [Vantsgames](https://vantsgg.mintlify.site/repos/vantsgames.md).

> [!NOTE]
>
> Los registros con `is_demo: true` son datos de demostración. Su nombre empieza por `DEMO ·` y sirven para validar la plataforma.

## Reglas generales

| Regla | Detalle |
| - | - |
| Método | Solo `GET`. Cualquier otro método recibe `405`. |
| Formato | JSON en UTF-8. |
| Origen | Si la petición trae una cabecera `Origin` que no es de un dominio de VANTS, recibe `403`. Las peticiones sin `Origin` (curl, scripts, servidores) se aceptan. |
| User-Agent | Envía siempre un `User-Agent` descriptivo. Sin él, la protección contra bots responde `403`. |
| Límite de uso | Hay un límite de peticiones por IP. Al superarlo recibes `429` y la cabecera `Retry-After` con los segundos de espera. |
| Caché | Las respuestas correctas llevan `Cache-Control: public, max-age=60`. Los errores llevan `no-store`. |

```bash theme={null}
curl -s "https://vants.vants.workers.dev/api/games" \
  -H "User-Agent: mi-app/1.0"
```

## Formato de respuesta

Una respuesta correcta lleva `ok: true` y los datos en `data`:

```json theme={null}
{ "ok": true, "data": [] }
```

Un error lleva `ok: false` y un texto en `error.message`:

```json theme={null}
{ "ok": false, "error": { "message": "estado debe ser upcoming, ongoing o archive" } }
```

| Código | Cuándo ocurre |
| - | - |
| `200` | La petición se resolvió. |
| `400` | Parámetro inválido. Hoy también lo devuelve un equipo o jugador que no existe: distingue el caso con `error.message`. |
| `403` | `Origin` no permitido, o `User-Agent` ausente o bloqueado. |
| `404` | El torneo pedido no existe, o la ruta no existe. |
| `405` | Método distinto de `GET`. |
| `429` | Superaste el límite de peticiones. Espera los segundos de `Retry-After`. |
| `500` | Error interno. |

> [!NOTE]
>
> Si el origen de datos no responde, recibes `400` con el mensaje `Datos no disponibles (proxy <código>)`. Reintenta pasado un momento.

## Rutas de lectura

| Ruta | Descripción |
| - | - |
| `GET /api/games` | Juegos activos. |
| `GET /api/tournaments` | Lista paginada de torneos por estado. |
| `GET /api/tournaments/:slug` | Ficha de un torneo con sus equipos confirmados. |
| `GET /api/matches` | Lista paginada de partidas por estado. |
| `GET /api/teams` | Lista de equipos, hasta 50. |
| `GET /api/teams/:slug` | Ficha de un equipo con plantilla y partidas. |
| `GET /api/players` | Ranking de perfiles VANTS, 50 por página. |
| `GET /api/players/:slug` | Ficha de un jugador de la plataforma de torneos. |
| `GET /api/articles` | Artículos publicados, 20 por página. |
| `GET /api/search` | Búsqueda en torneos, equipos, artículos y jugadores. |

Los slugs usan letras minúsculas, números y guiones. Los de equipo y jugador tienen entre 2 y 64 caracteres.

### Juegos

`GET /api/games` no admite parámetros. Usa el campo `slug` como valor del parámetro `juego` en el resto de rutas.

```json theme={null}
{
  "ok": true,
  "data": [
    { "slug": "valorant", "nombre": "VALORANT", "corto": "VALORANT", "logo_url": null, "color": null, "activo": true },
    { "slug": "cs2", "nombre": "COUNTER-STRIKE 2", "corto": "CS2", "logo_url": null, "color": null, "activo": true }
  ]
}
```

### Torneos

`GET /api/tournaments`

| Parámetro | Por defecto | Descripción |
| - | - | - |
| `estado` | `upcoming` | `upcoming` (próximos), `ongoing` (en curso) o `archive` (finalizados). |
| `juego` | todos | Slug de un juego, por ejemplo `valorant`. |
| `region` | todas | Región de 2 a 8 letras o números, por ejemplo `LATAM`. No distingue mayúsculas. |
| `pag` | `1` | Página, de 1 a 500. |
| `porPagina` | `12` | Resultados por página, de 1 a 50. |

Un número fuera de rango se ajusta al límite más cercano. Un `estado`, `juego` o `region` inválido devuelve `400`. Los próximos y en curso se ordenan por fecha de inicio ascendente. Los finalizados, descendente.

```bash theme={null}
curl -s "https://vants.vants.workers.dev/api/tournaments?estado=upcoming&juego=valorant&porPagina=5" \
  -H "User-Agent: mi-app/1.0"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "pag": 1,
    "porPagina": 5,
    "total": 1,
    "items": [
      {
        "slug": "demo-copa-comunidad-s5",
        "nombre": "DEMO · Copa Comunidad S5",
        "descripcion": "Torneo de demostración para validar la plataforma.",
        "game": { "slug": "valorant", "nombre": "VALORANT" },
        "estado": "upcoming",
        "major": false,
        "region": "LATAM",
        "location_type": "online",
        "prize": { "value": 500, "currency": "USD" },
        "fee": 0,
        "max_teams": 16,
        "starts_at": "2026-11-08T15:39:27.319Z",
        "ends_at": "2026-11-12T15:39:27.319Z",
        "logo_url": null,
        "formato": "Eliminación simple · Bo1",
        "source": "demo",
        "is_demo": true
      }
    ]
  }
}
```

| Campo | Descripción |
| - | - |
| `slug` | Identificador del torneo para URLs. |
| `nombre`, `descripcion` | Textos del torneo. `descripcion` puede ser `null`. |
| `game` | Objeto con el `slug` y el `nombre` del juego. |
| `estado` | `upcoming`, `ongoing`, `finished` o `cancelled`. |
| `major` | `true` si es un torneo major. |
| `region` | Región, por ejemplo `LATAM`, o `null`. |
| `location_type` | `online`, `lan` o `null`. |
| `prize` | Objeto con `value` y `currency`, o `null` si no hay premio. |
| `fee` | Cuota de inscripción. `0` si es gratis. |
| `max_teams` | Máximo de equipos, o `null`. |
| `starts_at`, `ends_at` | Fechas en formato ISO 8601 (UTC), o `null`. |
| `logo_url` | URL del logo, o `null`. |
| `formato` | Descripción del formato, o `null`. |
| `source` | Origen del dato: `vants`, `faceit` o `demo`. |
| `is_demo` | `true` si es un dato de demostración. |

> [!NOTE]
>
> El filtro usa `archive`, pero el campo `estado` de un torneo finalizado devuelve `finished`. Además, en torneos y partidas el campo `pag` de la respuesta devuelve hoy `1` aunque pidas otra página. Usa el valor que enviaste. El campo `total` sí es el total de resultados.

#### Ficha de un torneo

`GET /api/tournaments/:slug` devuelve los mismos campos que la lista y añade `participantes`: los equipos con inscripción confirmada.

```json theme={null}
{
  "ok": true,
  "data": {
    "slug": "demo-copa-comunidad-s5",
    "nombre": "DEMO · Copa Comunidad S5",
    "estado": "upcoming",
    "participantes": [
      { "name": "Equipo Ejemplo", "tag": "EJE", "captain": "Capitán", "region": "LATAM", "game": "valorant" }
    ]
  }
}
```

El ejemplo omite el resto de campos del torneo. Si el slug no existe, responde `404` con el mensaje `Torneo no encontrado`.

### Partidas

`GET /api/matches`

| Parámetro | Por defecto | Descripción |
| - | - | - |
| `estado` | `upcoming` | `live` (en vivo), `upcoming` (próximas) o `finished` (terminadas). |
| `juego` | todos | Slug de un juego. |
| `pag` | `1` | Página, de 1 a 500. |
| `porPagina` | `12` | Resultados por página, de 1 a 50. |

Las próximas se ordenan de la más cercana a la más lejana. Las demás, de la más reciente a la más antigua.

```json theme={null}
{
  "ok": true,
  "data": {
    "pag": 1,
    "porPagina": 12,
    "total": 1,
    "items": [
      {
        "game": { "slug": "valorant", "nombre": "VALORANT" },
        "tournament_slug": "6f1f2b0e-1c4d-4e57-9a3b-0d2c5e8a7b11",
        "equipos": { "a": "DEMO · Equipo Lobo", "b": "DEMO · Equipo Fénix" },
        "score": null,
        "estado": "upcoming",
        "best_of": 1,
        "empieza_at": "2026-10-19T17:39:27.392Z",
        "is_demo": true
      }
    ]
  }
}
```

| Campo | Descripción |
| - | - |
| `equipos` | Nombres de los dos equipos, `a` y `b`. |
| `score` | Objeto con `a` y `b` cuando hay resultado, o `null`. |
| `estado` | `upcoming`, `live`, `finished` o `cancelled`. |
| `best_of` | Serie al mejor de N mapas (por ejemplo `3` para Bo3), o `null`. |
| `empieza_at` | Fecha de inicio en formato ISO 8601 (UTC), o `null`. |
| `tournament_slug` | Hoy contiene el identificador interno (UUID) del torneo, no su slug. No sirve para pedir `/api/tournaments/:slug`. |

### Equipos

`GET /api/teams` devuelve hasta 50 equipos ordenados por nombre, sin paginación. Acepta el parámetro opcional `juego`.

```json theme={null}
{
  "ok": true,
  "data": [
    { "slug": "demo-equipo-fenix", "nombre": "DEMO · Equipo Fénix", "tag": "FNX", "game": "valorant", "region": "LATAM", "logo_url": null, "is_demo": true }
  ]
}
```

`GET /api/teams/:slug` devuelve la ficha del equipo con dos listas añadidas:

* `plantilla`: hasta 30 jugadores, ordenados por nombre.
* `partidas`: las más recientes primero, hasta 20 como equipo A y 20 como equipo B.

```json theme={null}
{
  "ok": true,
  "data": {
    "slug": "demo-equipo-fenix",
    "nombre": "DEMO · Equipo Fénix",
    "tag": "FNX",
    "game": { "slug": "valorant", "nombre": "VALORANT" },
    "region": "LATAM",
    "logo_url": null,
    "source": null,
    "is_demo": true,
    "plantilla": [
      {
        "slug": "demo-jugador-alex",
        "nombre": "DEMO · Alex",
        "game": { "slug": "valorant", "nombre": "VALORANT" },
        "team_slug": "demo-equipo-fenix",
        "rol": "IGL",
        "pais": "VE",
        "bio": null,
        "source": "demo",
        "is_demo": true
      }
    ],
    "partidas": []
  }
}
```

> [!NOTE]
>
> En la lista, `game` es el slug del juego (texto). En la ficha, `game` es un objeto con `slug` y `nombre`.

### Jugadores

`GET /api/players` devuelve los perfiles VANTS ordenados por `rating` de mayor a menor, 50 por página. Acepta `pag` (de 1 a 500). Solo expone campos públicos: nunca incluye correo ni datos de contacto o de autenticación.

```json theme={null}
{
  "ok": true,
  "data": {
    "pag": 1,
    "items": [
      {
        "id": "b1c2d3e4-0000-4000-8000-000000000001",
        "role": "jugador",
        "is_demo": false,
        "display_name": "NickEjemplo",
        "rating": 0.72,
        "region": "LATAM"
      }
    ],
    "total": 1
  }
}
```

`GET /api/players/:slug` devuelve la ficha de un jugador de la plataforma de torneos: `slug`, `nombre`, `game`, `team_slug`, `rol`, `pais`, `bio`, `source` e `is_demo`. Si el jugador tiene equipo, añade `equipo` con los datos de ese equipo, con el mismo formato que la ficha de equipo sin las listas.

> [!NOTE]
>
> La lista sale de los perfiles VANTS y la ficha por slug, de los jugadores de la plataforma de torneos. Son conjuntos distintos, así que un perfil de la lista puede no tener ficha.

### Artículos

`GET /api/articles` devuelve los artículos publicados, del más reciente al más antiguo, 20 por página.

| Parámetro | Por defecto | Descripción |
| - | - | - |
| `pag` | `1` | Página, de 1 a 500. |
| `juego` | todos | Slug de un juego. |

```json theme={null}
{
  "ok": true,
  "data": {
    "pag": 1,
    "items": [
      {
        "slug": "demo-calendario-s5",
        "titulo": "DEMO · Calendario de la Temporada 5",
        "resumen": "Artículo de demostración con el calendario previsto de la temporada.",
        "autor": "VANTS",
        "game": "cs2",
        "publicado_at": "2026-10-09T16:10:57.064Z",
        "is_demo": true
      }
    ],
    "total": 1
  }
}
```

La lista no incluye el cuerpo del artículo. La ficha de un artículo no está disponible por API todavía.

### Búsqueda

`GET /api/search?q=texto` busca en torneos, equipos, artículos y jugadores. Devuelve hasta 8 resultados por tipo.

| Parámetro | Descripción |
| - | - |
| `q` | Obligatorio. Entre 2 y 64 caracteres. No admite `%`, `_`, `;` ni la barra invertida. |

```bash theme={null}
curl -s "https://vants.vants.workers.dev/api/search?q=lobo" \
  -H "User-Agent: mi-app/1.0"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "q": "lobo",
    "torneos": [],
    "equipos": [
      { "slug": "demo-equipo-lobo", "nombre": "DEMO · Equipo Lobo", "tag": "LBO", "game_slug": "valorant", "is_demo": true }
    ],
    "articulos": [],
    "jugadores": []
  }
}
```

La búsqueda de `jugadores` cubre un conjunto limitado de perfiles, así que no es exhaustiva.

## Rutas de la web

La web usa además rutas propias bajo `/api/`. Las que piden sesión necesitan la cabecera `Authorization: Bearer <token de acceso>` de un usuario con la sesión iniciada y un `Origin` de un dominio de VANTS. Sus errores tienen la forma `{ "ok": false, "error": "codigo" }`, distinta de la de las rutas de lectura.

| Ruta | Método | Sesión | Descripción |
| - | - | - | - |
| `/api/health` y `/healthz` | GET | No | Comprobación de estado del servicio. |
| `/api/en-vivo` | GET | No | Jugadores conectados ahora (presencia de los últimos 2 minutos), hasta 50. Caché de 10 s. Si la base no responde devuelve `ok: false` y `jugadores: []`. |
| `/api/torneos/bracket?torneo=<id>` | GET | No | Equipos y cuadro de un torneo de la web. `id`: de 1 a 40 letras, números, `_` o `-`. Caché de 15 s. Sin datos devuelve `ok: false` con `motivo: sin_datos`. |
| `/api/valorant/esports` | GET | No | Calendario de esports de VALORANT desde un proveedor externo. Caché de 5 minutos. Puede devolver `503`. |
| `/api/gpr` | GET | No | Global Power Rankings de Riot: `calculated`, `total` y `regions`. Caché de 1 hora. Devuelve `502` si falla la fuente. |
| `/api/faceit/usuario?nick=<nick>` | GET | No | Perfil FACEIT: id, nickname, país, avatar, nivel, región, elo y fecha de alta. Caché de 60 s. |
| `/api/faceit/historia?nick=<nick>` | GET | No | Hasta 10 partidas recientes de CS2 y un `resumen` con jugadas, victorias, winrate, K/D, HS, MVP, nivel y elo. Caché de 120 s. |
| `/api/teams-live` | GET | No | Heredada. Equipos inscritos y campeones. Úsala solo si ya dependes de ella. |
| `/api/clips/featured` | GET | No | Clips destacados. Caché de 60 s. |
| `/api/clips/featured` | POST | Sí | Sube un clip. |
| `/api/clips/featured?id=<clip>` | DELETE | Sí | Borra un clip. Solo puede hacerlo su autor. |
| `/api/torneos/inscribir` | POST | Sí | Inscribe un equipo en un torneo. |
| `/api/account/perfil` | GET, POST | Sí | Lee y actualiza el nick de la cuenta y las redes conectadas. |

El parámetro `nick` de FACEIT tiene entre 2 y 24 caracteres: letras, números, `_`, `.` o `-`. Un nick inválido devuelve `400` con `nick_invalido`, y uno que no existe, `404` con `no_encontrado`.

### Clips destacados

`GET /api/clips/featured` devuelve `clips`, hasta 60 entradas. Cada clip incluye, entre otros, `id`, `nick`, `username`, `titulo`, `juego`, `ext`, `fecha`, `dur`, `tam`, `video` y `thumb`. Los vídeos, las miniaturas y el índice se guardan en [vants-clips](https://vantsgg.mintlify.site/repos/vants-clips.md).

`POST` recibe un formulario `multipart/form-data` con estos campos: `video`, `thumb`, `titulo`, `juego`, `nick`, `username`, `dur` y `ext`.

| Límite | Valor |
| - | - |
| Tamaño del vídeo | 48 MB |
| Tamaño de la miniatura | 400 KB |
| Extensiones | `webm`, `mp4`, `mkv`, `mov` y `m4v` |
| Clips guardados | 60. Al superarlo, se descartan los más antiguos. |

Si el `id` de un `DELETE` no existe devuelve `404` con `no_existe`, y si el clip es de otro usuario, `403` con `no_es_tuyo`.

### Inscribir un equipo

`POST /api/torneos/inscribir` crea una inscripción con estado `pendiente`. Recibe un cuerpo JSON:

| Campo | Obligatorio | Descripción |
| - | - | - |
| `torneo` | Sí | Identificador del torneo: de 1 a 40 letras, números, `_` o `-`. |
| `juego` | No | `cs2` o `valorant`. Cualquier otro valor se trata como `valorant`. |
| `equipo` | Sí | Nombre del equipo, de 2 a 32 caracteres. Se limpian `<`, `>` y las comillas invertidas. |
| `tag` | Sí | Etiqueta de 2 a 4 caracteres alfanuméricos. Se descartan los demás. |
| `capitan` | No | Nombre del capitán, hasta 40 caracteres. |
| `region` | No | Región, hasta 40 caracteres. |

Si todo va bien, responde `200` con `ok: true` y, en `equipo`, el registro creado con `status` igual a `pendiente`. Estos son los errores posibles:

| Código | `error` | Causa |
| - | - | - |
| `400` | `torneo_invalido` | `torneo` no cumple el formato. |
| `400` | `datos_invalidos` | `equipo` o `tag` quedan con menos de 2 caracteres. |
| `401` | `sin_sesion` o `token_invalido` | Falta el token o no es válido. |
| `403` | `Origen no permitido` | El `Origin` falta o no es de un dominio de VANTS. |
| `405` | `Solo POST` | Método distinto de `POST`. |
| `409` | `equipo_ya_inscrito` | Ese equipo ya está inscrito en el torneo. |
| `429` | `Demasiadas peticiones` | Superaste el límite de peticiones. |
| `502` | `base_inaccesible` o `base_rechazo` | La base de datos no respondió o rechazó el registro. |

## Más información

* [Vantsgames](https://vantsgg.mintlify.site/repos/vantsgames.md): estructura del Worker y despliegue.
* [Seguridad](https://vantsgg.mintlify.site/referencia/seguridad.md): protecciones de la API y de la plataforma.
* [Esquema de la base de datos](https://vantsgg.mintlify.site/referencia/esquema-base-de-datos.md): tablas que alimentan esta API.
* [Arquitectura](https://vantsgg.mintlify.site/arquitectura.md): cómo encajan los componentes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.