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

# Paginação (Offset) na Judit API

> Como navegar por grandes conjuntos de dados na Judit API usando paginação por offset com page e page_size, com exemplos em cURL, Python e JavaScript.

> 🤖 A paginação da Judit API não utiliza cursores. Ela é baseada no padrão *Offset*, utilizando exclusivamente os parâmetros de *query* `page` (número da página) e `page_size` (quantidade de itens). O limite máximo estrito para `page_size` é de <strong>1000 itens</strong>. Os metadados de paginação são retornados na raiz do objeto de resposta.

## Como Funciona a Paginação

### Parâmetros de Query (Requisição)

Ao realizar listagens (como buscar histórico de requisições ou monitoramentos), você pode enviar os seguintes parâmetros na URL:

| Parâmetro   | Tipo    | Padrão | Descrição                                                                                                                                     |
| :---------- | :------ | :----- | :-------------------------------------------------------------------------------------------------------------------------------------------- |
| `page`      | integer | 1      | Número da página desejada (baseado em 1).                                                                                                     |
| `page_size` | integer | 20     | Quantidade de itens retornados por página. **Máximo permitido: 1000.** *Recomendação: Mantenha entre 10 e 100 para melhor tempo de resposta.* |

### Estrutura da Resposta (Payload)

As respostas de endpoints paginados sempre retornam os metadados de navegação na raiz do JSON, e os itens propriamente ditos geralmente vêm no array `page_data`.

```json theme={null}
{
  "page": 1,              // Página atual que está sendo retornada
  "page_count": 20,       // Quantidade de itens presentes nesta página específica
  "all_pages_count": 10,  // Total de páginas disponíveis para esta consulta
  "all_count": 200,       // Total absoluto de itens encontrados no banco
  "page_data": [          // Array contendo os objetos da consulta
    { ... }, 
    { ... }
  ]
}
```

***

## Exemplos Práticos

### Consulta Básica com Paginação

Abaixo, demonstramos como buscar a primeira página de requisições e iterar sobre os dados.

<CodeGroup>
  ```bash cURL theme={null}
  # 1. Buscando a primeira página (10 itens)
  curl -X GET "[https://requests.production.judit.io/requests?page=1&page_size=10](https://requests.production.judit.io/requests?page=1&page_size=10)" \
    -H "api-key: $JUDIT_API_KEY"

  # 2. Buscando uma página específica (ex: página 3, 25 itens)
  curl -X GET "[https://requests.production.judit.io/requests?page=3&page_size=25](https://requests.production.judit.io/requests?page=3&page_size=25)" \
    -H "api-key: $JUDIT_API_KEY"
  ```

  ```python Python theme={null}
  import requests
  import os

  api_key = os.getenv('JUDIT_API_KEY')
  base_url = "[https://requests.production.judit.io](https://requests.production.judit.io)"

  def get_requests_page(page=1, page_size=20):
      """Busca uma página específica do histórico de requisições"""
      headers = {
          'api-key': api_key,
          'Content-Type': 'application/json'
      }
      params = {
          'page': page,
          'page_size': page_size
      }
      
      response = requests.get(f"{base_url}/requests", headers=headers, params=params)
      
      if response.status_code == 200:
          return response.json()
      else:
          print(f"Erro: {response.status_code}")
          return None

  # Execução
  data = get_requests_page(page=1, page_size=10)
  if data:
      print(f"Página atual: {data.get('page')}")
      print(f"Total de itens no banco: {data.get('all_count')}")
  ```

  ```javascript JavaScript theme={null}
  const apiKey = process.env.JUDIT_API_KEY;
  const baseUrl = "[https://requests.production.judit.io](https://requests.production.judit.io)";

  async function getRequestsPage(page = 1, pageSize = 20) {
      const params = new URLSearchParams({
          page: page.toString(),
          page_size: pageSize.toString()
      });
      
      try {
          const response = await fetch(`${baseUrl}/requests?${params}`, {
              headers: {
                  'api-key': apiKey,
                  'Content-Type': 'application/json'
              }
          });
          
          if (response.ok) {
              return await response.json();
          } else {
              console.error(`Erro HTTP: ${response.status}`);
              return null;
          }
      } catch (error) {
          console.error('Erro na conexão:', error);
          return null;
      }
  }

  // Execução
  const data = await getRequestsPage(1, 10);
  if (data) {
      console.log(`Página atual: ${data.page}`);
      console.log(`Total de itens no banco: ${data.all_count}`);
  }
  ```
</CodeGroup>

***

## Otimizações e Boas Práticas

Para lidar com grandes volumes de dados de forma eficiente e sem ser bloqueado pela API, siga as recomendações abaixo.

### 1. Adequação do `page_size`

Adapte o tamanho da página de acordo com a necessidade da sua aplicação, lembrando sempre do <strong>limite de 1000 itens</strong> por requisição.

```python theme={null}
# ✅ BOM: Para exibição em interface (tabelas, grids)
small_page = get_requests_page(page=1, page_size=10)

# ✅ BOM: Para processamento assíncrono em lote (ETL, migrações)
large_page = get_requests_page(page=1, page_size=100) 

# ❌ ERRO: Excede o limite máximo permitido pela API
# invalid_page = get_requests_page(page=1, page_size=1001) 
```

### 2. Controle de Rate Limit (Iteração Segura)

A Judit API possui limites rigorosos de requisições por minuto. Ao construir *loops* para extrair todas as páginas, é **obrigatório** implementar um pequeno atraso (*delay*) entre as chamadas para evitar o erro `429 Too Many Requests`.

<CodeGroup>
  ```python Python theme={null}
  import time

  def fetch_all_data_safely(delay_seconds=0.2):
      """Extrai todas as páginas respeitando o limite de requisições da API"""
      current_page = 1
      all_extracted_items = []
      
      while True:
          # Usando um page_size seguro (abaixo do limite de 1000)
          data = get_requests_page(page=current_page, page_size=50)
          
          # Interrompe se não houver dados ou a chave page_data não existir
          if not data or not data.get('page_data'):
              break
              
          all_extracted_items.extend(data['page_data'])
          print(f"Extraído: Página {current_page}/{data.get('all_pages_count')}. Total Acumulado: {len(all_extracted_items)}")
          
          # Verifica se chegamos na última página
          if current_page >= data.get('all_pages_count', 1):
              print("Extração concluída com sucesso.")
              break
          
          current_page += 1
          
          # ⚠️ CRÍTICO: Pausa para não estourar o Rate Limit (ex: 180 req/min)
          time.sleep(delay_seconds)
          
      return all_extracted_items
  ```

  ```javascript JavaScript theme={null}
  async function fetchAllDataSafely(delayMs = 200) {
      // Extrai todas as páginas respeitando o limite de requisições da API
      let currentPage = 1;
      const allExtractedItems = [];
      
      while (true) {
          // Usando um page_size seguro (abaixo do limite de 1000)
          const data = await getRequestsPage(currentPage, 50);

          // Interrompe se não houver dados
          if (!data || !data.page_data || data.page_data.length === 0) {
              break;
          }

          allExtractedItems.push(...data.page_data);
          console.log(`Extraído: Página ${currentPage}/${data.all_pages_count}. Total Acumulado: ${allExtractedItems.length}`);

          // Verifica se chegamos na última página
          if (currentPage >= (data.all_pages_count || 1)) {
              console.log("Extração concluída com sucesso.");
              break;
          }

          currentPage++;

          // ⚠️ CRÍTICO: Pausa para não estourar o Rate Limit
          await new Promise(resolve => setTimeout(resolve, delayMs));
      }

      return allExtractedItems;
  }
  ```
</CodeGroup>

> **Nota sobre Processamento Paralelo:** Removemos o exemplo de processamento concorrente (threads) porque disparar múltiplas páginas em paralelo quase certamente causará bloqueio por Rate Limit (Erro 429), a menos que sua aplicação tenha uma gestão de fila distribuída robusta. Recomendamos sempre o processamento sequencial com *delay* ou filas controladas.

***

## Próximos Passos

* 👉 **[Rate Limits](/essentialConcepts/rate-limits)**: Entenda as quotas de requisições da sua conta.
* 👉 **[Autenticação](/introduction/authentication)**: Revise como enviar suas credenciais.
* 👉 **[Endpoints](/api-reference/endpoint/requests/create)**: Explore os recursos que suportam listagem.
