Pagination
Most list endpoints return paginated responses to handle large datasets efficiently. This guide covers how to work with paginated results.
Pagination Types
The API supports two pagination strategies:
| Type | Best For | Parameters |
|---|---|---|
| Offset-based | Small datasets, random access | page, limit |
| Cursor-based | Large datasets, real-time data | cursor, limit |
Offset-Based Pagination
Request Parameters
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
page | integer | 1 | - | Page number (1-indexed) |
limit | integer | 20 | 100 | Items per page |
Example Request
curl -X GET "https://platform.powerverse.com/inventory-service/sites?page=2&limit=25" \
-H "Authorization: Bearer YOUR_TOKEN"
Response Format
{
"data": [
{ "id": "sit_026", "name": "Site 26" },
{ "id": "sit_027", "name": "Site 27" }
],
"pagination": {
"page": 2,
"limit": 25,
"total": 150,
"total_pages": 6,
"has_next": true,
"has_prev": true
}
}
Navigating Pages
- Python
- JavaScript
def fetch_all_sites(api_client):
"""Fetch all sites across all pages."""
all_sites = []
page = 1
while True:
response = api_client.get('/inventory-service/sites', params={
'page': page,
'limit': 100
})
all_sites.extend(response['data'])
if not response['pagination']['has_next']:
break
page += 1
return all_sites
async function fetchAllSites(apiClient) {
const allSites = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await apiClient.get('/inventory-service/sites', {
params: { page, limit: 100 }
});
allSites.push(...response.data);
hasMore = response.pagination.has_next;
page++;
}
return allSites;
}
Cursor-Based Pagination
Cursor pagination is recommended for large or frequently changing datasets.
Request Parameters
| Parameter | Type | Description |
|---|---|---|
cursor | string | Opaque cursor from previous response |
limit | integer | Items per page (max 100) |
Example Request
# First request (no cursor)
curl -X GET "https://platform.powerverse.com/asset-controls/events?limit=50" \
-H "Authorization: Bearer YOUR_TOKEN"
# Subsequent requests (with cursor)
curl -X GET "https://platform.powerverse.com/asset-controls/events?cursor=eyJpZCI6MTAwfQ&limit=50" \
-H "Authorization: Bearer YOUR_TOKEN"
Response Format
{
"data": [
{ "id": "evt_1", "type": "session_started", "status": "completed" },
{ "id": "evt_2", "type": "schedule_triggered", "status": "pending" }
],
"pagination": {
"cursor": "eyJpZCI6MTAwfQ",
"next_cursor": "eyJpZCI6MTUwfQ",
"has_next": true,
"limit": 50
}
}
Navigating with Cursors
def fetch_all_events(api_client):
"""Fetch all events using cursor pagination."""
all_events = []
cursor = None
while True:
params = {'limit': 100}
if cursor:
params['cursor'] = cursor
response = api_client.get('/asset-controls/events', params=params)
all_events.extend(response['data'])
if not response['pagination']['has_next']:
break
cursor = response['pagination']['next_cursor']
return all_events
Sorting
Combine pagination with sorting:
# Sort by creation date, newest first
curl -X GET "https://platform.powerverse.com/inventory-service/assets?sort=-created_at&limit=25" \
-H "Authorization: Bearer YOUR_TOKEN"
Sort Syntax
| Syntax | Description |
|---|---|
field | Ascending order |
-field | Descending order |
field1,-field2 | Multiple sort fields |
Sortable Fields
Each endpoint documents its sortable fields. Common ones include:
created_at- Creation timestampupdated_at- Last update timestampname- Alphabetical by namestatus- By status value
Filtering
Combine pagination with filters:
curl -X GET "https://platform.powerverse.com/inventory-service/assets?\
status=active&\
created_at[gte]=2024-01-01&\
limit=25" \
-H "Authorization: Bearer YOUR_TOKEN"
Filter Operators
| Operator | Description | Example |
|---|---|---|
eq | Equals (default) | status=active |
ne | Not equals | status[ne]=decommissioned |
gt | Greater than | capacity[gt]=100 |
gte | Greater or equal | created_at[gte]=2024-01-01 |
lt | Less than | capacity[lt]=1000 |
lte | Less or equal | created_at[lte]=2024-12-31 |
in | In list | status[in]=active,maintenance |
Best Practices
1. Use Appropriate Page Sizes
// ❌ Too small - many requests
const response = await api.get('/inventory-service/assets', { limit: 5 });
// ❌ Too large - slow responses
const response = await api.get('/inventory-service/assets', { limit: 1000 });
// ✅ Balanced
const response = await api.get('/inventory-service/assets', { limit: 50 });
2. Don't Rely on Total Count for Large Datasets
For performance, total may be approximate or omitted for very large datasets:
{
"pagination": {
"page": 1,
"limit": 100,
"total": null,
"has_next": true
}
}
3. Handle Empty Pages
async function processAssets(callback) {
let page = 1;
while (true) {
const response = await api.get('/inventory-service/assets', { page });
// Handle empty results
if (response.data.length === 0) {
break;
}
for (const asset of response.data) {
await callback(asset);
}
if (!response.pagination.has_next) {
break;
}
page++;
}
}
4. Use Cursor Pagination for Real-Time Data
Offset pagination can miss or duplicate items when data changes:
// ❌ With offset pagination, if a new item is inserted while paginating,
// you might see duplicates or miss items
// ✅ Cursor pagination maintains consistent position
let cursor = null;
while (true) {
const response = await api.get('/asset-controls/events', { cursor });
// Process events...
cursor = response.pagination.next_cursor;
if (!response.pagination.has_next) break;
}
5. Implement Parallel Fetching (When Order Doesn't Matter)
async function fetchAllSitesParallel(totalPages) {
const pagePromises = [];
for (let page = 1; page <= totalPages; page++) {
pagePromises.push(
api.get('/inventory-service/sites', { page, limit: 100 })
);
}
const responses = await Promise.all(pagePromises);
return responses.flatMap(r => r.data);
}
Link Headers (Alternative)
Some endpoints provide pagination links in headers:
HTTP/1.1 200 OK
Link: <https://platform.powerverse.com/inventory-service/sites?page=3>; rel="next",
<https://platform.powerverse.com/inventory-service/sites?page=1>; rel="prev",
<https://platform.powerverse.com/inventory-service/sites?page=10>; rel="last"
Parse and use these links:
function parseLinkHeader(header) {
if (!header) return {};
return header.split(',').reduce((links, part) => {
const [url, rel] = part.split(';');
const match = rel.match(/rel="(.+)"/);
if (match) {
links[match[1]] = url.trim().slice(1, -1);
}
return links;
}, {});
}
Next Steps
- Rate Limits - Understand request limits
- Error Handling - Handle pagination errors
- API Reference - See pagination for specific endpoints