Pagination

Cursor pagination with limit and next_token.

Collection endpoints page with an opaque forward cursor. There are no page numbers and no total count.

Requesting a page

ParameterTypeDefaultNotes
limitinteger20Items per page, 1–100
next_tokenstringCursor from the previous response
GET /merchants?limit=50
GET /merchants?limit=50&next_token=eyJwayI6IjNjMWU1YTkwI…

Reading the response

Pagination state lives in meta.pagination:

{
  "data": [ "…50 merchants…" ],
  "meta": {
    "correlation_id": "…",
    "item_count": 50,
    "pagination": {
      "limit": 50,
      "next_token": "eyJwayI6IjNjMWU1YTkwI…"
    }
  }
}

next_token absent means you have reached the end. That is the only end-of-collection signal — do not infer it from a short page, and do not keep paging until you get an empty array.

async function* allMerchants(campaignId) {
  let token;
  do {
    const url = new URL('https://api.acc.funtrips.io/v2/merchants');
    url.searchParams.set('limit', '100');
    if (token) url.searchParams.set('next_token', token);

    const res  = await fetch(url, { headers: { 'x-campaign-id': campaignId } });
    const body = await res.json();

    yield* body.data;
    token = body.meta?.pagination?.next_token;
  } while (token);
}

Rules for cursors

  • Opaque. A next_token is a base64 blob encoding our internal key position. Do not decode, construct, or modify one.
  • Do not persist them. They are meaningful for the duration of a traversal, not as bookmarks. Store the underlying ids instead.
  • Do not log them. They can contain partition-key values.
  • Send the same filters. Pass the identical limit, headers and query filters on each page. Changing filters mid-traversal produces undefined ordering.

Endpoints that page

EndpointOrdering
GET /merchantsKey order — stable, not chronological
GET /merchants/broadsearchRelevance. Paginated only when limit is sent
GET /merchants/searchRelevance, or distance when geo-filtering. Paginated only when limit is sent
GET /me/fulfillment/ordersNewest first by last_mutation_date
GET /me/loyalty/ledger/entriesNewest first

The two search endpoints are the exception worth remembering: omit limit and they return every match in one response, with no meta.pagination block at all. Always send limit in production — an unbounded search against a large catalog is a slow response for your customer and a 504 waiting to happen.


Did this page help you?