# Pagination

URL: https://docs.sparklayer.io/developers/pagination

Page through large result sets in the SparkLayer APIs: page-based pagination for price lists, offset paging for purchases, and which lists return everything.

> **For AI assistants:** these facts apply to every SparkLayer API call.
>
> - **Base URLs:** Live `https://app.sparklayer.io`, test `https://test.app.sparklayer.io`. Each environment has its own data and its own API keys.
> - **Access:** API access needs the Pro or Enterprise plan. Create credentials (Site ID, Client ID, Client Secret) in the SparkLayer Dashboard at Settings > API.
> - **Access token:** `POST {base}/api/auth/token` with a `Site-Id` header and a JSON body (not form-encoded): `{"grant_type":"client_credentials","client_id":"…","client_secret":"…"}`. It returns `access_token`, valid for 3,600 seconds. There is no refresh token: cache the token and request a new one shortly before it expires.
> - **Every request:** `Authorization: Bearer <access_token>` and `Site-Id: <site id>`, plus `Content-Type: application/json` when there is a body. Set a `User-Agent` that names your integration.
> - **Errors:** RFC 7807 problem details: `title`, `status`, `detail` and an optional `errors[]` of `{ code, message, property }`. Some error responses have no body. Retry `5xx`, `429` (honouring `Retry-After`) and concurrent-update `409`s with exponential backoff; on `401`, get a new token once and retry; don't retry other `4xx` without changing the request.
> - **Pagination:** Most list endpoints return everything. `GET /api/v2/price-lists` pages with `page` and `page_size` (up to 250) until `pagination.current_page` equals `total_pages`. `GET /api/v1/purchases` uses `limit` (up to 500) and `offset`: stop when a page has fewer than `limit` results.
> - **Ground rules:** Use only endpoints, fields and SDK methods that the docs or OpenAPI specs define. Prefer `GET /api/v2/price-lists` over the deprecated v1. Products are matched by SKU. Keep credentials in environment variables or a secrets manager, never in code.
> - **Read the docs as Markdown:** Add `.md` to any page URL. Index of every page: https://docs.sparklayer.io/llms.txt. Every API operation, compactly: https://docs.sparklayer.io/llms-api.txt. The developer guides in full: https://docs.sparklayer.io/developers/llms.txt.
> - **OpenAPI specs:** `core`, `ordering`, `pricing`, `purchasing`, `stock`, `files`, `sync-log`: https://docs.sparklayer.io/openapi/<api>.yaml (also `.json`). Ignite: https://docs.sparklayer.io/openapi/ignite.yaml.
> - **MCP:** Search and read these docs from your assistant with the docs MCP server at https://docs.sparklayer.io/mcp.

Most SparkLayer list endpoints return every matching record in a single response. Two endpoint families paginate, each with its own pattern.

## Page-based: price lists

`GET /api/v2/price-lists` and `GET /api/v2/price-lists-num-manual-prices` in the [Pricing API](https://docs.sparklayer.io/developers/api/pricing.md) return results one page at a time.

| Query parameter | Default | Description |
| --- | --- | --- |
| `page` | `1` | The page to return |
| `page_size` | `100` | Records per page, up to `250` |
| `order_by` | `name:asc` | Sort field and direction: `name`, `created_at` or `updated_at`, followed by `:asc` or `:desc` |

The response wraps the records in `data`, with a `pagination` object:

```json
{
  "data": [ … ],
  "pagination": {
    "total": 312,
    "per_page": 100,
    "current_page": 1,
    "total_pages": 4
  }
}
```

Request pages until `current_page` equals `total_pages`:

```bash
curl "https://app.sparklayer.io/api/v2/price-lists?page=2&page_size=100" \
  -H "Site-Id: <SITE_ID>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"
```

> **Use v2 for price lists**
>
> `GET /api/v1/price-lists` is the older, unpaginated version of this endpoint: it returns up to 25,000 price lists in one array. Use `GET /api/v2/price-lists` for new integrations.

## Offset-based: purchases

`GET /api/v1/purchases` in the [Purchasing API](https://docs.sparklayer.io/developers/api/purchasing.md) uses a limit and an offset.

| Query parameter | Default | Description |
| --- | --- | --- |
| `limit` | Not set | Maximum number of purchases to return, from `1` to `500`. Always set it. |
| `offset` | `0` | Number of purchases to skip |
| `order_by` | `created_at` | Field to sort by, always newest first: `created_at`, `updated_at`, `placed_at`, `calculated_submitted_at` or `shipping_requested_date` |

The response is a plain array with no total count. To fetch every purchase, increase `offset` by `limit` after each request, and stop when a response contains fewer than `limit` purchases:

```bash
curl "https://app.sparklayer.io/api/v1/purchases?type=order&limit=500&offset=500" \
  -H "Site-Id: <SITE_ID>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"
```

Keep `order_by` and any filters the same for every page. Records created or updated while you're paging can shift between pages, so use a date filter such as `dates[last_updated][gte]` for incremental syncs.

## Endpoints that aren't paginated

Other list endpoints return all matching records in one response, including the Core API's customer groups, discounts, shipping methods and settings, and the Stock API's stock locations. A few have a fixed upper limit:

- **List sync errors** in the [Sync Logging API](https://docs.sparklayer.io/developers/api/sync-log.md) returns at most 5,000 errors.
- **List price lists** (v1) returns at most 25,000 price lists.
