How pagination works across all list endpoints: parameters, defaults, and iteration patterns.
Pagination
List endpoints in the UrbanPayX API return paginated results. This guide covers the pagination parameters, response format, and how to iterate through all results.
How it works
Most list endpoints use page-based pagination with two query parameters:
| Parameter | Description | Default |
|---|---|---|
page | Page number (starts at 1) | 1 |
page_size | Number of items per page | Varies by endpoint |
Results are always sorted by creation date, newest first.
Paginated response format
Most paginated responses put the rows in a resource-named array and the counters in a nested pagination object. The array key varies by endpoint - it is never literally items:
{
"transactions": [ ... ],
"pagination": {
"total": 142,
"page": 1,
"page_size": 10,
"total_pages": 15
}
}| Field | Description |
|---|---|
<resource> | Array of rows for the current page. Key name depends on the endpoint: transactions, users, business_customers, opcos, projects, tickets, invoices, notifications, ... |
pagination.total | Total number of items matching the query, across all pages |
pagination.page | Current page number |
pagination.page_size | Items per page (what you requested or the default) |
pagination.total_pages | Total number of pages (ceil(total / page_size)) |
Always check the endpoint's API reference for its exact array key before writing a client. A few endpoints deviate from the shape above:
| Shape | Where |
|---|---|
Counters at the top level instead of nested (records, page, page_size, total, total_pages) | Transaction monitoring, wallet screening, travel-rule transfers, activity logs |
Only a total, with limit / offset instead of page / page_size | GET /webhooks/deliveries, GET /webhooks/destinations |
| No pagination at all - the full list is returned | GET /kyc/levels, GET /kyb/levels, contract template lists |
Endpoint-specific defaults and limits
| Endpoint | Array key | Default | Max |
|---|---|---|---|
GET /transactions | transactions | 10 | 200 |
GET /kyc/lists | users | 20 | 200 |
GET /kyb/businesses | business_customers | 20 | 200 |
GET /opcos | opcos | 20 | 200 |
GET /projects | projects | 20 | 200 |
GET /tickets | tickets | 20 | 200 |
GET /webhooks/deliveries | deliveries | 50 (limit) | 200 |
Requesting a page_size above the maximum is a validation error (422), not a silent cap.
Iterating through all results
To retrieve all items, increment the page parameter until you have fetched all pages:
import requests
def get_all_transactions(base_url, token):
headers = {"Authorization": f"Bearer {token}"}
all_items = []
page = 1
while True:
resp = requests.get(
f"{base_url}/api/v1/transactions",
params={"page": page, "page_size": 100},
headers=headers
)
data = resp.json()
all_items.extend(data["transactions"])
if page >= data["pagination"]["total_pages"]:
break
page += 1
return all_itemsasync function getAllTransactions(baseUrl, token) {
const allItems = [];
let page = 1;
while (true) {
const resp = await fetch(
`${baseUrl}/api/v1/transactions?page=${page}&page_size=100`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const data = await resp.json();
allItems.push(...data.transactions);
if (page >= data.pagination.total_pages) break;
page++;
}
return allItems;
}Webhook delivery history
The webhook deliveries endpoint uses offset-based pagination instead of page-based:
| Parameter | Description | Default |
|---|---|---|
limit | Number of items to return | 50 |
offset | Number of items to skip | 0 |
GET /api/v1/webhooks/deliveries?limit=50&offset=0
GET /api/v1/webhooks/deliveries?limit=50&offset=50
GET /api/v1/webhooks/deliveries?limit=50&offset=100The response includes total and items fields. Increment offset by limit until offset >= total.
Filtering
Some endpoints support additional query parameters to narrow results before pagination:
Transactions:
| Filter | Description |
|---|---|
status | Filter by transaction status (e.g., success, pending) |
project_id | Filter by project |
user_id | Filter by user |
GET /api/v1/transactions?status=success&project_id=uuid&page=1&page_size=50Filters are applied server-side before pagination, so total reflects the filtered count.
Best practices
Use the largest reasonable page_size. If you need all results, use the maximum allowed page_size to minimize the number of requests.
Check pagination.total_pages before iterating. If it is 1, you already have all the data.
Handle empty results. If pagination.total is 0, the resource array will be empty and pagination.total_pages will be 0.
Do not assume stable ordering during writes. If items are being created while you paginate, you may see duplicates or miss items. For critical data, use timestamps or IDs to deduplicate.
Related guides
- Error Reference — What happens when pagination parameters are invalid
- Transaction Lifecycle — Understanding the items returned by transaction list