Pagination
All list endpoints in Tiqora use cursor-based pagination. This approach is more efficient than offset-based pagination for large datasets and guarantees consistent results even when data is being added or removed.
How It Works
Every list endpoint accepts two pagination parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
per_page |
integer | 25 | Number of items per page (max: 100) |
cursor |
string | — | Opaque cursor for the next page |
The response includes a meta object with pagination information:
{
"data": [...],
"meta": {
"per_page": 25,
"has_more": true,
"next_cursor": "eyJpZCI6IjAxOTEyMzQ1LTY3ODktN2FiYy1kZWYwLTEyMzQ1Njc4OWFiYyJ9"
}
}
| Meta Field | Description |
|---|---|
per_page |
Items returned per page |
has_more |
true if more items exist |
next_cursor |
Opaque string to pass as cursor param for next page. null when no more pages. |
Fetching Pages
First Page
GET /api/v1/external/tickets?per_page=25
Next Page
Take next_cursor from the previous response and pass it as cursor:
GET /api/v1/external/tickets?per_page=25&cursor=eyJpZCI6IjAxOTEyMzQ1In0=
Complete Traversal
async function fetchAllTickets() {
const allTickets = [];
let cursor = null;
do {
const params = new URLSearchParams({ per_page: '100' });
if (cursor) params.set('cursor', cursor);
const response = await tiqoraRequest(
'GET',
`/api/v1/external/tickets?${params}`
);
allTickets.push(...response.data);
cursor = response.meta.has_more ? response.meta.next_cursor : null;
} while (cursor);
return allTickets;
}
Python
def fetch_all_tickets():
all_tickets = []
cursor = None
while True:
params = {'per_page': 100}
if cursor:
params['cursor'] = cursor
query = '&'.join(f'{k}={v}' for k, v in params.items())
response = tiqora_request('GET', f'/api/v1/external/tickets?{query}')
all_tickets.extend(response['data'])
if not response['meta']['has_more']:
break
cursor = response['meta']['next_cursor']
return all_tickets
Combining Pagination with Filters
Filters and pagination work together. Filters are applied first, then results are paginated:
GET /api/v1/external/tickets?status=open&priority=high&per_page=50
The cursor encodes the filter state, so you can safely paginate through filtered results without them changing.
Important Notes
- Cursors are opaque — Don't try to decode, construct, or modify cursor values. Treat them as opaque strings.
- Cursors expire — Cursors are tied to a specific query. Don't reuse cursors across different filter combinations.
- Use
per_page=100for bulk operations — This minimizes the number of API calls needed. - Order is consistent — Results are ordered by
created_at DESCby default (newest first). You can change the sort order withsort_byandsortparameters where supported.
Hint: If you need to sync all data, paginate through the entire dataset once, then use webhooks to stay up-to-date with changes going forward. This avoids repeated full scans.