# Pagination (/pagination) Three list operations page, one does not, and the paging is zero-based with no total count. Getting the first two facts wrong silently skips or repeats records. ## Zero-based, and there is no total [#zero-based-and-there-is-no-total] `pageNumber` is an **offset in pages starting at 0**. The first page is `pageNumber=0`; passing `1` gives you the second page. A loop written as `for (let p = 1; ...)` skips the first page entirely and reports nothing wrong. No list operation returns a total count, a page count, or a has-more flag. **Detect the end by a short page**: fewer items than `pageSize` means you have reached the last one. ```js async function* allOrders(key, pageSize = 100) { for (let pageNumber = 0; ; pageNumber++) { const response = await fetch( `https://app.lettrlabs.com/api/v1/order?pageNumber=${pageNumber}&pageSize=${pageSize}`, { headers: { "X-API-KEY": key } }, ); const { payload } = await response.json(); const orders = payload.orders ?? []; yield* orders; if (orders.length < pageSize) return; } } ``` The `orders.length < pageSize` check is the end condition: a page shorter than you asked for is the last one. Records are ordered newest-first by creation date, and paging is by offset rather than by cursor. So an order created while you are part-way through a walk shifts everything down one place, and you can see the same record twice. For a reconciliation job, prefer filtering to a fixed set of order IDs over walking the whole list. ## Which operations page [#which-operations-page] | Operation | Parameters | Default page size | | -------------------------- | ------------------------------------------------ | ----------------- | | List orders | `pageNumber`, `pageSize` | 100 | | List an order's recipients | `pageNumber`, `pageSize`, plus `query` to filter | see the reference | | List conversions | **none** — returns everything | — | There is no maximum enforced on `pageSize`. A very large value will work until the response is big enough to time out, which surfaces as a `500` rather than as a clear error, so stay near the default and page rather than pulling everything at once. ## Filtering instead of paging [#filtering-instead-of-paging] For the order listing, filtering is usually better than walking. `id` accepts a comma-separated list, so if you track order IDs on your side you can fetch exactly the ones you care about: ``` GET /api/v1/order?id=48213,48214,48215 ``` Filter values are matched by equality and are **not validated**: a misspelled `status` or `product` returns `200` with an empty list rather than an error. Copy values from [the reference](/api-reference/orders/v1-order-get), where the accepted set for each filter is published.