Metadata-Version: 2.4
Name: algorand-x402-client
Version: 0.2.0
Summary: Official Algorand Indexer clients with a swappable HTTP layer: unpaid Nodely queries, or x402 USDC payments to api.algorand-indexer.xyz
Author: thecryptomie
License-Expression: MIT
Project-URL: Homepage, https://github.com/thecryptomie/algorand-x402-client
Project-URL: Repository, https://github.com/thecryptomie/algorand-x402-client
Project-URL: Issues, https://github.com/thecryptomie/algorand-x402-client/issues
Project-URL: Documentation, https://api.algorand-indexer.xyz
Keywords: algorand,indexer,x402
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: algokit-utils<5,>=4.2.3
Requires-Dist: x402-avm[avm,httpx,requests]>=2.0.2
Requires-Dist: httpx>=0.28.1
Requires-Dist: requests>=2.32.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
Requires-Dist: ruff>=0.6.0; extra == "dev"
Provides-Extra: publish
Requires-Dist: build>=1.2.0; extra == "publish"
Requires-Dist: twine>=5.0.0; extra == "publish"
Dynamic: license-file

# algorand-x402-client

Query Algorand Indexer with the **official** py-algorand-sdk / AlgoKit client.
This package does not add a new query API. It only changes **where the HTTP
goes, and whether that request can pay**.

| Backend | Default origin | Auth | Data |
| --- | --- | --- | --- |
| **`.free`** | Nodely / AlgoNode (AlgoKit `getAlgoNodeConfig`) | none | full archival Indexer v2 |
| **`.paid`** | MainNet `https://api.algorand-indexer.xyz`, TestNet `https://testnet.algorand-indexer.xyz` | x402 USDC (`exact` / AVM) | private **full** Indexer (genesis → tip) |

You call the same methods as always (`account_info()`, `search_transactions()`,
pagination helpers). Under the hood the official `IndexerClient` is pointed at
one of two transports:

1. **`.free`** — send the request to Nodely. No payment headers, no USDC.
2. **`.paid`** — send the same path to the x402 gateway. If the gateway replies
   **HTTP 402**, the client signs a USDC payment (capped), retries **once** with
   a payment signature, and returns the Indexer JSON.

Both backends speak vanilla Indexer REST and retain history from genesis. They
differ by billing and rate limits, not by how far back data goes. There is no
silent “try Nodely, then pay” fallback — a free-tier 429 would otherwise spend
USDC.

## Install

Python 3.10+:

```bash
pip install algorand-x402-client
# or: uv add algorand-x402-client
```

## Usage

```python
import os

from algorand_x402_client import Payer, configure_logging, create_algorand_indexer, get_logger

configure_logging()  # stderr + algorand-x402-client.log
logger = get_logger(__name__)
indexer_client = create_algorand_indexer(
    "mainnet",
    payer=Payer(mnemonic=os.environ["BUYER_MNEMONIC"]),  # omit for free-only
)

# Nodely — never sends PAYMENT-SIGNATURE, never spends USDC
account = indexer_client.free.account_info("JRG3CUVOFK3YJK3QDD4IOWKMHHRCWVTEMUSYKDN7U73FQO5ZYTCC7CEBRQ")

# x402 gateway — HTTP 402 → sign USDC → retry (search tier is $0.0001)
paid = indexer_client.paid.account_info("JRG3CUVOFK3YJK3QDD4IOWKMHHRCWVTEMUSYKDN7U73FQO5ZYTCC7CEBRQ")

logger.info("gateway network=%s", indexer_client.gateway.health()["network"])
indexer_client.close()
```

`indexer_client.free` / `indexer_client.paid` are py-algorand-sdk `IndexerClient`s.
`indexer_client.algorand_free` is `AlgorandClient.from_clients` with Nodely algod
+ the free Indexer.

Payer must be opted into USDC: MainNet `31566704`, TestNet `10458941`. Default
max payment is 10_000 microUSDC ($0.01). `network="testnet"` points `.paid` /
`.gateway` at `https://testnet.algorand-indexer.xyz`.

Environment: `BUYER_MNEMONIC`, `X402_BASE_URL`, `X402_NETWORK`, `ALGORAND_X402_LOG_FILE`.

## How the HTTP layer is swapped

py-algorand-sdk’s `IndexerClient` has no session hook, so this library subclasses
it (`SessionIndexerClient`) and sends every call through a `requests.Session`.

- **Free session** — plain `requests`, plus backoff on HTTP 429.
- **Paid session** — the same session wrapped with x402-avm
  `wrapRequestsWithPayment`. The wrapper owns the 402 → sign → retry loop.
  Suggested params for the payment group come from Nodely **algod**, not from
  the Indexer.

You still get official response types. Only the transport is ours.

## Docs

- Repository: https://github.com/thecryptomie/algorand-x402-client
- MainNet gateway health: https://api.algorand-indexer.xyz/health
- MainNet OpenAPI: https://api.algorand-indexer.xyz/openapi.json
- TestNet gateway health: https://testnet.algorand-indexer.xyz/health
- TestNet OpenAPI: https://testnet.algorand-indexer.xyz/openapi.json
