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

# Pagination

> Learn how to handle large response sets with pagination.

The Untether Labs API uses cursor-based pagination for most endpoints which return lists of items.
This approach provides efficient and consistent navigation through result sets.

## Pagination Structure

All paginated endpoints return responses in the following format:

```json Paginated Response Structure icon=braces theme={null}
{
    "items": [
        // Array of returned items
    ],
    "cursor": "<string>"
}
```

### Response Fields

<ResponseField name="items" type="array" required>
  An array containing the requested data items for the current page
</ResponseField>

<ResponseField name="cursor" type="string" required>
  A string token for fetching the next page, or `null` if this is the last page
</ResponseField>

<Info>
  The cursor value should be treated as an opaque string. The format is subject to
  change without notice, clients should not attempt to decode or modify it.
</Info>

## Making Paginated Requests

### Initial Request

Start by making a request to any paginated endpoint without a cursor parameter:

```bash Initial Paginated Request icon=file-terminal theme={null}
curl -X GET --location "https://app.untetherlabs.com/api/v1/pay-codes" \
  -H "Authorization: Bearer {ACCESS_TOKEN}"
```

```json Initial Response icon=braces theme={null}
{
    "items": [
        {
            "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
            "name": "Overtime",
            "shorthandName": "OT",
            "hexColor": "#f97316",
            "type": "hours",
            "value": 1.5
        }
        // ... more items
    ],
    "cursor": "my-opaque-cursor"
}
```

### Subsequent Requests

To fetch the next page, include the previous cursor value as a query parameter:

```bash Next Page Request icon=file-terminal theme={null}
curl -X GET --location "https://app.untetherlabs.com/api/v1/timekeeping/timecards?cursor=my-opaque-cursor" \
  -H "Authorization: Bearer {ACCESS_TOKEN}"
```

### Last Page Detection

When you reach the last page, the cursor will be `null`:

```json Final Page Response icon=braces theme={null}
{
    "items": [
        {
            "id": "79208585-e4d2-4142-aafd-e76b851ffb88",
            "name": "Regular",
            "shorthandName": "REG",
            "hexColor": "#f97316",
            "type": "hours",
            "value": 1
        }
    ],
    "cursor": null
}
```

## Best Practices

* Always treat cursor values as opaque strings
* Process items in batches rather than loading all pages at once for large datasets
* Consider implementing pagination limits in your application to avoid memory issues

<Info>
  Page counts are not currently provided in pagination responses. This may change
  (per-endpoint) in the future.
</Info>

## Implementation Examples

Below are basic examples of how to iterate through pages of a paginated endpoint in JavaScript and Python.

<CodeGroup>
  ```javascript fetchAllPages.js lines theme={null}
  async function fetchAllItems(endpoint, accessToken) {
      const allItems = [];
      let cursor = null;

      do {
          const url = new URL(`https://app.untetherlabs.com/api${endpoint}`);
          if (cursor) {
              url.searchParams.set('cursor', cursor);
          }

          const response = await fetch(url, {
              headers: {
                  Authorization: `Bearer ${accessToken}`,
              },
          });

          const data = await response.json();
          allItems.push(...data.items);
          cursor = data.cursor;
      } while (cursor !== null);

      return allItems;
  }

  // Usage
  const allPayCodes = await fetchAllItems('/v1/pay-codes', accessToken);
  ```

  ```python fetch_all_pages.py lines theme={null}
  import requests
  from urllib.parse import urljoin

  def fetch_all_items(endpoint, access_token):
      """Fetch all items from a paginated endpoint."""
      all_items = []
      cursor = None
      base_url = "https://app.untetherlabs.com/api"

      while True:
          url = urljoin(base_url, endpoint)
          headers = {"Authorization": f"Bearer {access_token}"}
          params = {"cursor": cursor} if cursor else {}

          response = requests.get(url, headers=headers, params=params)
          response.raise_for_status()

          data = response.json()
          all_items.extend(data["items"])

          cursor = data.get("cursor")
          if cursor is None:
              break

      return all_items

  # Usage
  all_pay_codes = fetch_all_items("/v1/pay-codes", access_token)
  ```
</CodeGroup>
