Pagination
Every list endpoint pages the same way: ask for a limit, get back a page plus
a nextCursor, pass that cursor to get the next page, stop when it's null.
| Field | Where | Notes |
|---|---|---|
limit | request | Page size. Each endpoint's default and ceiling are listed below. |
cursor | request | The previous response's nextCursor. Omit for the first page. |
nextCursor | response | Always present. null means you've read everything. |
# first page
curl "https://api.dealops.com/external/v1/products?limit=100" \
-H "x-api-key: $DEALOPS_API_KEY"
# next page
curl "https://api.dealops.com/external/v1/products?limit=100&cursor=$NEXT_CURSOR" \
-H "x-api-key: $DEALOPS_API_KEY"
def read_all(path, collection, **params):
cursor, items = None, []
while True:
page = get(path, params={**params, "cursor": cursor} if cursor else params)
items.extend(page[collection])
cursor = page["nextCursor"] # always present
if cursor is None: # the only stopping condition
break
return items
products = read_all("/products", "products", limit=100)
Loop on nextCursor, never on "did I get a full page?" — a page that comes back
exactly limit long can still be the last one, and a page can legitimately come
back shorter than limit with more to follow.
Cursors are opaque
A cursor is a string we generate for you to hand back unchanged. Don't parse it,
build one, or store it long-term — its contents are an implementation detail and
differ between endpoints. A cursor that isn't one we issued is rejected with
400.
Cursors are safe to use across a paging walk that takes a while: they resume from a position rather than a row, so an item deleted between your calls doesn't strand you.
Page sizes
| Endpoint | Default | Max |
|---|---|---|
GET /products | 100 | 500 |
GET /pricing-quotes | 100 | 500 |
GET /webhook-configs | 100 | 500 |
GET /webhook-configs/{id}/deliveries | 50 | 500 |
GET /approval-rules | 100 | 500 |
GET /approval-rule-groups | 100 | 500 |
GET /approval-groups | 100 | 500 |
GET /approvals | 20 | 100 |
A limit outside the range is a 400 — it isn't clamped silently.
Ordering
GET /approvals and GET /webhook-configs/{id}/deliveries read newest-first.
Every other list endpoint returns items in a stable internal order that's
consistent across pages but not otherwise meaningful — sort client-side if you
need a particular one.
Reading a moving collection
Most of these endpoints page from a snapshot of your organization's collection.
For GET /approvals and GET /approval-rules, the cursor resumes by position,
so a row inserted or removed ahead of your cursor mid-walk shifts the window and
you can see an item twice or miss one. For an audit-grade sweep, filter to a set
that won't change while you page (for example an /approvals status that has
already settled), or reconcile by id afterwards.
Endpoints that aren't paged
GET /deal-groups takes a required opportunityId and returns the deal groups
that one opportunity belongs to — a bounded lookup rather than a collection, so
it takes no paging parameters.
GET /approvals also accepts offset and count, which predate this
convention. They still work, and the API reference marks them deprecated. Use
limit and cursor.