Listing and Pagination
Every GET endpoint that returns a collection (/v1/portal_users, /v1/dashboard_users, /v1/team_roles, etc.) uses page-number pagination.
Parameters
Sent in the query string:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer ≥ 1 | 1 | Requested page (starts at 1). |
per_page | integer 1–100 | 20 | Items per page. Maximum 100. |
sort_by | string | varies by resource | Field used for sorting. Accepts the same names as the response. |
sort_order | asc or desc | desc | Sort direction. |
Out-of-range values are clamped (e.g. per_page=999 becomes 100; page=0 becomes 1).
Response
Every listing follows this envelope:
{
"data": [
{ "id": "8b2f4c1e-6a3d-4f0b-9c7e-2d5a1b3c4d5e", "email": "joao@example.com", "status": "active", "tenant_id": "cliente-1042" }
],
"meta": {
"total": 142,
"page": 1,
"per_page": 20,
"total_pages": 8
}
}
| Field | Description |
|---|---|
data | Array with the items of the current page. |
meta.total | Total items matching the filters (not just the ones returned). |
meta.page | Current page. |
meta.per_page | Items per page actually applied. |
meta.total_pages | Total number of pages (ceil(total / per_page)). |
The last page may contain fewer than per_page items. When page > total_pages, data is empty (not an error).
Examples
First page, default
curl -H "Authorization: Bearer $KOBANA_TOKEN" \
'https://api.dashboards.sandbox.kobana.com.br/v1/portal_users'
Page 3 with 50 items
curl -H "Authorization: Bearer $KOBANA_TOKEN" \
'https://api.dashboards.sandbox.kobana.com.br/v1/portal_users?page=3&per_page=50'
Sorted by created_at ascending
curl -H "Authorization: Bearer $KOBANA_TOKEN" \
'https://api.dashboards.sandbox.kobana.com.br/v1/portal_users?sort_by=created_at&sort_order=asc'
Filters + pagination
Resource-specific filters work together with page/per_page:
curl -H "Authorization: Bearer $KOBANA_TOKEN" \
'https://api.dashboards.sandbox.kobana.com.br/v1/portal_users?status=active&email=joao&page=2&per_page=25'
Iterating over all pages
Recommended pattern in pseudo-code:
async function fetchAll(url, token) {
const out = [];
let page = 1;
while (true) {
const res = await fetch(`${url}?page=${page}&per_page=100`, {
headers: { Authorization: `Bearer ${token}` },
});
const { data, meta } = await res.json();
out.push(...data);
if (page >= meta.total_pages) break;
page += 1;
}
return out;
}
Best practices
- For incremental sync, prefer filtering by
updated_at_gte(or a similar filter available on the endpoint) instead of scanning every page. per_page=100minimizes the number of requests and uses less of the rate limit.- Cache
meta.totalwhen rendering paginators; don't recompute it on every navigation. - Don't assume a stable order without an explicit
sort_by— the default order may differ between resources.