> ## Documentation Index
> Fetch the complete documentation index at: https://docs.range.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Pull stablecoin payment flows

> Page through a transaction's payment records and select Ethereum USDC by contract address.

Extract the two Ethereum USDC payment rows from a recorded transaction that also contains an ETH payment.

## Prerequisites

* An API key with the **Data API** scope, exported as `RANGE_API_KEY`. Use the [shared quickstart](https://docs.range.org/introduction/quickstart.md) for key setup and Bearer authentication.
* Python 3.10 or later and `httpx` for the complete script: `python -m pip install httpx`.
* Ethereum network identifier `eth` and transaction hash `0xe22fefdfb13dc89c83473480881a8f4f16e9b8e3c9ed60aa5727afdc4baaf1e2`, recorded from a live response. This is a transaction hash, not a transfer ID.
* USDC contract `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` on Ethereum, listed in [Circle's contract addresses](https://developers.circle.com/stablecoins/usdc-contract-addresses). The example uses its six decimal places.
* [GET /v1/network/payments](https://docs.range.org/data-api/reference/v1/get-network-payments.md), which accepts `network`, `hash`, `limit`, and `offset`. This example verifies Ethereum (`eth`); see the reference's [network support](https://docs.range.org/data-api/reference/v1/get-network-payments.md#network-support) for a verified Cosmos Hub input. These recorded lookups do not establish availability on every network.

The network payment operation reads payments for a known transaction. It has no contract-address filter, so select matching `base_denom` values from its returned rows. The address payment operation projects symbol fields without a token contract; this recipe uses the network operation to retain the contract identity. A `USDC` symbol by itself does not establish that identity.

## 1. Read the first payment row

Call `GET /v1/network/payments` with `offset=0` and `limit=1`.

```bash cURL theme={null}
curl --get "https://api.range.org/v1/network/payments" \
  --header "Authorization: Bearer $RANGE_API_KEY" \
  --data-urlencode "network=eth" \
  --data-urlencode "hash=0xe22fefdfb13dc89c83473480881a8f4f16e9b8e3c9ed60aa5727afdc4baaf1e2" \
  --data-urlencode "limit=1" \
  --data-urlencode "offset=0"
```

Recorded HTTP 200 on October 21, 2026, abbreviated:

```json theme={null}
{
  "total": 3,
  "payments": [
    {
      "sender": "0x0000000071727de22e5e9d8baf0edac6f37da032",
      "receiver": "0x4337026d731283f9917fa3c9194d74809bfbec26",
      "base_amount": "17489307119250",
      "base_denom": "eth",
      "tx_hash": "0xe22fefdfb13dc89c83473480881a8f4f16e9b8e3c9ed60aa5727afdc4baaf1e2",
      "time": "2026-10-21T02:51:47.000Z",
      "token": "ETH"
    }
  ]
}
```

The first row has `base_denom: "eth"`, so it does not match the USDC contract. The response reports `total: 3` payment rows for this hash, not three transactions or three USDC payments.

## 2. Read the next row and match the contract

Call `GET /v1/network/payments` with the same network, hash, and limit, and `offset=1`.

```bash cURL theme={null}
curl --get "https://api.range.org/v1/network/payments" \
  --header "Authorization: Bearer $RANGE_API_KEY" \
  --data-urlencode "network=eth" \
  --data-urlencode "hash=0xe22fefdfb13dc89c83473480881a8f4f16e9b8e3c9ed60aa5727afdc4baaf1e2" \
  --data-urlencode "limit=1" \
  --data-urlencode "offset=1"
```

Recorded HTTP 200 on October 21, 2026, abbreviated:

```json theme={null}
{
  "total": 3,
  "payments": [
    {
      "sender": "0x6957b40bbefdc949bc0c46081066fcfc1a6679bc",
      "receiver": "0x4337ff05c84b9a80ea0a78dbe7b8e102f66d4c08",
      "base_amount": "45370",
      "base_denom": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "tx_hash": "0xe22fefdfb13dc89c83473480881a8f4f16e9b8e3c9ed60aa5727afdc4baaf1e2",
      "time": "2026-10-21T02:51:47.000Z",
      "token": "USDC"
    }
  ]
}
```

Here, `base_denom` matches the Ethereum USDC contract. Keep `base_amount: "45370"` as an integer string; with six decimal places it is `0.045370` USDC. The script compares the Ethereum contract in lowercase and retains the sender, receiver, and transaction hash.

## 3. Read the remaining payment row

Call `GET /v1/network/payments` with `offset=2`.

```bash cURL theme={null}
curl --get "https://api.range.org/v1/network/payments" \
  --header "Authorization: Bearer $RANGE_API_KEY" \
  --data-urlencode "network=eth" \
  --data-urlencode "hash=0xe22fefdfb13dc89c83473480881a8f4f16e9b8e3c9ed60aa5727afdc4baaf1e2" \
  --data-urlencode "limit=1" \
  --data-urlencode "offset=2"
```

Recorded HTTP 200 on October 21, 2026, abbreviated:

```json theme={null}
{
  "total": 3,
  "payments": [
    {
      "sender": "0x6957b40bbefdc949bc0c46081066fcfc1a6679bc",
      "receiver": "0xc1d13492285eb664951e201bf7c80c7c6318a1b5",
      "base_amount": "21000000",
      "base_denom": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "tx_hash": "0xe22fefdfb13dc89c83473480881a8f4f16e9b8e3c9ed60aa5727afdc4baaf1e2",
      "time": "2026-10-21T02:51:47.000Z",
      "token": "USDC"
    }
  ]
}
```

This row matches the same contract. Its `base_amount: "21000000"` is `21.000000` USDC. Keep it as a separate payment row with its own receiver.

## 4. Confirm the end of the result set

Call `GET /v1/network/payments` with `offset=3`.

```bash cURL theme={null}
curl --get "https://api.range.org/v1/network/payments" \
  --header "Authorization: Bearer $RANGE_API_KEY" \
  --data-urlencode "network=eth" \
  --data-urlencode "hash=0xe22fefdfb13dc89c83473480881a8f4f16e9b8e3c9ed60aa5727afdc4baaf1e2" \
  --data-urlencode "limit=1" \
  --data-urlencode "offset=3"
```

Recorded HTTP 200 on October 21, 2026:

```json theme={null}
{
  "total": 3,
  "payments": []
}
```

The empty payment array ends this sample. Use [Working with responses](https://docs.range.org/data-api/product-info/working-with-responses.md#pagination-by-operation) for the offset convention.

## Complete script

Save this as `stablecoin_flows.py`, then run `python stablecoin_flows.py` with `RANGE_API_KEY` set. It fetches every payment page for this transaction and retains only the approved Ethereum contract. Amount arithmetic uses the exact base-unit strings.

```python theme={null}
import json
import os
import random
import time

import httpx


def get(client, path, params=None):
    for attempt in range(5):
        response = client.get(path, params=params)
        if response.status_code != 429 or attempt == 4:
            response.raise_for_status()
            return response.json()
        # No Retry-After header is sent, so back off exponentially with jitter.
        time.sleep(min(2 ** attempt, 30) + random.uniform(0, 1))


from decimal import Decimal, localcontext

NETWORK = "eth"
TX_HASH = "0xe22fefdfb13dc89c83473480881a8f4f16e9b8e3c9ed60aa5727afdc4baaf1e2"
USDC_CONTRACT = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"

with httpx.Client(
    base_url="https://api.range.org",
    headers={
        "Authorization": f"Bearer {os.environ['RANGE_API_KEY']}",
        "User-Agent": "curl/8.4.0",
        "Accept": "application/json",
    },
    timeout=60,
) as client:
    offset = 0
    all_payments = []
    stablecoin_payments = []
    while True:
        page = get(client, "/v1/network/payments", {
            "network": NETWORK, "hash": TX_HASH, "limit": 1, "offset": offset,
        })
        rows = page["payments"]
        if not rows:
            break
        for row in rows:
            assert row["tx_hash"] == TX_HASH
            all_payments.append(row)
            # Ethereum only: match the contract, never the display symbol.
            if row["base_denom"].lower() == USDC_CONTRACT:
                with localcontext() as context:
                    context.prec = 100
                    units = Decimal(row["base_amount"]).scaleb(-6)
                stablecoin_payments.append({
                    "network": NETWORK, "contract": USDC_CONTRACT,
                    "sender": row["sender"], "receiver": row["receiver"],
                    "tx_hash": row["tx_hash"], "base_amount": row["base_amount"],
                    "amount_string": format(units, "f"),
                })
        offset += len(rows)
    print(json.dumps({
        "payment_rows": len(all_payments),
        "stablecoin_payment_rows": len(stablecoin_payments),
        "other_payment_rows": len(all_payments) - len(stablecoin_payments),
        "distinct_transactions": len({row["tx_hash"] for row in all_payments}),
        "stablecoin_payments": stablecoin_payments,
    }, indent=2))
```

The recorded run prints `payment_rows: 3`, `stablecoin_payment_rows: 2`, `other_payment_rows: 1`, and `distinct_transactions: 1`, with USDC quantities `0.045370` and `21.000000`. These are payment-row and transaction counts for this one query. The script does not query or count transfer records, and the result does not represent all payments on the network.

See [Working with responses](https://docs.range.org/data-api/product-info/working-with-responses.md) for response conventions, [network support](https://docs.range.org/data-api/reference/v1/get-network-payments.md#network-support) for this operation, and [Errors and rate limits](https://docs.range.org/resources/errors-and-rate-limits.md) for failures and retry guidance.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.