# TikTok Archives API v1

Acceso programático a perfiles de TikTok (datos, región, nivel de regalos), listas de videos,
reposts, seguidores y seguidos, búsqueda, comentarios, descargas de videos/sliders/audios,
historias y directos (estado, chat y video en tiempo real, clips y avisos de inicio/fin).

- Base URL: `https://geometryamerica.xyz/api/v1/<método>`
- Documentación interactiva (HTML): https://geometryamerica.xyz/api
- Este archivo se genera automáticamente desde la página, así que siempre está al día.

## Autenticación

Todas las peticiones a `/api/v1/` requieren una API key (empiezan por `ga_`). Se crea con una
cuenta de la web en https://geometryamerica.xyz/api (sección "Tu panel"). Se envía de una de estas formas:

| Forma | Ejemplo |
|---|---|
| Header (recomendado) | `Authorization: Bearer ga_…` |
| Header alternativo | `X-API-Key: ga_…` |
| Parámetro | `?key=ga_…` (para `EventSource` y reproductores de video, que no pueden enviar headers) |

Trata la key como una contraseña: no la pongas en el código de una web pública ni en repositorios.

## Formato de respuesta

Todas las respuestas JSON tienen la misma estructura:

```json
{ "ok": true, "method": "getProfileInfo", "data": { }, "usage": { "used": 12, "limit": 100, "remaining": 88, "resetsAt": "2026-10-05T00:00:00Z" } }
```

En caso de error, `ok` es `false` y `error.code` identifica la causa:

```json
{ "ok": false, "error": { "code": "not_live", "message": "@usuario no esta en directo ahora mismo." }, "usage": { } }
```

| HTTP | code | Significado |
|---|---|---|
| 400 | `bad_request` | Falta un parámetro o no es válido. |
| 401 | `missing_key`, `invalid_key` | No se envió la key, o es incorrecta o está revocada. |
| 404 | `not_found`, `not_live` | El recurso no existe, o el usuario no está en directo. |
| 409 | `limit_reached`, `duplicate` | Máximo de callbacks alcanzado, o el callback ya existe. |
| 410 | `expired_link` | El enlace de descarga caducó; vuelve a llamar a `downloadTT`. |
| 429 | `daily_limit`, `too_many_streams` | Cuota diaria agotada, o 3 conexiones abiertas. |
| 502 | `upstream_error` | TikTok no respondió. Reintenta en unos segundos. |
| 503 | `busy` | El servidor tiene demasiados directos abiertos a la vez. |

## Límites y cuota

- **100 peticiones al día por cuenta** (todas tus keys comparten la cuota). Se reinicia a las 00:00 UTC.
- Solo cuentan las respuestas correctas (2xx); los errores no consumen cuota.
- `getLiveChat` y `getLiveBuffer` cuentan 1 al conectar y 1 más por cada hora abierta.
- Máximo **3 conexiones abiertas** a la vez por cuenta (chat, stream, `liveEvents` y clips de `downloadLive`).
- Hasta **10 keys** activas y **10 callbacks** por cuenta. Los avisos por callback no consumen cuota;
  con `liveEvents` conectarse es gratis y cada aviso entregado cuenta 1.
- Los enlaces que devuelve `downloadTT` son válidos 6 horas y no consumen cuota.
- Cada respuesta trae el consumo en `usage` y en los headers `X-RateLimit-Limit`,
  `X-RateLimit-Remaining` y `X-RateLimit-Reset`.

## Métodos (25)

- **Perfiles**: `getProfileInfo`, `getProfileById`, `getProfileRegion`, `getProfileFullInfo`
- **Listas del perfil**: `getPosts`, `getReposts`, `getFollowers`, `getFollowing`
- **Búsqueda**: `search`, `searchUsers`
- **Comentarios**: `getComments`, `getCommentReplies`
- **Contenido**: `downloadTT`
- **Directos**: `getLiveInfo`, `getLiveTime`, `getLiveHearts`, `getLiveChat`, `getLiveBuffer`, `downloadLive`, `liveCallback`, `liveEvents`
- **Publicaciones nuevas**: `postCallback`, `postEvents`
- **Historias**: `getHistories`, `downloadHistories`

## Perfiles

### getProfileInfo

`GET` `/api/v1/getProfileInfo`

Datos públicos de un perfil: nombre, biografía, avatar, verificación y estadísticas.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getProfileInfo?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "username": "tiktok",
  "nickname": "TikTok",
  "bio": "Make Your Day",
  "avatar": "https://p16-sign.tiktokcdn.com/…",
  "verified": true,
  "userId": "107955",
  "secUid": "MS4wLjABAAAAv7iSuuXD…",
  "url": "https://www.tiktok.com/@tiktok",
  "stats": {
    "followers": 91800000,
    "following": 12,
    "likes": 450000000,
    "videos": 1200
  }
}
```

### getProfileById

`GET` `/api/v1/getProfileById`

Igual que getProfileInfo, buscando por el ID numérico de la cuenta.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `id` | string | sí | ID numérico de TikTok (userId). Ejemplo: `107955`. |

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getProfileById?id=107955" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "username": "tiktok",
  "nickname": "TikTok",
  "userId": "107955",
  "verified": true,
  "stats": {
    "followers": 91800000,
    "following": 12,
    "likes": 450000000
  }
}
```

### getProfileRegion

`GET` `/api/v1/getProfileRegion`

País o región de la cuenta, como código ISO de dos letras.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getProfileRegion?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "username": "tiktok",
  "region": "US"
}
```

### getProfileFullInfo

`GET` `/api/v1/getProfileFullInfo`

Perfil completo: datos públicos, región, nivel de regalos, tipo de cuenta y categoría, verificación, fechas de creación y de cambio de nombre, si es privada y si está en directo.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |

- `giftLevel` es el nivel de regalos (gifter level) de la cuenta, también si lo tiene oculto. `accountType` es `personal`, `creador` o `empresa`. `category` viene en español y `categoryEn` en inglés.
- `liveSubscriptionEligible`: habilitada para suscripciones de LIVE. `creatorMarketplace`: dada de alta en el Creator Marketplace. `followingHidden`: oculta su lista de seguidos.
- Los campos que TikTok no da para esa cuenta vienen como `null`.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getProfileFullInfo?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "username": "tiktok",
  "nickname": "TikTok",
  "verified": true,
  "region": "US",
  "private": false,
  "accountCreated": "2015-08-24 10:00:00",
  "nicknameModified": "2023-05-02 12:00:00",
  "giftLevel": 0,
  "accountType": "empresa",
  "category": "Otros",
  "categoryEn": "Others",
  "verifiedText": "Cuenta verificada",
  "liveSubscriptionEligible": true,
  "creatorMarketplace": false,
  "followingHidden": false,
  "bioTranslation": null,
  "profileModified": "2026-11-06 13:34:22",
  "stats": {
    "followers": 91800000,
    "following": 12,
    "likes": 450000000,
    "videos": 1200
  },
  "isLive": false,
  "live": null
}
```

## Listas del perfil

### getPosts

`GET` `/api/v1/getPosts`

Videos publicados por el perfil, paginados.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |
| `count` | número | no | Resultados por página (máx 50, por defecto 30). Ejemplo: `30`. |
| `cursor` | número | no | Cursor de paginación: el `cursor` que devuelve la respuesta anterior. Por defecto 0. Ejemplo: `0`. |
| `secUid` | string | no | secUid del perfil, para saltarse la resolución del usuario (más rápido). |

- Pagina con el `cursor` que devuelve la respuesta.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getPosts?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "username": "tiktok",
  "secUid": "MS4wLjABAAAA…",
  "count": 30,
  "hasMore": true,
  "cursor": "1700000000000",
  "videos": [
    {
      "aweme_id": "7542001496599072055",
      "desc": "texto del video",
      "author": "tiktok",
      "nick": "TikTok",
      "plays": 2100000,
      "diggs": 120000,
      "comments": 3000,
      "shares": 900,
      "create_time": 1700000000,
      "duration": 15,
      "cover": "https://…",
      "url": "https://www.tiktok.com/@tiktok/video/7542001496599072055"
    }
  ]
}
```

### getReposts

`GET` `/api/v1/getReposts`

Videos que el perfil ha reposteado.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |
| `count` | número | no | Resultados por página (máx 50, por defecto 30). Ejemplo: `30`. |
| `offset` | número | no | Desplazamiento de paginación: el `offset` de la respuesta anterior. Por defecto 0. Ejemplo: `0`. |
| `secUid` | string | no | secUid del perfil, para saltarse la resolución del usuario (más rápido). |

- Pagina con el `offset` que devuelve la respuesta.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getReposts?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "username": "tiktok",
  "secUid": "MS4wLjABAAAA…",
  "count": 12,
  "hasMore": true,
  "offset": 12,
  "videos": [
    {
      "aweme_id": "7663274106892193054",
      "desc": "",
      "author": "otro",
      "nick": "Otro",
      "plays": 258199,
      "create_time": 1700000000,
      "cover": "https://…",
      "url": "https://www.tiktok.com/@otro/video/7663274106892193054"
    }
  ]
}
```

### getFollowers

`GET` `/api/v1/getFollowers`

Lista de seguidores del perfil, paginada.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |
| `count` | número | no | Resultados por página (máx 50, por defecto 30). Ejemplo: `30`. |
| `cursor` | número | no | Cursor de paginación: el `cursor` que devuelve la respuesta anterior. Por defecto 0. Ejemplo: `0`. |
| `secUid` | string | no | secUid del perfil, para saltarse la resolución del usuario (más rápido). |

- Pagina con el `cursor` que devuelve la respuesta.
- `total` es el total de seguidores (TikTok no lista cuentas privadas/eliminadas).

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getFollowers?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "username": "tiktok",
  "secUid": "MS4wLjABAAAA…",
  "count": 30,
  "hasMore": true,
  "cursor": 1700000000,
  "total": 91800000,
  "users": [
    {
      "unique_id": "user1",
      "nick": "User",
      "sec_uid": "MS4wLjABAAAA…",
      "uid": "6812345678901234567",
      "avatar": "https://…",
      "followers": 1200,
      "signature": "bio"
    }
  ]
}
```

### getFollowing

`GET` `/api/v1/getFollowing`

Lista de cuentas que el perfil sigue, paginada.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |
| `count` | número | no | Resultados por página (máx 50, por defecto 30). Ejemplo: `30`. |
| `cursor` | número | no | Cursor de paginación: el `cursor` que devuelve la respuesta anterior. Por defecto 0. Ejemplo: `0`. |
| `secUid` | string | no | secUid del perfil, para saltarse la resolución del usuario (más rápido). |

- Pagina con el `cursor` que devuelve la respuesta.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getFollowing?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "username": "tiktok",
  "secUid": "MS4wLjABAAAA…",
  "count": 12,
  "hasMore": false,
  "cursor": 1700000000,
  "total": 12,
  "users": [
    {
      "unique_id": "user2",
      "nick": "User2",
      "sec_uid": "MS4wLjABAAAA…",
      "uid": "6812345678901234567",
      "avatar": "https://…"
    }
  ]
}
```

## Búsqueda

### search

`GET` `/api/v1/search`

Busca en TikTok: lista de videos y de usuarios para un texto.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `keyword` | string | sí | Texto a buscar (también se acepta `q`). Ejemplo: `bad bunny`. |
| `count` | número | no | Resultados por página (máx 50, por defecto 30). Ejemplo: `30`. |
| `offset` | número | no | Desplazamiento de paginación: el `offset` de la respuesta anterior. Por defecto 0. Ejemplo: `0`. |
| `withUsers` | bool | no | Incluir la lista de usuarios (por defecto sí). `0` para solo videos. Ejemplo: `1`. |

- Pagina los videos con `offset`.
- Cada video trae `author`, `plays`, `cover` y `url`; cada usuario, `unique_id`, `sec_uid` y `followers`.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/search?keyword=bad%20bunny" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "keyword": "bad bunny",
  "count": 15,
  "hasMore": true,
  "cursor": 15,
  "videos": [
    {
      "aweme_id": "7694119174263672082",
      "desc": "…",
      "author": "jaem20_06",
      "nick": "Jae",
      "author_uid": "68…",
      "plays": 35600,
      "diggs": 1200,
      "comments": 30,
      "cover": "https://…",
      "url": "https://www.tiktok.com/@jaem20_06/video/7694119174263672082"
    }
  ],
  "users": [
    {
      "unique_id": "badbunny",
      "nick": "Bad Bunny",
      "uid": "7047450743465477126",
      "sec_uid": "MS4wLjABAAAA…",
      "avatar": "https://…",
      "followers": 41381895,
      "verified": true
    }
  ]
}
```

### searchUsers

`GET` `/api/v1/searchUsers`

Busca solo usuarios (la pestaña de cuentas).

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `keyword` | string | sí | Texto a buscar (también se acepta `q`). Ejemplo: `bad bunny`. |
| `count` | número | no | Resultados por página (máx 50, por defecto 30). Ejemplo: `30`. |
| `offset` | número | no | Desplazamiento de paginación: el `offset` de la respuesta anterior. Por defecto 0. Ejemplo: `0`. |

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/searchUsers?keyword=bad%20bunny" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "keyword": "bad bunny",
  "count": 12,
  "hasMore": true,
  "cursor": 12,
  "users": [
    {
      "unique_id": "badbunny",
      "nick": "Bad Bunny",
      "uid": "7047450743465477126",
      "sec_uid": "MS4wLjABAAAA…",
      "avatar": "https://…",
      "followers": 41381895,
      "signature": "…",
      "verified": true
    }
  ]
}
```

## Comentarios

### getComments

`GET` `/api/v1/getComments`

Comentarios de un video, paginados. Se obtienen de la app de TikTok (todos, con stickers); si falla, de la web.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `videoId` | string | sí | ID del video o su enlace de TikTok. Ejemplo: `7542001496599072055`. |
| `count` | número | no | Resultados por página (máx 50, por defecto 30). Ejemplo: `30`. |
| `cursor` | número | no | Cursor de paginación: el `cursor` que devuelve la respuesta anterior. Por defecto 0. Ejemplo: `0`. |

- Pagina con el `cursor` que devuelve la respuesta.
- `repliesCount` es cuántas respuestas tiene el comentario (usa getCommentReplies).
- `media` es el sticker (WebP animado) o la imagen del comentario: `{ url, w, h, kind }`, o `null`.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getComments?videoId=7542001496599072055" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "videoId": "7542001496599072055",
  "count": 20,
  "hasMore": true,
  "cursor": 20,
  "total": 1530,
  "comments": [
    {
      "id": "7542216140531041031",
      "text": "buen video",
      "likes": 42,
      "createTime": 1700000000,
      "repliesCount": 2,
      "author": {
        "uid": "68…",
        "username": "user1",
        "nickname": "User",
        "avatar": "https://…",
        "secUid": "MS4wLjABAAAA…"
      }
    }
  ]
}
```

### getCommentReplies

`GET` `/api/v1/getCommentReplies`

Respuestas de un comentario.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `videoId` | string | sí | ID del video o su enlace de TikTok. Ejemplo: `7542001496599072055`. |
| `commentId` | string | sí | ID del comentario (el campo `id` de getComments). Ejemplo: `7542216140531041031`. |
| `count` | número | no | Resultados por página (máx 50, por defecto 30). Ejemplo: `30`. |
| `cursor` | número | no | Cursor de paginación: el `cursor` que devuelve la respuesta anterior. Por defecto 0. Ejemplo: `0`. |

- Cada respuesta trae `media` igual que getComments (stickers e imágenes).

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getCommentReplies?videoId=7542001496599072055&commentId=7542216140531041031" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "videoId": "7542001496599072055",
  "commentId": "7542216140531041031",
  "count": 2,
  "hasMore": false,
  "cursor": 2,
  "replies": [
    {
      "id": "7542300000000000000",
      "text": "de acuerdo",
      "likes": 3,
      "createTime": 1700000100,
      "repliesCount": 0,
      "author": {
        "uid": "68…",
        "username": "user2",
        "nickname": "User2",
        "avatar": "https://…",
        "secUid": "MS4wLjABAAAA…"
      }
    }
  ]
}
```

## Contenido

### downloadTT

`GET` `/api/v1/downloadTT`

Descarga de videos, sliders (fotos) y audios. Devuelve los datos de la publicación y enlaces de descarga válidos durante 6 horas.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `url` | string | sí | Enlace de TikTok: video, foto o slider, sonido (`/music/…`), enlace corto `vm.tiktok.com` / `vt.tiktok.com` o enlace de un comentario compartido. Ejemplo: `https://www.tiktok.com/@tiktok/video/7106594312292453675`. |

- `type` es `video`, `slideshow` o `audio`.
- Los videos se entregan en la mayor calidad disponible.
- Con `type: video`, `audioDownload` descarga solo el audio del video (.m4a, la pista original sin recodificar). `music.download` es el sonido de TikTok que usa el video, que en canciones con derechos puede ser un recorte.
- Con un enlace de sonido (`type: audio`) la respuesta trae `title`, `author`, `duration`, `videoCount` (videos que usan el sonido), `cover` y `download`.
- Si el enlace se compartió desde un comentario, `sharedComment` trae ese comentario (mismo formato que getComments, con `replyTo` si es una respuesta), o `null` si no se pudo obtener.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/downloadTT?url=https%3A%2F%2Fwww.tiktok.com%2F%40tiktok%2Fvideo%2F7106594312292453675" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "id": "7106594312292453675",
  "type": "video",
  "author": {
    "username": "tiktok",
    "nickname": "TikTok"
  },
  "description": "…",
  "createdAt": "2022-06-06T15:00:00Z",
  "stats": {
    "likes": 120000,
    "comments": 3000,
    "shares": 900,
    "plays": 2100000
  },
  "duration": 15,
  "width": 1080,
  "height": 1920,
  "cover": "https://…",
  "download": "https://geometryamerica.xyz/api/v1/media/gAAAAAB…",
  "audioDownload": "https://geometryamerica.xyz/api/v1/media/gAAAAAB…",
  "music": {
    "title": "sonido original",
    "author": "TikTok",
    "download": "https://geometryamerica.xyz/api/v1/media/gAAAAAB…"
  },
  "expiresAt": "2026-10-04T22:00:00Z"
}
```

## Directos

### getLiveInfo

`GET` `/api/v1/getLiveInfo`

Estado del directo y datos de la sala: título, portada, espectadores, inicio y orientaciones disponibles.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |

- Si no está en directo responde `{"isLive": false}`, y cuenta como petición.
- `likes` puede ser `null`: TikTok no siempre lo incluye en la ficha de la sala. Para el valor exacto, usa `getLiveHearts`.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getLiveInfo?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "isLive": true,
  "username": "usuario",
  "roomId": "7312345678901234567",
  "title": "Charlando un rato",
  "cover": "https://…",
  "startedAt": "2026-10-04T18:02:11Z",
  "elapsedSeconds": 2714,
  "viewers": 8231,
  "totalViewers": 40210,
  "likes": null,
  "owner": {
    "nickname": "Usuario",
    "avatar": "https://…",
    "userId": "6812…"
  },
  "orientations": [
    "v"
  ],
  "url": "https://www.tiktok.com/@usuario/live",
  "watchUrl": "https://geometryamerica.xyz/live/usuario"
}
```

### getLiveTime

`GET` `/api/v1/getLiveTime`

Tiempo transcurrido desde el inicio del directo.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getLiveTime?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "isLive": true,
  "username": "usuario",
  "startedAt": "2026-10-04T18:02:11Z",
  "elapsedSeconds": 2714,
  "elapsed": "45m 14s"
}
```

### getLiveHearts

`GET` `/api/v1/getLiveHearts`

Likes totales del directo y espectadores actuales, leídos en tiempo real.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |

- Puede tardar unos segundos si nadie más está viendo ese directo.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getLiveHearts?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "isLive": true,
  "username": "usuario",
  "likes": 412908,
  "viewers": 8231
}
```

### getLiveChat

`SSE` `/api/v1/getLiveChat`

Chat del directo en tiempo real mediante Server-Sent Events: mensajes, entradas, regalos, compartidos, likes y recuento de la sala.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |

- Cuenta 1 al conectar y 1 más por cada hora abierta.
- Al conectar se reciben los últimos eventos del chat.
- Eventos: `open`, `message`, `error` y `end`.
- `data.type`: `chat`, `join`, `gift`, `share`, `like` o `seq` (espectadores, likes totales y top 3).

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getLiveChat?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta:

```
// event: message
{ "type": "chat", "nick": "Pepe", "uid": "6812…", "avatar": "https://…", "text": "hola", "t": 2714.3 }

// event: message
{ "type": "seq", "viewers": 8231, "total_likes": 412908, "top": [ { "rank": 1, "score": 900, "nick": "Ana" } ] }
```

### getLiveBuffer

`GET` `/api/v1/getLiveBuffer`

Video del directo en tiempo real como stream FLV continuo. Compatible con VLC, ffmpeg y mpegts.js.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |
| `orientation` | v | h | no | Si el directo emite en vertical y horizontal a la vez, cuál recibir. Por defecto, el de mayor resolución. |

- Respuesta binaria `video/x-flv`.
- Cuenta 1 al conectar y 1 más por cada hora abierta.
- En el navegador, usa `?key=` con mpegts.js: los reproductores no envían headers.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getLiveBuffer?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta:

```
<stream FLV binario: video/x-flv>
```

### downloadLive

`GET` `/api/v1/downloadLive`

Graba un clip MP4 de los próximos segundos del directo.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |
| `seconds` | número | no | Duración del clip, de 5 a 60. Por defecto 15. Ejemplo: `15`. |
| `orientation` | v | h | no | Igual que en getLiveBuffer. |

- La respuesta tarda lo que dure el clip más unos segundos.
- Respuesta binaria `video/mp4` con `Content-Disposition: attachment`.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/downloadLive?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta:

```
<archivo MP4 binario: video/mp4>
```

### liveCallback

`GET · POST · DELETE` `/api/v1/liveCallback`

Avisos automáticos: se envía un POST a tu URL, o a tu webhook de Discord, cuando el usuario empieza o termina un directo.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | **POST**: usuario a vigilar. Ejemplo: `usuario`. |
| `url` | string | sí | **POST**: endpoint público (http/https) o webhook de Discord. Ejemplo: `https://tuservidor.com/aviso`. |
| `id` | número | sí | **DELETE**: id del callback a eliminar. |

- **GET** lista tus callbacks, **POST** crea uno y **DELETE** lo elimina.
- Al crearlo recibes un `secret` para verificar las firmas. Solo se muestra una vez.
- Máximo 10 por cuenta. Comprobación cada minuto. Ver formato de los avisos.

Ejemplo:

```bash
curl -X POST "https://geometryamerica.xyz/api/v1/liveCallback" \
  -H "Authorization: Bearer TU_API_KEY" -H "Content-Type: application/json" \
  -d '{"username": "usuario", "url": "https://tuservidor.com/aviso"}'
```

Respuesta (`data`):

```json
{
  "id": 4,
  "username": "usuario",
  "url": "https://tuservidor.com/aviso",
  "active": true,
  "createdAt": "2026-10-04T17:00:00Z",
  "lastEvent": null,
  "discord": false,
  "secret": "whsec_9fK2…",
  "note": "Guarda el secret…"
}
```

### liveEvents

`SSE` `/api/v1/liveEvents`

Avisos de inicio y fin de directo por Server-Sent Events. Alternativa a liveCallback para clientes sin servidor propio ni puertos abiertos: el cliente se conecta y recibe los avisos por la misma conexión.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `usernames` | string | sí | Usuarios a vigilar separados por comas, hasta 10. Ejemplo: `usuario1,usuario2`. |

- Conectarse no consume cuota: **cada aviso entregado cuenta 1**.
- Eventos: `open`, `state` (si cada usuario está en directo al conectar), `live_start`, `live_end` y `error`.
- Comprobación cada minuto. Ocupa una de las 3 conexiones simultáneas.
- El cuerpo de `live_start` y `live_end` es el mismo que el de los avisos de liveCallback.
- Si un usuario ya estaba en directo al conectar, recibes un `live_start` con `"ongoing": true` (los enviados al conectar son gratis). Usa `roomId` para no avisar dos veces del mismo directo.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/liveEvents?usernames=usuario1%2Cusuario2" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta:

```
// event: state
{ "isLive": { "usuario1": false, "usuario2": true } }

// event: live_start
{ "event": "live_start", "username": "usuario1", "roomId": "7312345678901234567", "title": "En vivo", "startedAt": "2026-10-04T18:02:11Z", "url": "https://www.tiktok.com/@usuario1/live", "sentAt": "2026-10-04T18:02:40Z" }
```

## Publicaciones nuevas

### postCallback

`GET · POST · DELETE` `/api/v1/postCallback`

Avisos automáticos cuando una cuenta sube un video o un carrusel de fotos: se envía un POST a tu URL o a tu webhook de Discord (con la portada).

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | **POST**: usuario a vigilar. Ejemplo: `usuario`. |
| `url` | string | sí | **POST**: endpoint público (http/https) o webhook de Discord. Ejemplo: `https://tuservidor.com/aviso`. |
| `id` | número | sí | **DELETE**: id del callback a eliminar. |

- **GET** lista tus callbacks de publicaciones, **POST** crea uno y **DELETE** lo elimina.
- El perfil se revisa **cada 2 minutos**. La primera revisión solo apunta lo que ya hay: avisa de lo que se publique después.
- Un video antiguo que se fija arriba del perfil no cuenta como nuevo.
- Mismo `secret` y firma `X-GA-Signature` que liveCallback. El máximo de 10 callbacks es para liveCallback y postCallback juntos.
- Crear el callback no gasta cuota: **cada aviso entregado cuenta 1**. Para descargar la publicación, pasa su `url` a downloadTT.
- Las cuentas privadas no se pueden vigilar.

Ejemplo:

```bash
curl -X POST "https://geometryamerica.xyz/api/v1/postCallback" \
  -H "Authorization: Bearer TU_API_KEY" -H "Content-Type: application/json" \
  -d '{"username": "usuario", "url": "https://tuservidor.com/aviso"}'
```

Respuesta:

```
// Aviso que llega a tu URL (header X-GA-Event: new_post)
{ "event": "new_post", "username": "usuario", "id": "7705603633437527327", "description": "Mi video nuevo #fyp", "cover": "https://…", "duration": 15, "createdAt": "2026-11-08T12:31:06Z", "url": "https://www.tiktok.com/@usuario/video/7705603633437527327", "stats": { "plays": 1200, "likes": 85, "comments": 4, "shares": 1 }, "callbackId": 7, "sentAt": "2026-11-08T12:33:40Z" }
```

### postEvents

`SSE` `/api/v1/postEvents`

Avisos de publicaciones nuevas por Server-Sent Events. Alternativa a postCallback para clientes sin servidor propio.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `usernames` | string | sí | Usuarios a vigilar separados por comas, hasta 10. Ejemplo: `usuario1,usuario2`. |

- Conectarse no consume cuota: **cada aviso entregado cuenta 1**.
- Eventos: `open`, `new_post` y `error`. El cuerpo de `new_post` es el mismo que el de postCallback.
- Revisión cada 2 minutos. Ocupa una de las 3 conexiones simultáneas.
- Si una cuenta no se estaba vigilando, la primera revisión solo apunta lo que ya hay.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/postEvents?usernames=usuario1%2Cusuario2" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta:

```
// event: new_post
{ "event": "new_post", "username": "usuario1", "id": "7705603633437527327", "description": "Mi video nuevo", "createdAt": "2026-11-08T12:31:06Z", "url": "https://www.tiktok.com/@usuario1/video/7705603633437527327", "sentAt": "2026-11-08T12:33:40Z" }
```

## Historias

### getHistories

`GET` `/api/v1/getHistories`

Historias activas del usuario (últimas 24 h), con tipo, portada y música.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/getHistories?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta (`data`):

```json
{
  "username": "usuario",
  "count": 2,
  "stories": [
    {
      "id": "7421…",
      "type": "video",
      "createdAt": "2026-10-04T10:00:00Z",
      "expiresAt": "2026-10-05T10:00:00Z",
      "duration": 9,
      "cover": "https://…",
      "hasAudio": true,
      "download": "https://geometryamerica.xyz/api/v1/downloadHistories?username=usuario&story_id=7421…"
    },
    {
      "id": "7421…",
      "type": "image",
      "imageCount": 3,
      "cover": "https://…",
      "hasAudio": true,
      "music": {
        "title": "Canción",
        "author": "Artista"
      }
    }
  ]
}
```

### downloadHistories

`GET` `/api/v1/downloadHistories`

Descarga una historia: el video, una de sus imágenes o su audio.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `username` | string | sí | Usuario de TikTok: `usuario`, `@usuario` o enlace del perfil. Ejemplo: `tiktok`. |
| `story_id` | string | sí | ID de la historia (de getHistories). |
| `index` | número | no | En historias con imágenes, cuál descargar (desde 0). Por defecto 0. Ejemplo: `0`. |
| `audio` | 1 | no | `1` para descargar solo la música. |

- Respuesta binaria: `video/mp4`, `image/jpeg` o `audio/mpeg`.

Ejemplo:

```bash
curl "https://geometryamerica.xyz/api/v1/downloadHistories?username=tiktok" \
  -H "Authorization: Bearer TU_API_KEY"
```

Respuesta:

```
<archivo binario>
```

## Formato de los avisos de directo

Con `liveCallback`, cuando un usuario vigilado empieza o termina un directo se envía un `POST` con JSON
a tu URL (comprobación cada minuto). `liveEvents` entrega este mismo cuerpo por SSE. `ongoing` es `true`
cuando el directo ya estaba en curso al empezar a vigilar al usuario. Usa `roomId` para no avisar dos
veces del mismo directo.

```json
{ "event": "live_start", "username": "usuario", "roomId": "7312345678901234567", "title": "En vivo",
  "cover": "https://…/cover.jpeg", "startedAt": "2026-10-04T18:02:11Z", "url": "https://www.tiktok.com/@usuario/live",
  "watchUrl": "https://geometryamerica.xyz/live/usuario", "ongoing": false, "callbackId": 4, "sentAt": "2026-10-04T18:02:40Z" }
```

```json
{ "event": "live_end", "username": "usuario", "roomId": "7312345678901234567", "title": "En vivo",
  "startedAt": "2026-10-04T18:02:11Z", "endedAt": "2026-10-04T19:40:03Z", "durationSeconds": 5872,
  "url": "https://www.tiktok.com/@usuario/live", "callbackId": 4, "sentAt": "2026-10-04T19:41:10Z" }
```

Si la URL es un webhook de Discord (`https://discord.com/api/webhooks/…`), el aviso llega como mensaje
de Discord con la portada del directo.

### Verificar la firma

Cada aviso incluye `X-GA-Signature: sha256=<hex>`: HMAC-SHA256 del cuerpo crudo con el `secret` que
recibiste al crear el callback. Tu servidor debe responder 2xx en menos de 8 segundos; tras 20 fallos
consecutivos el callback se pausa.

```python
import hmac, hashlib
firma = "sha256=" + hmac.new(SECRET.encode(), cuerpo_crudo, hashlib.sha256).hexdigest()
valido = hmac.compare_digest(firma, headers["X-GA-Signature"])
```
