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

# Pagination (Offset) on the Judit API

> How to traverse large datasets in the Judit API using offset-based pagination with page and page_size, with cURL, Python and JavaScript examples.

> 🤖 Judit API pagination does not use cursors. It is based on the *Offset* pattern, using exclusively the query parameters `page` (page number) and `page_size` (number of items). The strict maximum limit for `page_size` is <strong>1000 items</strong>. Pagination metadata is returned at the root of the response object.

## How Pagination Works

### Query Parameters (Request)

When performing listings (such as fetching the history of requests or trackings), you can send the following parameters in the URL:

| Parameter   | Type    | Default | Description                                                                                                                       |
| :---------- | :------ | :------ | :-------------------------------------------------------------------------------------------------------------------------------- |
| `page`      | integer | 1       | Desired page number (1-based).                                                                                                    |
| `page_size` | integer | 20      | Number of items returned per page. **Maximum allowed: 1000.** *Recommendation: Keep between 10 and 100 for better response time.* |

### Response Structure (Payload)

Responses from paginated endpoints always return navigation metadata at the root of the JSON, and the items themselves usually come in the `page_data` array.

```json theme={null}
{
  "page": 1,              // Current page being returned
  "page_count": 20,       // Number of items present in this specific page
  "all_pages_count": 10,  // Total number of pages available for this query
  "all_count": 200,       // Absolute total of items found in the database
  "page_data": [          // Array containing the query objects
    { ... }, 
    { ... }
  ]
}
```

***

## Practical Examples

### Basic Query with Pagination

Below, we show how to fetch the first page of requests and iterate over the data.

<CodeGroup>
  ```bash cURL theme={null}
  # 1. Fetching the first page (10 items)
  curl -X GET "https://requests.production.judit.io/requests?page=1&page_size=10" \
    -H "api-key: $JUDIT_API_KEY"

  # 2. Fetching a specific page (e.g., page 3, 25 items)
  curl -X GET "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"

  def get_requests_page(page=1, page_size=20):
      """Fetches a specific page from the request history"""
      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"Error: {response.status_code}")
          return None

  # Run
  data = get_requests_page(page=1, page_size=10)
  if data:
      print(f"Current page: {data.get('page')}")
      print(f"Total items in the database: {data.get('all_count')}")
  ```

  ```javascript JavaScript theme={null}
  const apiKey = process.env.JUDIT_API_KEY;
  const baseUrl = "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(`HTTP error: ${response.status}`);
              return null;
          }
      } catch (error) {
          console.error('Connection error:', error);
          return null;
      }
  }

  // Run
  const data = await getRequestsPage(1, 10);
  if (data) {
      console.log(`Current page: ${data.page}`);
      console.log(`Total items in the database: ${data.all_count}`);
  }
  ```
</CodeGroup>

***

## Optimizations and Best Practices

To handle large data volumes efficiently and without being blocked by the API, follow the recommendations below.

### 1. Choosing the right `page_size`

Adjust the page size according to your application's needs, always keeping the <strong>1000-item limit</strong> per request in mind.

```python theme={null}
# ✅ GOOD: For UI rendering (tables, grids)
small_page = get_requests_page(page=1, page_size=10)

# ✅ GOOD: For async batch processing (ETL, migrations)
large_page = get_requests_page(page=1, page_size=100) 

# ❌ ERROR: Exceeds the maximum allowed by the API
# invalid_page = get_requests_page(page=1, page_size=1001) 
```

### 2. Rate Limit Control (Safe Iteration)

The Judit API has strict per-minute request limits. When building *loops* to extract all pages, it is **mandatory** to implement a small delay between calls to avoid the `429 Too Many Requests` error.

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

  def fetch_all_data_safely(delay_seconds=0.2):
      """Extracts all pages while respecting the API's request limit"""
      current_page = 1
      all_extracted_items = []
      
      while True:
          # Using a safe page_size (below the 1000 limit)
          data = get_requests_page(page=current_page, page_size=50)
          
          # Stop if there is no data or the page_data key is missing
          if not data or not data.get('page_data'):
              break
              
          all_extracted_items.extend(data['page_data'])
          print(f"Extracted: Page {current_page}/{data.get('all_pages_count')}. Total so far: {len(all_extracted_items)}")
          
          # Check if we've reached the last page
          if current_page >= data.get('all_pages_count', 1):
              print("Extraction completed successfully.")
              break
          
          current_page += 1
          
          # ⚠️ CRITICAL: Pause so we don't blow past the Rate Limit (e.g., 180 req/min)
          time.sleep(delay_seconds)
          
      return all_extracted_items
  ```

  ```javascript JavaScript theme={null}
  async function fetchAllDataSafely(delayMs = 200) {
      // Extracts all pages while respecting the API's request limit
      let currentPage = 1;
      const allExtractedItems = [];
      
      while (true) {
          // Using a safe page_size (below the 1000 limit)
          const data = await getRequestsPage(currentPage, 50);

          // Stop if there is no data
          if (!data || !data.page_data || data.page_data.length === 0) {
              break;
          }

          allExtractedItems.push(...data.page_data);
          console.log(`Extracted: Page ${currentPage}/${data.all_pages_count}. Total so far: ${allExtractedItems.length}`);

          // Check if we've reached the last page
          if (currentPage >= (data.all_pages_count || 1)) {
              console.log("Extraction completed successfully.");
              break;
          }

          currentPage++;

          // ⚠️ CRITICAL: Pause so we don't blow past the Rate Limit
          await new Promise(resolve => setTimeout(resolve, delayMs));
      }

      return allExtractedItems;
  }
  ```
</CodeGroup>

> **Note on Parallel Processing:** We removed the concurrent processing (threads) example because firing multiple pages in parallel will almost certainly trigger Rate Limit blocking (Error 429), unless your application has robust distributed queue management. We always recommend sequential processing with a *delay* or controlled queues.

***

## Next Steps

* 👉 **[Rate Limits](/en/essentialConcepts/rate-limits)**: Understand your account's request quotas.
* 👉 **[Authentication](/en/introduction/authentication)**: Review how to send your credentials.
* 👉 **[Endpoints](/en/api-reference/endpoint/requests/create)**: Explore the resources that support listings.
