Skip to content
Elara One docs

Pagination

Page through lists with page and perPage, read links and meta, use cursors on merchant lists, and sync CRM records incrementally with filter[updated_since].

Lists that can grow come back one page at a time. Storefront lists use numbered pages. Merchant lists, such as CRM contacts and orders, use cursors, which stay correct while records are being added and changed.

Numbered pages

Storefront lists take two query parameters:

ParameterDefaultRange
perPage241 to 100. Larger values are capped at 100.
page11 and up

They apply to GET /v1/products, GET /v1/collections, GET /v1/collections/{slug}/products, GET /v1/search and a signed-in customer's GET /v1/orders. Note the camel case: perPage, not per_page.

curl -G https://api.elaraone.app/api/v1/products \
  -H "X-Tenant-Key: $ELARAONE_TENANT_KEY" \
  -H "X-Tenant-Secret: $ELARAONE_TENANT_SECRET" \
  --data-urlencode "perPage=48" \
  --data-urlencode "page=2"

The response carries links and meta next to data:

Response (trimmed)
{
  "data": [ … ],
  "links": {
    "first": "https://api.elaraone.app/api/v1/products?perPage=48&page=1",
    "last": "https://api.elaraone.app/api/v1/products?perPage=48&page=3",
    "prev": "https://api.elaraone.app/api/v1/products?perPage=48&page=1",
    "next": "https://api.elaraone.app/api/v1/products?perPage=48&page=3"
  },
  "meta": {
    "current_page": 2,
    "from": 49,
    "last_page": 3,
    "per_page": 48,
    "to": 96,
    "total": 131,
    "path": "https://api.elaraone.app/api/v1/products"
  }
}
  • links.next is null on the last page, and links.prev on the first.
  • meta.total and meta.last_page are what you need for page numbers.
  • The links keep your other query parameters, such as filters and sorts.
  • A page past the end returns an empty data list, not an error.

Lists that are always short are not paginated: GET /v1/promotions, GET /v1/countries, GET /v1/cart/shipping-options and GET /v1/account/addresses return everything at once.

Cursors on merchant lists

The merchant CRM lists (contacts, companies, tasks and their related records) and the merchant orders list use cursor pagination:

ParameterMeaning
perPage1 to 100, default 24. A value outside the range returns 422.
cursormeta.next_cursor or meta.prev_cursor from the previous page
sortA sort the list allows, with - for descending
Response (trimmed)
{
  "data": [ … ],
  "links": { "first": null, "last": null, "prev": null, "next": "https://api.elaraone.app/api/v1/merchant/crm/contacts?cursor=eyJ…" },
  "meta": {
    "path": "https://api.elaraone.app/api/v1/merchant/crm/contacts",
    "per_page": 24,
    "next_cursor": "eyJ…",
    "prev_cursor": null
  }
}

Keep requesting with cursor set to meta.next_cursor until it is null. Treat cursors as opaque: pass them back exactly as you received them. Cursor lists have no total.

An unknown filter[…] or sort on these lists returns 400; a malformed value, such as a date that cannot be read, returns 422 VALIDATION_FAILED.

Incremental sync with filter[updated_since]

To keep another system in step with the store's CRM, do not re-read everything on every run. The CRM contacts, companies and tasks lists take filter[updated_since], an ISO 8601 time, and return only records changed at or after it.

Run a full sync once

Page through the whole list with sort=updated_at and store each record. Note the time you started.

Then fetch only what changed

On each later run, ask for records changed since the start of the previous run, and page through them the same way.

Move the mark forward

When the run finishes, save its start time as the next run's updated_since.

curl -G https://api.elaraone.app/api/v1/merchant/crm/contacts \
  -H "X-Tenant-Key: $ELARAONE_TENANT_KEY" \
  -H "X-Tenant-Secret: $ELARAONE_TENANT_SECRET" \
  -H "Authorization: Bearer $ELARAONE_MERCHANT_API_KEY" \
  --data-urlencode "filter[updated_since]=2026-10-23T02:00:00Z" \
  --data-urlencode "sort=updated_at" \
  --data-urlencode "perPage=100"
  • Use the start of the previous run, not its end, so a record changed while the run was in progress is picked up next time. You may see a few records twice; make your writes idempotent by record id.
  • A tag change counts as a change to the contact.
  • Pair the sync with CRM change webhooks if you want to hear about changes as they happen, and keep the sync as a safety net.
  • Stay inside the store's API budget: see rate limits.