Pagination

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:

ParameterDescriptionDefault
pagePage number (starts at 1)1
page_sizeNumber of items per pageVaries by endpoint

Results are always sorted by creation date, newest first.


Paginated response format

Every paginated response includes metadata alongside the results:

{
  "total": 142,
  "page": 1,
  "page_size": 10,
  "total_pages": 15,
  "items": [ ... ]
}
FieldDescription
totalTotal number of items across all pages
pageCurrent page number
page_sizeItems per page (what you requested or the default)
total_pagesTotal number of pages (ceil(total / page_size))
itemsArray of items for the current page

Endpoint-specific defaults and limits

EndpointDefault page_sizeMax page_size
GET /transactions10100
GET /kyc/lists20200
GET /webhooks/deliveries50200
GET /billing/invoices20100
GET /tickets20100

If you request a page_size larger than the maximum, the API caps it at the maximum value.

Note: Some endpoints (OpCo list, project list) return all results without pagination because the expected dataset size is small.


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["items"])
        
        if page >= data["total_pages"]:
            break
        page += 1
    
    return all_items
async 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.items);
    
    if (page >= data.total_pages) break;
    page++;
  }
  
  return allItems;
}

Webhook delivery history

The webhook deliveries endpoint uses offset-based pagination instead of page-based:

ParameterDescriptionDefault
limitNumber of items to return50
offsetNumber of items to skip0
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=100

The 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:

FilterDescription
statusFilter by transaction status (e.g., success, pending)
project_idFilter by project
user_idFilter by user
GET /api/v1/transactions?status=success&project_id=uuid&page=1&page_size=50

Filters 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 total_pages before iterating. If total_pages is 1, you already have all the data.

Handle empty results. If total is 0, items will be an empty array and 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