# Pagination

> Learn how to work with the paginated order list when querying the 4N NextDay API.

Source: https://api-doc.4nortes.app/pagination

One endpoint in the 4N NextDay API is paginated: the order list. This guide covers how to navigate it.

<a id="what-paginates"></a>

## What paginates

| Endpoint          | Paginated?                                                                   |
| ----------------- | ---------------------------------------------------------------------------- |
| `GET /orders`     | **Yes** — `page` and `per_page` query parameters, `items` + `meta` in `data` |
| `GET /localities` | No — `data` is the full array                                                |
| `GET /regions`    | No — `data` is the full array                                                |
| `GET /services`   | No — `data` is the full array                                                |

Everything below applies to `GET /orders` only.

<a id="parameters"></a>

## Pagination Parameters

- `page` (integer): The page number to retrieve. Default: `1`
- `per_page` (integer): Number of items per page. Default: `15`, Min: `1`, Max: `100`. Values outside this range return a `422` validation error on `per_page`.

<a id="response-structure"></a>

## Paginated Response Structure

The response puts an `items` array inside `data`, along with a `meta` object containing pagination information:

- `current_page` (integer): The current page number.
- `from` (integer|null): The index of the first item on this page (`null` when the page is empty).
- `to` (integer|null): The index of the last item on this page (`null` when the page is empty).
- `last_page` (integer): The total number of pages.
- `per_page` (integer): Items per page.
- `total` (integer): Total number of items across all pages.

Orders are sorted newest first.

```json
{
  "success": true,
  "message": "Orders retrieved successfully",
  "data": {
    "items": [
      {
        "id": 12346,
        "tracking_number": "4N202502030002"
        // ...
      },
      {
        "id": 12345,
        "tracking_number": "4N202502030001"
        // ...
      }
    ],
    "meta": {
      "current_page": 2,
      "from": 16,
      "to": 30,
      "last_page": 5,
      "per_page": 15,
      "total": 73
    }
  },
  "timestamp": "2025-02-03T10:00:00.000000Z"
}
```

<a id="example"></a>

## Example: Fetching Orders

```bash
# First page (default)
curl "https://api.4nortes.app/api/v1/orders" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

# Specific page with custom page size
curl "https://api.4nortes.app/api/v1/orders?page=2&per_page=25" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

```js
// Fetch first page
const response = await fetch(
  'https://api.4nortes.app/api/v1/orders',
  {
    headers: {
      'Authorization': `Bearer ${token}`,
      'Accept': 'application/json',
    },
  }
)

// Fetch specific page
const page2 = await fetch(
  'https://api.4nortes.app/api/v1/orders?page=2&per_page=25',
  {
    headers: {
      'Authorization': `Bearer ${token}`,
      'Accept': 'application/json',
    },
  }
)
```

```python
import requests

# Fetch first page
response = requests.get(
    'https://api.4nortes.app/api/v1/orders',
    headers={'Authorization': f'Bearer {token}'}
)

# Fetch specific page
response = requests.get(
    'https://api.4nortes.app/api/v1/orders',
    headers={'Authorization': f'Bearer {token}'},
    params={'page': 2, 'per_page': 25}
)
```

<a id="iterating"></a>

## Iterating Through All Pages

Here's how to iterate through all pages of results:

```js
async function getAllOrders() {
  const allOrders = []
  let page = 1
  let hasMore = true

  while (hasMore) {
    const response = await fetch(
      `https://api.4nortes.app/api/v1/orders?page=${page}&per_page=100`,
      {
        headers: {
          'Authorization': `Bearer ${token}`,
          'Accept': 'application/json',
        },
      }
    )

    if (!response.ok) {
      throw new Error(`Failed to load page ${page}: HTTP ${response.status}`)
    }

    const result = await response.json()
    allOrders.push(...result.data.items)

    hasMore = page < result.data.meta.last_page
    page++
  }

  return allOrders
}
```

```python
def get_all_orders():
    all_orders = []
    page = 1

    while True:
        response = requests.get(
            'https://api.4nortes.app/api/v1/orders',
            headers={'Authorization': f'Bearer {token}'},
            params={'page': page, 'per_page': 100}
        )
        response.raise_for_status()

        result = response.json()
        all_orders.extend(result['data']['items'])

        if page >= result['data']['meta']['last_page']:
            break

        page += 1

    return all_orders
```

<a id="best-practices"></a>

## Best Practices

1. **Use appropriate page sizes**: Request only what you need. Smaller page sizes mean faster responses.

2. **Don't poll the list for status changes**: Use [webhooks](https://api-doc.4nortes.app/webhooks.md) to be told when an order moves, and the [Tracking API](https://api-doc.4nortes.app/api/tracking.md) for a single order.

3. **Handle empty results**: Always check if `items` is empty before processing. `from` and `to` are `null` on an empty page.

4. **Respect rate limits**: The API allows 100 requests per minute per account. A full export at `per_page=100` costs one request per 100 orders — add a short delay between pages for very large accounts.

```js
// Add delay between pagination requests
async function fetchWithDelay(page) {
  const response = await fetch(
    `https://api.4nortes.app/api/v1/orders?page=${page}&per_page=100`,
    { headers: { 'Authorization': `Bearer ${token}` } }
  )
  await new Promise(resolve => setTimeout(resolve, 100)) // 100ms delay
  return response.json()
}
```
