Pagination
Which operations page, how the page cursor is numbered, and why there is no total count.
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
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.
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
| 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
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,48215Filter 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, where the accepted set for each
filter is published.