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

# Pagination

> The limit/skip contract and response shapes used by list endpoints

Most list endpoints across the Integration and Admin APIs share a common pagination contract. This page documents the shape so you can build a single helper and reuse it everywhere.

## Query parameters

| Parameter | Type    | Default           | Notes                                                                                                                                    |
| --------- | ------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `limit`   | integer | `10`              | Maximum number of items to return. Upper bound is typically `100`.                                                                       |
| `skip`    | integer | `0`               | Number of items to skip before returning the page.                                                                                       |
| `search`  | string  | —                 | Case-insensitive substring match on the entity's primary text fields.                                                                    |
| `sort`    | string  | endpoint-specific | A sort directive (e.g. `-createdAt` for descending). Not every list endpoint supports arbitrary sort keys — check the endpoint's schema. |

Date-range filters use the conventions `fromDate` / `toDate` on most endpoints. A few older endpoints use `startDate` / `endDate` — check the endpoint page for the canonical parameter names.

## Response shape

Most paginated endpoints return an envelope:

```json theme={null}
{
  "totalCount": 142,
  "edges": [
    { /* entity */ },
    { /* entity */ }
  ]
}
```

| Field        | Description                                                                                      |
| ------------ | ------------------------------------------------------------------------------------------------ |
| `totalCount` | Total number of matching entities, ignoring `limit` and `skip`. Use this to drive pagination UI. |
| `edges`      | Array of entities for the current page. Array length is at most `limit`.                         |

<Note>
  A handful of older list endpoints return `{ items }` or a bare array instead of `{ totalCount, edges }`. The endpoint page will reflect the actual schema — always prefer the per-endpoint schema over assumptions.
</Note>

## Requesting a page

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://{subdomain}.nudj.cx/api/v2/admin/challenges?limit=20&skip=40" \
    -H "Authorization: Bearer $NUDJ_API_TOKEN" \
    -H "Content-Type: application/json"
  ```

  ```javascript JavaScript theme={null}
  async function listChallenges({ limit = 20, skip = 0 } = {}) {
    const url = new URL(`https://${DOMAIN}/api/v2/admin/challenges`);
    url.searchParams.set('limit', limit);
    url.searchParams.set('skip', skip);

    const response = await fetch(url, {
      headers: { 'Authorization': `Bearer ${process.env.NUDJ_API_TOKEN}` },
    });
    return response.json(); // { totalCount, edges }
  }
  ```

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

  def list_challenges(limit=20, skip=0):
      response = requests.get(
          f"https://{DOMAIN}/api/v2/admin/challenges",
          params={"limit": limit, "skip": skip},
          headers={"Authorization": f"Bearer {os.environ['NUDJ_API_TOKEN']}"},
      )
      return response.json()  # { totalCount, edges }
  ```
</CodeGroup>

## Paginating through every page

```javascript theme={null}
async function* paginateAll(path, pageSize = 100) {
  let skip = 0;
  while (true) {
    const page = await nudjRequest(`${path}?limit=${pageSize}&skip=${skip}`);
    for (const edge of page.edges) yield edge;
    skip += page.edges.length;
    if (skip >= page.totalCount || page.edges.length === 0) return;
  }
}

for await (const challenge of paginateAll('/api/v2/admin/challenges')) {
  // …
}
```

## Common errors

| Status                                                 | Cause                                       | Fix                                                     |
| ------------------------------------------------------ | ------------------------------------------- | ------------------------------------------------------- |
| `400 BAD_REQUEST` — `limit` must be a positive integer | Non-integer or negative `limit`             | Use a positive integer, capped at 100                   |
| `400 BAD_REQUEST` — `skip` must be non-negative        | Negative `skip`                             | Use `0` or a positive integer                           |
| `400 BAD_REQUEST` — Invalid sort key                   | Endpoint doesn't support the requested sort | Check the endpoint's schema for supported `sort` values |

See [Errors](/api-reference/errors) for the full envelope.

## Related

<CardGroup cols={2}>
  <Card title="Errors" icon="triangle-exclamation" href="/api-reference/errors">
    Error envelope and common status codes.
  </Card>

  <Card title="Internationalization" icon="language" href="/api-reference/internationalization">
    Translating response bodies with `x-language`.
  </Card>
</CardGroup>
