# 分页 (/zh/docs/pix-processamento/best-practices/pagination)

<QuickLinks>
  <QuickLink href="/docs/pix-processamento/endpoints/reports/get_user_transactions" title="GET /user/transactions" />

  <QuickLink href="/docs/pix-processamento/endpoints/reports/post_user_report" title="POST /user/report" />

  <QuickLink href="/docs/pix-processamento/endpoints/callbacks/get_user_callbacks" title="GET /user/callbacks" />
</QuickLinks>

列出资源的端点都用 &#x2A;*`page` + `limit`** 分页，但响应结构逐个端点不同。三个端点都不会在响应顶层返回 `hasNextPage`。

| 端点                       | 响应结构                                                                   | 停止条件                             |
| ------------------------ | ---------------------------------------------------------------------- | -------------------------------- |
| `GET /user/transactions` | `{ total, pages, transactions }`                                       | `page >= pages`                  |
| `GET /user/callbacks`    | `{ pagination: { page, limit, hasNextPage }, callbacks }`              | `pagination.hasNextPage` 为 false |
| `GET /user/infractions`  | `{ pagination: { page, limit, totalItems, totalPages }, infractions }` | `page >= pagination.totalPages`  |

## `/user/transactions` 的循环模式 [#usertransactions-的循环模式]

<Tabs items="['curl', 'Node.js']">
  <Tab value="curl">
    ```bash
    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))
    done
    ```
  </Tab>

  <Tab value="Node.js">
    ```ts
    async 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);
    }
    ```
  </Tab>
</Tabs>

在 `/user/callbacks` 上遍历 `callbacks`，当 `pagination.hasNextPage` 为 `false` 时停止。在 `/user/infractions` 上遍历 `infractions`，当 `page` 达到 `pagination.totalPages` 时停止。

## 可用过滤器 [#可用过滤器]

| 过滤器                   | 使用场景                                 |
| --------------------- | ------------------------------------ |
| `dateFrom` / `dateTo` | 时间窗口（ISO 8601）。                      |
| `clientReference`     | 查找与您的订单对应的交易。                        |
| `virtualAccount`      | 按租户过滤（多店铺）。                          |
| `status`              | CSV：`COMPLETED,PENDING`。接受多个值。       |
| `type`                | CSV：`DEPOSIT,WITHDRAW,COMMISSION`。   |
| `endToEndId`          | Bacen 唯一标识符。                         |
| `document`, `name`    | 按付款方过滤。`document` 仅接受数字（11 位或 14 位）。 |
| `amount`              | 按精确金额过滤。                             |

## 限制和页面大小 [#限制和页面大小]

| 端点                       | `limit` 最大值 | 默认值 |
| ------------------------ | ----------- | --- |
| `GET /user/transactions` | 1000        | 10  |
| `GET /user/callbacks`    | 100         | 10  |
| `GET /user/infractions`  | 100         | 10  |

超过该端点的最大值时，请求返回 `400`，`errorCode` 为 `PZV001`。页面过大会降低延迟性能。如果需要长时间段（月、年）或导出全部数据，**建议使用异步报告**。

## 何时使用异步报告替代分页 [#何时使用异步报告替代分页]

| 场景              | 建议                                                                                         |
| --------------- | ------------------------------------------------------------------------------------------ |
| 屏幕列表（dashboard） | 使用 `GET /user/transactions` 分页。                                                            |
| 单次查询            | `GET /user/transactions?clientReference=order-1234`。                                       |
| 日对账（\< 10k 笔交易） | 使用 `GET /user/transactions` 分页。                                                            |
| 月度/年度对账         | [`POST /user/report`](/docs/pix-processamento/endpoints/reports/post_user_report)（CSV 异步）。 |
| BI/数据仓库         | 每日运行 `POST /user/report`，通过 ETL 进行数据摄取。                                                    |

<Callout type="info">
  异步报告生成带签名下载 URL 的 CSV 文件。无行数限制，后台运行。请查看[对账教程](/docs/pix-processamento/tutoriais/reconciliation)。
</Callout>

## 常见陷阱 [#常见陷阱]

| 陷阱                                            | 症状                            |
| --------------------------------------------- | ----------------------------- |
| 在大流量账户中未传 `dateFrom` 拉取全部数据                   | 响应缓慢，可能 timeout               |
| `limit` 超过该端点的最大值（`/user/callbacks` 传 `1000`） | 错误 400，`errorCode` 为 `PZV001` |
| 在响应顶层读取 `hasNextPage`                         | 该字段不存在，循环停在第一页                |
| 三个端点复用同一个停止条件                                 | 静默丢页                          |
| 固定页码（始终 `page=1`）                             | 只读取第一页，丢失其余数据                 |
| 传递带标点符号的 `document`（`123.456.789-00`）         | 错误 400，正则仅接受数字                |