Pagination
All list endpoints use cursor-based pagination. Pass nextCursor on each request; stop when the response returns null.
How it works
Every list endpoint (GET /labels, GET /webhooks, GET /events) returns a page of items + a nextCursorstring. Pass that cursor on the next request to fetch the following page. The cursor is opaque — don't parse it; we may change its encoding without notice.
{
"data": [ ... ],
"nextCursor": "cur_DDD..."
}Iterating to completion
When nextCursor is null, you've reached the last page. A common pattern:
async function* allLabels() {
let cursor = null;
for (;;) {
const url = new URL("https://shiponline.app/api/v1/labels");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.SHIPONLINE_TOKEN}` },
});
const { data, nextCursor } = await res.json();
for (const label of data) yield label;
if (!nextCursor) return;
cursor = nextCursor;
}
}
for await (const label of allLabels()) {
console.log(label.id, label.status);
}Page sizes
- limit query param: 1–100 items per page. Default 25.
- Larger pages = fewer round-trips but slower per-request response. Default 25 is the right balance for interactive UI; use 100 for batch jobs.
Don't use offset pagination
Stability
The cursor reflects a point in the result set, not a snapshot of the database at request time. If a new label is created between two page requests, it may appear in your iteration (newer items are returned first; the cursor moves backward through time so newer-than-cursor items show up on the next page). Plan your iteration to handle this — typically by recording the latest createdAtyou've seen and ignoring subsequent items older than that.