SaqSaq Docs
最佳实践

分页

列出资源的端点(/user/transactions/user/callbacks/user/infractions)采用经典的 page + limit 分页方式,并带有 hasNextPage 标志。

循环模式

PAGE=1
LIMIT=100

while : ; do
  RESP=$(curl -s "https://api.saq.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 '.data[]'

  HAS_NEXT=$(echo "$RESP" | jq -r '.hasNextPage')
  [ "$HAS_NEXT" != "true" ] && break
  PAGE=$((PAGE+1))
done
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.saq.processamento.com/v1/user/transactions?${params}`, {
      headers: {
        Authorization: `Bearer ${process.env.SAQ_TOKEN}`,
        'Content-Type': 'application/json',
      },
    });
    const { data, hasNextPage } = await res.json();
    for (const tx of data) yield tx;
    if (!hasNextPage) return;
    page++;
  }
}

for await (const tx of iterateTransactions({ dateFrom: '2025-11-01' })) {
  await process(tx);
}
def iterate_transactions(**filters):
    page = 1
    limit = 100
    while True:
        res = requests.get(
            'https://api.saq.processamento.com/v1/user/transactions',
            params={**filters, 'page': page, 'limit': limit},
            headers={
                'Authorization': f'Bearer {os.environ["SAQ_TOKEN"]}',
                'Content-Type': 'application/json',
            },
        )
        body = res.json()
        for tx in body['data']:
            yield tx
        if not body.get('hasNextPage'):
            return
        page += 1
func IterateTransactions(filters url.Values, fn func(tx Transaction) error) error {
    page := 1
    for {
        filters.Set("page", strconv.Itoa(page))
        filters.Set("limit", "100")

        req, _ := http.NewRequest("GET",
            "https://api.saq.processamento.com/v1/user/transactions?"+filters.Encode(), nil)
        req.Header.Set("Authorization", "Bearer "+os.Getenv("SAQ_TOKEN"))
        req.Header.Set("Content-Type", "application/json")

        res, err := http.DefaultClient.Do(req)
        if err != nil { return err }

        var body struct {
            Data        []Transaction `json:"data"`
            HasNextPage bool          `json:"hasNextPage"`
        }
        if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
            res.Body.Close()
            return err
        }
        res.Body.Close()

        for _, tx := range body.Data {
            if err := fn(tx); err != nil { return err }
        }
        if !body.HasNextPage { return nil }
        page++
    }
}

可用过滤器

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

限制和页面大小

项目
limit 最大值每页 100
默认值20

页面过大会降低延迟性能。如果需要长时间段(月、年)或导出全部数据,建议使用异步报告

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

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

异步报告生成带签名下载 URL 的 CSV 文件。无行数限制,后台运行。请查看对账教程

常见陷阱

陷阱症状
在大流量账户中未传 dateFrom 拉取全部数据响应缓慢,可能 timeout
limit=1000(超出允许范围)API 拒绝或截断
data.length === 0 而不是 hasNextPage 进行迭代最后一次迭代空页导致无限循环
固定页码(始终 page=1只读取前 100 条,丢失其余数据
传递带标点符号的 document123.456.789-00错误 400,正则仅接受数字

On this page