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
| Parameter | Type | Default | Bounds |
|---|---|---|---|
limit | integer | 20 | 1–100 |
offset | integer | 0 | ≥ 0 |
Note: A small number of endpoints raise these defaults — most notably
GET /v2/usage(default100, max500) andGET /v2/billing(default50, max100). 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
}
}| Field | Type | Description |
|---|---|---|
limit | integer | Page size used for this response. |
offset | integer | Current offset. |
has_more | boolean | Whether more results exist beyond this page. |
next_offset | integer | null | Offset to fetch the next page, or null if this is the last page. |
prev_offset | integer | null | Offset 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_moreto decide whether to fetch another page; don't infer it fromdata.length. - Use
next_offsetfrom the response rather than recomputing it. - Pick a
limitclose 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
dataarray withhas_more: falseis the end of the list, not an error.
