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
limitinteger2011000
offsetinteger0≥ 0

Note: Merchant list endpoints such as transactions, invoices, customers, emails, and payment-methods allow limit up to 1000. A few endpoints differ — most notably GET /v2/usage (default 100, max 500), GET /v2/billing (default 50, max 100), and GET /v2/autoprocessing-forecast (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,
    "hasMore": true,
    "nextOffset": 20,
    "prevOffset": null
  }
}
FieldTypeDescription
limitintegerPage size used for this response.
offsetintegerCurrent offset.
hasMorebooleanWhether more results exist beyond this page.
nextOffsetinteger | nullOffset to fetch the next page, or null if this is the last page.
prevOffsetinteger | nullOffset for the previous page, or null if this is the first page.

Many merchant list endpoints also include pagination.total (count of matching items across all pages):

  • GET /v2/invoices
  • GET /v2/customers
  • GET /v2/payment-methods
  • GET /v2/transactions
  • GET /v2/emails
  • GET /v2/users
  • GET /v2/autoprocessing-forecast

Per-operation schemas in the OpenAPI spec are authoritative.

Example: first page

GET https://api.benjipays.com/v2/transactions?limit=20&offset=0
x-api-key: YOUR_API_KEY
{
  "data": [
    { "id": "txn_abc123", "status": "approved" }
  ],
  "pagination": {
    "total": 150,
    "limit": 20,
    "offset": 0,
    "hasMore": true,
    "nextOffset": 20,
    "prevOffset": null
  }
}

Example: next page

GET https://api.benjipays.com/v2/transactions?limit=20&offset=20
x-api-key: YOUR_API_KEY
{
  "data": [ /* ... 20 items starting from offset 20 */ ],
  "pagination": {
    "total": 150,
    "limit": 20,
    "offset": 20,
    "hasMore": true,
    "nextOffset": 40,
    "prevOffset": 0
  }
}

Example: last page

{
  "data": [ /* ... remaining items (less than `limit`) */ ],
  "pagination": {
    "total": 150,
    "limit": 20,
    "offset": 140,
    "hasMore": false,
    "nextOffset": null,
    "prevOffset": 120
  }
}

Iterating through all pages

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

  while (hasMore) {
    const response = await fetch(
      `https://api.benjipays.com/v2/transactions?limit=${limit}&offset=${offset}`,
      { headers: { 'x-api-key': apiKey } }
    );
    const body = await response.json();
    all.push(...body.data);
    hasMore = body.pagination.hasMore;
    offset = body.pagination.nextOffset ?? offset + limit;
  }

  return all;
}

Best practices

  • Use hasMore to decide whether to fetch another page; don't infer it from data.length.
  • Use nextOffset 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 hasMore: false is the end of the list, not an error.

Did this page help you?