Pagination

Offset-based pagination, response envelope, and how to iterate through pages.

List endpoints use offset-based pagination. Two query parameters drive it, and every paginated response carries the same envelope so you can iterate without endpoint-specific logic.

Query parameters

ParameterTypeDefaultBounds
limitinteger201100
offsetinteger0≥ 0

Note: A small number of endpoints raise these defaults — most notably GET /v2/usage (default 100, max 500) and GET /v2/billing (default 50, max 100). Always check the per-operation schema in the OpenAPI spec for the authoritative bounds.

Response envelope

{
  "data": [ /* items */ ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "has_more": true,
    "next_offset": 20,
    "prev_offset": null
  }
}
FieldTypeDescription
limitintegerPage size used for this response.
offsetintegerCurrent offset.
has_morebooleanWhether more results exist beyond this page.
next_offsetinteger | nullOffset to fetch the next page, or null if this is the last page.
prev_offsetinteger | nullOffset for the previous page, or null if this is the first page.

A few endpoints extend the envelope with additional fields — for example, GET /v2/invoices adds a total count of matching invoices across all pages. Per-operation schemas in the OpenAPI spec are authoritative.

Example: first page

GET https://api.benjipays.com/v2/partners?limit=20&offset=0
Authorization: Bearer YOUR_ACCESS_TOKEN
{
  "data": [
    { "partnerId": "6022f98854f2c41d7ef2b1fe", "name": "Acme MSP", "externalId": "acme-001" }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "has_more": true,
    "next_offset": 20,
    "prev_offset": null
  }
}

Example: next page

GET https://api.benjipays.com/v2/partners?limit=20&offset=20
Authorization: Bearer YOUR_ACCESS_TOKEN
{
  "data": [ /* ... 20 items starting from offset 20 */ ],
  "pagination": {
    "limit": 20,
    "offset": 20,
    "has_more": true,
    "next_offset": 40,
    "prev_offset": 0
  }
}

Example: last page

{
  "data": [ /* ... remaining items (less than `limit`) */ ],
  "pagination": {
    "limit": 20,
    "offset": 60,
    "has_more": false,
    "next_offset": null,
    "prev_offset": 40
  }
}

Iterating through all pages

async function fetchAllPartners(accessToken) {
  const all = [];
  let offset = 0;
  const limit = 20;
  let hasMore = true;

  while (hasMore) {
    const response = await fetch(
      `https://api.benjipays.com/v2/partners?limit=${limit}&offset=${offset}`,
      { headers: { Authorization: `Bearer ${accessToken}` } }
    );
    const body = await response.json();
    all.push(...body.data);
    hasMore = body.pagination.has_more;
    offset = body.pagination.next_offset ?? offset + limit;
  }

  return all;
}

Best practices

  • Use has_more to decide whether to fetch another page; don't infer it from data.length.
  • Use next_offset from the response rather than recomputing it.
  • Pick a limit close to your actual rendering / processing batch size.
  • Respect rate limits when iterating — pace your requests so you don't burst through your quota.
  • An empty data array with has_more: false is the end of the list, not an error.