> ## 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.

# Paginação

Listas da Sorsa são retornadas em páginas. Para obter o conjunto completo, percorra as páginas usando cursores até o fim dos dados.

## Como funciona a paginação por cursor

Em dados sociais que mudam continuamente, cursores são mais confiáveis que números de página ou offsets, que podem pular ou repetir resultados.

1. Envie a primeira requisição sem cursor.
2. A resposta traz os dados e `next_cursor`.
3. Passe esse valor na próxima chamada.
4. Pare quando `next_cursor` for nulo ou ausente.

Nem todo endpoint tem paginação. `/info`, `/tweet-info`, `/score` e `/about` retornam um objeto. Algumas listas, como `/info-batch`, `/tweet-info-bulk` e `/top-followers`, retornam tudo em uma resposta. Confira se a referência inclui o parâmetro `next_cursor`.

## Estrutura da resposta

As respostas paginadas seguem um destes padrões:

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

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

Os dados ficam em `users` ou `tweets`. Trate `next_cursor` como um valor opaco: envie-o sem alterações e pare se estiver nulo, vazio ou ausente. Não incremente nem converta para Number no JavaScript.

Veja os esquemas em [formato de resposta](https://docs.sorsa.io/pt-BR/response-format).

## Como enviar cursores

O campo sempre se chama `next_cursor`.

**GET**, como `/followers`, `/follows` e `/list-tweets`: parâmetro de consulta.

```bash theme={null}
# First page
curl --request GET \
  --url 'https://api.sorsa.io/v3/followers?username=elonmusk' \
  --header 'ApiKey: YOUR_API_KEY'

# Next page
curl --request GET \
  --url 'https://api.sorsa.io/v3/followers?username=elonmusk&next_cursor=DAABCgABF7Y...' \
  --header 'ApiKey: YOUR_API_KEY'
```

**POST**, como `/search-tweets`, `/user-tweets` e `/comments`: corpo JSON.

```bash theme={null}
# First page
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 page
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": "DAABCgABF7Y..."}'
```

## O tamanho das páginas varia

Um endpoint que retorna até 20 itens pode retornar 18, 12 ou 5 mesmo com mais dados na próxima página.

**Nunca determine o fim pela quantidade de itens.** Verifique `next_cursor`. Uma página curta não significa que os dados terminaram.

## Exemplos completos

Os exemplos guardam resultados em memória. Em trabalhos grandes, grave cada página no armazenamento, deduplique por ID string e salve um checkpoint depois da gravação. Mantenha conta, consulta, filtros e ordenação constantes ao usar um cursor. Defina um orçamento de páginas ou requisições e detecte cursores repetidos para evitar loops infinitos. Uma pausa local não coordena outros workers com a mesma chave.

**Python: seguidores (GET)**

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

API_KEY = "YOUR_API_KEY"

def fetch_all_followers(username):
    all_users = []
    cursor = None

    while True:
        params = {"username": username}
        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()

        users = data.get("users", [])
        all_users.extend(users)
        print(f"Page fetched: {len(users)} users. Total so far: {len(all_users)}")

        cursor = data.get("next_cursor")
        if not cursor:
            break

        time.sleep(0.05)  # respect 20 req/s rate limit

    return all_users

followers = fetch_all_followers("elonmusk")
print(f"Done. {len(followers)} followers total.")
```

**Python: resultados de busca (POST)**

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

API_KEY = "YOUR_API_KEY"

def search_all_tweets(query):
    all_tweets = []
    cursor = None

    while True:
        body = {"query": query}
        if cursor:
            body["next_cursor"] = cursor

        response = requests.post(
            "https://api.sorsa.io/v3/search-tweets",
            json=body,
            headers={"ApiKey": API_KEY},
            timeout=30,
        )
        response.raise_for_status()
        data = response.json()

        tweets = data.get("tweets", [])
        all_tweets.extend(tweets)
        print(f"Page fetched: {len(tweets)} tweets. Total so far: {len(all_tweets)}")

        cursor = data.get("next_cursor")
        if not cursor:
            break

        time.sleep(0.05)

    return all_tweets

results = search_all_tweets("bitcoin")
print(f"Done. {len(results)} tweets total.")
```

**JavaScript: seguidores (GET)**

```javascript theme={null}
async function fetchAllFollowers(username) {
  const API_KEY = "YOUR_API_KEY";
  const allUsers = [];
  let cursor = null;

  while (true) {
    const params = new URLSearchParams({ username });
    if (cursor) params.append("next_cursor", cursor);

    const response = await fetch(
      `https://api.sorsa.io/v3/followers?${params}`,
      { headers: { "ApiKey": API_KEY } }
    );
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    const data = await response.json();

    const users = data.users || [];
    allUsers.push(...users);
    console.log(`Page fetched: ${users.length} users. Total: ${allUsers.length}`);

    cursor = data.next_cursor;
    if (!cursor) break;

    await new Promise(r => setTimeout(r, 50));
  }

  return allUsers;
}
```

**JavaScript: resultados de busca (POST)**

```javascript theme={null}
async function searchAllTweets(query) {
  const API_KEY = "YOUR_API_KEY";
  const allTweets = [];
  let cursor = null;

  while (true) {
    const body = { query };
    if (cursor) body.next_cursor = cursor;

    const response = await fetch("https://api.sorsa.io/v3/search-tweets", {
      method: "POST",
      headers: {
        "ApiKey": API_KEY,
        "Content-Type": "application/json"
      },
      body: JSON.stringify(body)
    });
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    const data = await response.json();

    const tweets = data.tweets || [];
    allTweets.push(...tweets);
    console.log(`Page fetched: ${tweets.length} tweets. Total: ${allTweets.length}`);

    cursor = data.next_cursor;
    if (!cursor) break;

    await new Promise(r => setTimeout(r, 50));
  }

  return allTweets;
}
```

## Paginação com tratamento de erros

Em produção, combine paginação e novas tentativas para que uma página com falha não interrompa toda a coleta. Veja [códigos de erro](https://docs.sorsa.io/pt-BR/error-codes).

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

API_KEY = "YOUR_API_KEY"

def paginate_with_retries(username, max_retries=3):
    all_users = []
    cursor = None

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

        for attempt in range(max_retries):
            response = requests.get(
                "https://api.sorsa.io/v3/followers",
                params=params,
                headers={"ApiKey": API_KEY},
                timeout=30,
            )

            if response.status_code == 200:
                break
            elif response.status_code == 429:
                time.sleep(1)
                continue
            elif response.status_code >= 500:
                time.sleep(2)
                continue
            else:
                raise Exception(f"Error {response.status_code}: {response.text}")
        else:
            raise Exception("Max retries exceeded")

        data = response.json()
        all_users.extend(data.get("users", []))

        cursor = data.get("next_cursor")
        if not cursor:
            break

        time.sleep(0.05)

    return all_users
```

## Próximos passos

* [Limites de requisições](https://docs.sorsa.io/pt-BR/rate-limits): respeite 20 req/s em grandes consultas.
* [Códigos de erro](https://docs.sorsa.io/pt-BR/error-codes): trate 429 e outros erros nos loops.
* [Formato de resposta](https://docs.sorsa.io/pt-BR/response-format): esquemas de User e Tweet.
