# Pagination

> Navigate large result sets with cursor-based pagination.

- **Category:** Getting Started
- HTML version: https://www.ondayzero.com/docs/guides/pagination
- All guides: https://www.ondayzero.com/docs/guides/index.md
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

# Pagination

All list endpoints use **cursor-based pagination** for efficient, consistent traversal of large datasets. There is no offset paging.

## How It Works

```bash
curl "https://api.ondayzero.com/api/v1/transactions?limit=25" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Accept: application/json"
```

Response:

```json
{
  "success": true,
  "data": {
    "items": [ ... ],
    "next_cursor": "eyJpZCI6IjAxOTEyMzQ1LWFiY2QtNzAwMC04MDAwLTAwMDAwMDAwMDA1MCJ9",  // pragma: allowlist secret
    "prev_cursor": null,
    "has_next": true,
    "has_prev": false,
    "limit": 25,
    "total": null
  }
}
```

To get the next page, pass `cursor`:

```bash
curl "https://api.ondayzero.com/api/v1/transactions?limit=25&cursor=eyJpZCI6..." \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Accept: application/json"
```

Keep going until `has_next` is `false`. To walk backwards, pass `prev_cursor` as `cursor` together with `direction=prev`.

## Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `limit` | integer | endpoint-specific | Items per page, 1–1000. Always pass it explicitly |
| `cursor` | string | null | `next_cursor` (or `prev_cursor`) from the previous page |
| `direction` | string | `next` | `next` or `prev` |
| `sort_by` | string | endpoint-specific (usually `created_at`) | Column to sort by, e.g. `created_at`, `amount`, `name` |
| `descending` | boolean | `true` | `true` = newest/largest first |
| `include_total_count` | boolean | `false` | Populate `total` (runs a full count query — expensive) |

## Response fields

| Field | Description |
|-------|-------------|
| `items` | The page of records |
| `next_cursor` / `prev_cursor` | Opaque cursors for the adjacent pages; `null` when there is none |
| `has_next` / `has_prev` | Whether an adjacent page exists |
| `limit` | The page size applied |
| `total` | Total matching records, only when `include_total_count=true`; otherwise `null` |

A few older endpoints return a subset of these fields (for example only `items`, `next_cursor` and `has_next`); check the endpoint's page in the API Reference.

## Tips

- **Don't store cursors long-term** — they encode a point-in-time position.
- **Reset the cursor when changing `sort_by` or filters** — cursors are tied to the sort order and query.
- **Avoid `include_total_count`** on large tables — it requires a full count query.
- **Filter before you page.** Most list endpoints take filters (`status`, `customer_id`, date ranges, `search`, …); a filtered request is cheaper than paging through everything client-side.
- When `has_next` is `false`, you've reached the end.
