Pagination
Cursor pagination and incremental sync crawls.
The lists that can grow large use cursor pagination (products, listings, orders, events, operations, actions, ignored listings, companies, storefront orders):
curl "https://api.nembol.com/rest/v1/products?limit=50" \
-H "Authorization: Bearer $NEMBOL_API_KEY"{
"data": [ { "id": "…" } ],
"has_more": true,
"next_cursor": "eyJ1IjoiMjAyNi0wNy0yNFQx…"
}Pass next_cursor back as ?cursor= to get the next page. When has_more
is false, you're done. limit is 1–100 (default 25). Cursors are opaque.
Don't parse or store them long-term. A cursor Nembol didn't give (truncated,
edited, empty) answers 422 validation_failed with param: cursor: it is
never read as the first page.
Lists without a cursor
A few lists are small by nature, or capped, and come back in one response.
They have no limit / cursor; where has_more is present it is always
false.
| List | How it pages |
|---|---|
GET /customers | Page-based: page (from 1), limit 1–100, total in the answer |
GET /promotions | The 200 most recent. Older ones are still reachable by id (GET /promotions/{id}) |
GET /notifications | The 200 most recent |
GET /storefront/discounts, GET /storefront/bundles | All of them, in one response |
GET /channel_accounts, GET /webhook_endpoints, GET /redirect_urls, GET /error_fixes | All of them, in one response (a store has a handful) |
GET /sales, GET /catalog/diagnostics | Reports: one object, no list |
Ordering guarantee
Lists are ordered newest first with a stable id tiebreak: products and
listings by updated_at, orders by created_at (the time the order was
placed), events by created_at. This order is part of the contract. Pages never skip or repeat items within
a single crawl.
Incremental sync
To keep an external system in sync without re-reading everything, crawl with
updated_after:
curl "https://api.nembol.com/rest/v1/products?updated_after=2026-07-24T00:00:00Z&limit=100" \
-H "Authorization: Bearer $NEMBOL_API_KEY"Record the timestamp you started the crawl at, page through to the end, then
use that timestamp as the next crawl's updated_after. Deleted and merged
products leave the default list: to catch them in a crawl, also read
status=archived&updated_after=… (or use the product.deleted webhook). (For push-based sync,
use webhooks instead. Crawling is the reconciliation
fallback.)
Orders that changed. GET /orders?updated_after=… returns the orders
placed or changed (status, fulfillment, tracking: e.g. cancelled or
refunded on the channel) after that time; each order's updated_at says
when it last changed. Poll with the time of your previous poll. For push,
use the order.created and order.status_changed webhooks.
Last updated on October 18, 2026
Need help?
Email us and a human replies, usually within one business day.