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

# Formato de respuesta

# Formato de respuesta: esquemas de User y Tweet

Sorsa API devuelve todos los datos en JSON. Esta página describe la estructura de las respuestas, los objetos principales, los tipos de campos y la paginación.

***

## Convenciones

Estas reglas se aplican en toda la API.

**Los IDs son cadenas.** Los IDs de X/Twitter (`id`, `conversation_id_str`, `in_reply_to_tweet_id` y otros) se devuelven como cadenas, no como enteros. X utiliza IDs Snowflake de 64 bits que superan `Number.MAX_SAFE_INTEGER` de JavaScript. Las cadenas evitan la pérdida silenciosa de precisión en navegadores, Node.js y lenguajes que representan los números JSON en coma flotante.

**Las fechas principales son cadenas ISO 8601.** Los campos `created_at` de User y Tweet utilizan valores como `2026-03-06T12:00:00Z`. Consulta el esquema para otras fechas; no supongas que las verificaciones o relaciones utilizan el mismo formato.

**Los booleanos son estrictos.** Indicadores como `verified`, `is_reply`, `protected` y `can_dm` son `true` o `false`, nunca `0`/`1` ni `"true"`/`"false"`.

**Campos nulos y ausentes.** Distingue un valor ausente de un cero medido o de `false`. Al recorrer arrays opcionales como `bio_urls` y `pinned_tweet_ids`, normaliza los valores nulos o ausentes a listas vacías: `user.get("bio_urls") or []` en Python o `user.bio_urls ?? []` en JavaScript. Los modelos compactos omiten campos del objeto User completo.

***

## Estructuras contenedoras de respuesta

Los endpoints de un único objeto, como `/info` y `/tweet-info`, lo devuelven directamente en el nivel superior. Los endpoints de listas utilizan estas estructuras.

**UsersResponse:** utilizada por `/followers`, `/follows`, `/verified-followers`, `/retweeters`, `/search-users`, `/list-members` y `/list-followers`. `/community-members` utiliza las mismas claves, pero devuelve objetos compactos `CommunityUser`.

```text theme={null}
{
  "users": [ ... ],
  "next_cursor": "abc123"
}
```

**TweetsResponse:** utilizada por `/user-tweets`, `/comments`, `/quotes`, `/search-tweets`, `/mentions`, `/list-tweets`, `/community-tweets` y `/community-search-tweets`.

```text theme={null}
{
  "tweets": [ ... ],
  "next_cursor": "abc123"
}
```

**FollowersResponse:** utilizada por `/new-followers-7d`, `/new-following-7d` y `/top-following`. `/top-followers` utiliza `TopFollowersResponse`, con perfiles compactos y un campo `score`.

```text theme={null}
{
  "users": [ ... ]
}
```

FollowersResponse no incluye `next_cursor`: devuelve todos los resultados en una sola respuesta.

***

## El objeto User

Representa el perfil de una cuenta de X/Twitter. `/info` lo devuelve directamente; los endpoints de listas lo incluyen como elemento de un array y cada objeto Tweet lo contiene en el campo `user`.

```text theme={null}
{
  "id": "44196397",
  "username": "elonmusk",
  "display_name": "Elon Musk",
  "description": "Mars & Cars, Chips & Dips",
  "location": "Earth",
  "created_at": "2009-06-02T20:12:29Z",
  "followers_count": 236021252,
  "followings_count": 1292,
  "favourites_count": 214650,
  "tweets_count": 98479,
  "media_count": 4374,
  "profile_image_url": "https://pbs.twimg.com/profile_images/.../photo_normal.jpg",
  "profile_background_image_url": "https://pbs.twimg.com/profile_banners/44196397/...",
  "bio_urls": ["https://example.com"],
  "pinned_tweet_ids": ["2028500984977330453"],
  "verified": true,
  "can_dm": false,
  "protected": false,
  "possibly_sensitive": false
}
```

| Campo                          | Tipo                    | Descripción                                        |
| :----------------------------- | :---------------------- | :------------------------------------------------- |
| `id`                           | cadena                  | ID numérico permanente del usuario (Snowflake)     |
| `username`                     | cadena                  | Nombre de usuario actual, sin @                    |
| `display_name`                 | cadena                  | Nombre público del perfil                          |
| `description`                  | cadena                  | Biografía de la cuenta                             |
| `location`                     | cadena                  | Ubicación indicada por el usuario (texto libre)    |
| `created_at`                   | cadena                  | Fecha y hora de creación de la cuenta              |
| `followers_count`              | entero                  | Número de seguidores                               |
| `followings_count`             | entero                  | Número de cuentas seguidas                         |
| `favourites_count`             | entero                  | Total de Me gusta dados por esta cuenta            |
| `tweets_count`                 | entero                  | Total de publicaciones                             |
| `media_count`                  | entero                  | Total de elementos multimedia publicados           |
| `profile_image_url`            | cadena                  | URL de la imagen de perfil                         |
| `profile_background_image_url` | cadena                  | URL de la imagen de portada                        |
| `bio_urls`                     | array de cadenas o null | URL de la biografía                                |
| `pinned_tweet_ids`             | array de cadenas o null | IDs de las publicaciones fijadas                   |
| `verified`                     | booleano                | Estado de verificación (marca azul, dorada o gris) |
| `can_dm`                       | booleano                | Indica si los mensajes directos están abiertos     |
| `protected`                    | booleano                | Indica si la cuenta es privada                     |
| `possibly_sensitive`           | booleano                | Indica si la cuenta está marcada como sensible     |

***

## El objeto Follower

Amplía el objeto User con un campo adicional. Lo devuelven `/new-followers-7d`, `/new-following-7d` y `/top-following`. `/top-followers` devuelve un modelo compacto diferente con `score`.

| Campo adicional | Tipo   | Descripción                                         |
| :-------------- | :----- | :-------------------------------------------------- |
| `followerDate`  | cadena | Fecha en que se registró la relación de seguimiento |

***

## El objeto Tweet

Contiene el texto completo, los metadatos, las métricas de interacción y las relaciones anidadas de una publicación. `/tweet-info` lo devuelve directamente; los endpoints de listas lo incluyen como elemento de un array.

```text theme={null}
{
  "id": "1234567890123456789",
  "full_text": "This is the complete tweet text including mentions and links",
  "created_at": "2026-03-06T12:00:00Z",
  "lang": "en",
  "bookmark_count": 42,
  "likes_count": 1500,
  "quote_count": 23,
  "reply_count": 89,
  "retweet_count": 312,
  "view_count": 250000,
  "conversation_id_str": "1234567890123456789",
  "in_reply_to_tweet_id": null,
  "in_reply_to_username": null,
  "is_reply": false,
  "is_quote_status": false,
  "is_replies_limited": false,
  "entities": [ ... ],
  "user": { ... },
  "quoted_status": null,
  "retweeted_status": null
}
```

**Campos de contenido**

| Campo        | Tipo   | Descripción                                        |
| :----------- | :----- | :------------------------------------------------- |
| `id`         | cadena | ID único de la publicación (Snowflake)             |
| `full_text`  | cadena | Texto completo de la publicación                   |
| `created_at` | cadena | Fecha y hora de publicación                        |
| `lang`       | cadena | Código de idioma detectado, como "en", "ja" o "es" |

**Métricas de interacción**

| Campo            | Tipo   | Descripción             |
| :--------------- | :----- | :---------------------- |
| `likes_count`    | entero | Total de Me gusta       |
| `retweet_count`  | entero | Total de retuits        |
| `reply_count`    | entero | Total de respuestas     |
| `quote_count`    | entero | Total de citas          |
| `view_count`     | entero | Total de impresiones    |
| `bookmark_count` | entero | Total de veces guardada |

**Contexto del hilo y de las respuestas**

| Campo                  | Tipo          | Descripción                                  |
| :--------------------- | :------------ | :------------------------------------------- |
| `conversation_id_str`  | cadena        | ID de la publicación inicial del hilo        |
| `in_reply_to_tweet_id` | cadena o null | ID de la publicación a la que responde       |
| `in_reply_to_username` | cadena o null | Nombre del usuario al que responde           |
| `is_reply`             | booleano      | Indica si es una respuesta                   |
| `is_quote_status`      | booleano      | Indica si cita otra publicación              |
| `is_replies_limited`   | booleano      | Indica si el autor restringió las respuestas |

**Objetos anidados**

| Campo              | Tipo                 | Descripción                                                   |
| :----------------- | :------------------- | :------------------------------------------------------------ |
| `user`             | objeto User          | Perfil completo del autor                                     |
| `entities`         | array de TweetEntity | Archivos multimedia y enlaces adjuntos                        |
| `quoted_status`    | objeto Tweet o null  | Publicación citada (objeto completo y recursivo)              |
| `retweeted_status` | objeto Tweet o null  | Publicación original retuiteada (objeto completo y recursivo) |

`quoted_status` y `retweeted_status` contienen objetos Tweet completos, con sus propios campos `user`, `entities` y métricas. Así obtienes los datos relacionados en una sola llamada, sin solicitudes adicionales.

***

## El objeto TweetEntity

Cada elemento de `entities` representa un archivo multimedia adjunto o un enlace insertado en la publicación.

```text theme={null}
{
  "type": "photo",
  "link": "https://pbs.twimg.com/media/..._large.jpg",
  "preview": "https://pbs.twimg.com/media/..._small.jpg"
}
```

| Campo     | Tipo   | Descripción                                              |
| :-------- | :----- | :------------------------------------------------------- |
| `type`    | cadena | Tipo de elemento, como `photo`, `video` o `animated_gif` |
| `link`    | cadena | URL directa al archivo en resolución completa            |
| `preview` | cadena | Texto de vista previa o URL de miniatura                 |

***

## Paginación por cursor

Los endpoints de listas paginadas utilizan cursores. Las consultas por lotes y las listas de análisis de criptomonedas descritas antes no los utilizan. La paginación por cursor es más fiable que la basada en desplazamientos cuando se añade contenido continuamente.

**Procedimiento:**

1. Envía la solicitud inicial sin cursor.
2. Recibirás los datos y un campo `next_cursor`.
3. Incluye ese valor en la siguiente solicitud para obtener la próxima página.
4. Si `next_cursor` es `null` o no aparece, has llegado al final.

**Los endpoints GET** reciben el cursor como parámetro de consulta:

```text theme={null}
curl --request GET \
  --url 'https://api.sorsa.io/v3/followers?username=elonmusk&next_cursor=abc123' \
  --header 'ApiKey: YOUR_API_KEY'
```

**Los endpoints POST** lo reciben en el cuerpo JSON:

```text theme={null}
curl --request POST \
  --url 'https://api.sorsa.io/v3/search-tweets' \
  --header 'ApiKey: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{"query": "bitcoin", "next_cursor": "abc123"}'
```

**Ejemplo en Python: recorrer todos los seguidores**

```text theme={null}
import time
import requests

API_KEY = "YOUR_API_KEY"
all_users = []
cursor = None

while True:
    params = {"username": "elonmusk"}
    if cursor:
        params["next_cursor"] = cursor

    response = requests.get(
        "https://api.sorsa.io/v3/followers",
        params=params,
        headers={"ApiKey": API_KEY},
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    all_users.extend(data["users"])
    cursor = data.get("next_cursor")

    if not cursor:
        break

    time.sleep(0.05)  # respect rate limit

print(f"Fetched {len(all_users)} followers")
```

Consulta estrategias y consejos de rendimiento en [Paginación](https://docs.sorsa.io/es/pagination).

***

## Próximos pasos

* [Paginación](https://docs.sorsa.io/es/pagination): patrones avanzados y buenas prácticas.
* [Códigos de error](https://docs.sorsa.io/es/error-codes): estructura de las respuestas de error.
* [Referencia de la API](https://docs.sorsa.io/es/api-reference-guide): esquemas completos y ejemplos de solicitudes y respuestas.
