SaqSaq Docs
Best practices

Pagination

Endpoints that list resources (/user/transactions, /user/callbacks, /user/infractions) use classic pagination via page + limit with a hasNextPage flag.

Loop pattern

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++
    }
}

Available filters

FilterWhen to use
dateFrom / dateToTime window (ISO 8601).
clientReferenceFinds the transaction matching your order.
virtualAccountFilter by tenant (multi-store).
statusCSV: COMPLETED,PENDING. Accepts multiple values.
typeCSV: DEPOSIT,WITHDRAW,COMMISSION.
endToEndIdUnique Bacen identifier.
document, namePayer filters. document digits only (11 or 14).
amountFilter by exact amount.

Page size and limit

ItemValue
limit max100 per page
Default20

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

ScenarioRecommendation
On-screen listing (dashboard)GET /user/transactions with pagination.
Single lookupGET /user/transactions?clientReference=order-1234.
Daily reconciliation (< 10k transactions)GET /user/transactions paginated.
Monthly/yearly reconciliationPOST /user/report (asynchronous CSV).
BI/Data WarehousePOST /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

PitfallSymptom
Fetching everything without dateFrom on a high-volume accountSlow response, possible timeout
limit=1000 (above the allowed maximum)API rejects or truncates
Iterating until data.length === 0 instead of hasNextPageInfinite loop on the empty page after the last iteration
Fixed page (page=1 always)Only reads the first 100, misses the rest
Passing document with punctuation (123.456.789-00)400 error, regex accepts digits only

On this page