Pagination
Explains how to walk long lists with page and limit, and when to swap the listing for the CSV report.
Endpoints that list resources paginate with page + limit, but the response envelope differs per route. None of the three returns hasNextPage at the top level of the response.
| Endpoint | Response envelope | Stop condition |
|---|---|---|
GET /user/transactions | { total, pages, transactions } | page >= pages |
GET /user/callbacks | { pagination: { page, limit, hasNextPage }, callbacks } | pagination.hasNextPage is false |
GET /user/infractions | { pagination: { page, limit, totalItems, totalPages }, infractions } | page >= pagination.totalPages |
Loop pattern for /user/transactions
PAGE=1
LIMIT=100
while : ; do
RESP=$(curl -s "https://api.payzu.processamento.com/v1/user/transactions?dateFrom=2025-11-01&page=$PAGE&limit=$LIMIT" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json")
echo "$RESP" | jq -c '.transactions[]'
PAGES=$(echo "$RESP" | jq -r '.pages')
[ "$PAGE" -ge "$PAGES" ] && break
PAGE=$((PAGE+1))
doneasync function* iterateTransactions(filters: Record<string, string>) {
let page = 1;
const limit = 100;
while (true) {
const params = new URLSearchParams({ ...filters, page: String(page), limit: String(limit) });
const res = await fetch(`https://api.payzu.processamento.com/v1/user/transactions?${params}`, {
headers: {
Authorization: `Bearer ${process.env.PAYZU_TOKEN}`,
'Content-Type': 'application/json',
},
});
const { pages, transactions } = await res.json();
for (const tx of transactions) yield tx;
if (page >= pages) return;
page++;
}
}
for await (const tx of iterateTransactions({ dateFrom: '2025-11-01' })) {
await process(tx);
}On /user/callbacks, iterate over callbacks and stop when pagination.hasNextPage is false. On /user/infractions, iterate over infractions and stop when page reaches pagination.totalPages.
Available filters
| Filter | When to use |
|---|---|
dateFrom / dateTo | Time window (ISO 8601). |
clientReference | Finds the transaction matching your order. |
virtualAccount | Filter by tenant (multi-store). |
status | CSV: COMPLETED,PENDING. Accepts multiple values. |
type | CSV: DEPOSIT,WITHDRAW,COMMISSION. |
endToEndId | Unique Bacen identifier. |
document, name | Payer filters. document digits only (11 or 14). |
amount | Filter by exact amount. |
Page size and limit
| Endpoint | limit max | Default |
|---|---|---|
GET /user/transactions | 1000 | 10 |
GET /user/callbacks | 100 | 10 |
GET /user/infractions | 100 | 10 |
Above the route maximum, the request is rejected with 400 and errorCode PZV001. Oversized pages degrade latency. If you need a long period (month, year) or to export everything, prefer the asynchronous report.
When to use the asynchronous report instead of paginating
| Scenario | Recommendation |
|---|---|
| On-screen listing (dashboard) | GET /user/transactions with pagination. |
| Single lookup | GET /user/transactions?clientReference=order-1234. |
| Daily reconciliation (< 10k transactions) | GET /user/transactions paginated. |
| Monthly/yearly reconciliation | POST /user/report (asynchronous CSV). |
| BI/Data Warehouse | POST /user/report run daily, ingested via ETL. |
The asynchronous report generates a CSV file with a signed download URL. It has no row limit and runs in the background. See the Reconciliation tutorial.
Common pitfalls
| Pitfall | Symptom |
|---|---|
Fetching everything without dateFrom on a high-volume account | Slow response, possible timeout |
limit above the route maximum (1000 on /user/callbacks) | 400 error with errorCode PZV001 |
Reading hasNextPage at the top level of the response | Value is absent, the loop stops on page one |
| Reusing one stop condition across the three routes | Pages dropped silently |
Fixed page (page=1 always) | Only reads the first page, misses the rest |
Passing document with punctuation (123.456.789-00) | 400 error, regex accepts digits only |