# Pagination

## Overview

Some Genlogs API endpoints return large result sets that are split across multiple pages. When this happens, the API returns a subset of results along with pagination headers that allow you to retrieve the remaining pages.

Pagination is currently available on the following endpoints:

| Endpoint                                      | Paginated when       | Page Size |
|-----------------------------------------------|----------------------|-----------|
| [GET /facilities](/pages/dH7jXLIJrGUh4H0RFEUJ) | include_lanes=true   | 20        |

*This page will be updated as pagination support is added to additional endpoints.*

## Navigating pages with the `Link` header

Paginated responses include a `Link` header containing URLs for navigating between pages. If all results fit on a single page, the Link header is omitted.

A typical Link header looks like this:

```shellscript
Link: <https://api.genlogs.io/facilities?zip_code=91761&include_lanes=true&cursor=eyJ0b3...>; rel="next"
```

The following relationships may appear:

| Relationships        | Meaning                                  |
|----------------------|------------------------------------------|
| rel="next"        | URL for the next page of results         |
| rel="prev"        | URL for the previous page of results     |

`rel="next"` is absent on the final page. `rel="prev"` is absent on the first page.

To retrieve the next page, make a request to the URL provided in the Link header. The URL includes all original query parameters along with a cursor value; there is no need to rebuild the request.

## Tracking total results with `X-Total-Count`

Every paginated response includes an X-Total-Count header with the total number of matching results across all pages. This can be used for progress indicators or to determine how many pages to expect.

`X-Total-Count`: 999

This value is consistent across all pages of a result set.

## Inspecting pagination headers

To verify pagination is working, you can inspect response headers using curl:

```shellscript
curl --include \
--url "https://api.genlogs.io/facilities?zip_code=91761&include_lanes=true" \
--header "Access-Token: [your-token]" \
--header "x-api-key: [your-api-key]" \
```

The `--include` flag prints the response headers above the body, allowing you to see the Link and X-Total-Count values.

You can use the URLs from the Link header to request another page of results. For example, to request the next page based on the previous example:

```shellscript
curl --include --request GET \
--url "https://api.genlogs.io/facilities?zip_code=91761&include_lanes=true&cursor=eyJ0b3..." \
--header "Access-Token: [your-token]" \
--header "x-api-key: [your-api-key]" \
```

The URLs in the Link header include the cursor query parameter, which the server uses to determine which page to return. The cursor value is opaque; do not attempt to parse, modify, or construct it. Always use the complete URL provided in the Link header.

## Iterating through pages programmatically

### Python

The requests library parses the `Link` header automatically via response.links. The following script collects all facilities across every page:

```python
import requests

BASE_URL = "https://api.genlogs.io"
headers = {
    "Access-Token": "<your-token>",
    "x-api-key": "<your-api-key>",
}

url = f"{BASE_URL}/facilities?zip_code=91761&include_lanes=true"
facilities = []

while url:
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    facilities.extend(response.json())
    url = response.links.get("next", {}).get("url")

total = response.headers.get("X-Total-Count")
print(f"Fetched {len(facilities)} of {total} facilities")
```

### Javascript

```javascript
const headers = {
    "Access-Token": "<your-token>",
    "x-api-key": "<your-api-key>",
};

let url = "https://api.genlogs.io/facilities?zip_code=91761&include_lanes=true";
const facilities = [];
let lastResponse;

while (url) {
    lastResponse = await fetch(url, { headers });
    const data = await lastResponse.json();
    facilities.push(...data);

const linkHeader = lastResponse.headers.get("Link") || "";
    const match = linkHeader.match(/<([^>]+)>;\s*rel="next"/);
    url = match ? match[1] : null;
}

const total = lastResponse.headers.get("X-Total-Count");
console.log(`Fetched ${facilities.length} of ${total} facilities`);
```

## Things to know:

* Cursor values are opaque. Do not parse, modify, cache long-term, or construct cursor values. Always follow the URL provided in the Link header.
* Authentication is required on every page request. Include your Access-Token and x-api-key headers on each request, including subsequent pages.
* Cursors do not expire. You can pause between page requests without losing your position in the result set.
* All query filters are preserved. The server embeds your original query parameters (zip_code, include_lanes, etc.) in the Link URL. You do not need to re-supply them.
* Backwards compatible. Requests that do not include a cursor parameter behave exactly as before. Existing integrations require no changes.
* Not supported with smart search. Combining the cursor parameter with `smart_search=true` returns a 400 Bad Request error.
