Detailed reference for the `x402-avm` Python package covering package structure, extras, async/sync variants, signer protocols, registration functions, constants, utilities, and algosdk encoding.
Scanned 6/1/2026
Install via CLI
openskills install tools-only/X-Skills# x402-avm Python Package Reference
Detailed reference for the `x402-avm` Python package covering package structure, extras, async/sync variants, signer protocols, registration functions, constants, utilities, and algosdk encoding.
## Package Structure
The package is published on PyPI as `x402-avm` but all imports use the `x402` namespace:
```
x402/
__init__.py # x402Client, x402ClientSync, x402Facilitator, etc.
server.py # x402ResourceServer, x402ResourceServerSync
schemas.py # AssetAmount, Network, PaymentRequirements, etc.
http/
__init__.py # HTTPFacilitatorClient, HTTPFacilitatorClientSync, PaymentOption, etc.
types.py # RouteConfig, RoutesConfig, FacilitatorConfig
clients/
__init__.py # Lazy imports for httpx/requests
httpx.py # x402HttpxClient, wrapHttpxWithPayment, etc.
requests.py # x402_requests, wrapRequestsWithPayment, etc.
middleware/
__init__.py # Lazy imports for fastapi/flask
fastapi.py # PaymentMiddlewareASGI, payment_middleware, etc.
flask.py # PaymentMiddleware, payment_middleware, etc.
mechanisms/
avm/
__init__.py # Re-exports constants
constants.py # Network IDs, USDC config, algod URLs
signer.py # ClientAvmSigner, FacilitatorAvmSigner Protocols
utils.py # Address validation, encoding, network utils
exact/
__init__.py # ExactAvmClientScheme, ExactAvmServerScheme, etc.
register.py # register_exact_avm_client, register_exact_avm_server, etc.
evm/ # EVM mechanism (same structure)
svm/ # SVM mechanism (same structure)
```
## Extras
| Extra | Installs | Use Case |
|-------|----------|----------|
| `[avm]` | `py-algorand-sdk>=2.0.0` | Algorand transaction signing |
| `[evm]` | `web3`, `eth-account` | Ethereum/EVM transaction signing |
| `[svm]` | `solders`, `solana-py` | Solana/SVM transaction signing |
| `[fastapi]` | `fastapi[standard]>=0.115.0`, `starlette>=0.27.0` | FastAPI async middleware |
| `[flask]` | `flask>=3.0.0` | Flask sync middleware |
| `[httpx]` | `httpx>=0.28.1` | Async HTTP client |
| `[requests]` | `requests>=2.31.0` | Sync HTTP client |
| `[mechanisms]` | All mechanism extras | All blockchain mechanisms |
| `[clients]` | `httpx`, `requests` | All HTTP clients |
| `[servers]` | `fastapi`, `flask` | All server frameworks |
| `[extensions]` | Extensions dependencies | Optional extensions |
| `[all]` | Everything | Full installation |
Installation examples:
```bash
pip install "x402-avm[avm]"
pip install "x402-avm[fastapi,avm]"
pip install "x402-avm[flask,avm]"
pip install "x402-avm[httpx,avm]"
pip install "x402-avm[requests,avm]"
pip install "x402-avm[all]"
```
## Async vs Sync Component Table
| Component | Async (FastAPI/httpx) | Sync (Flask/requests) |
|-----------|----------------------|----------------------|
| x402 Client | `x402Client` | `x402ClientSync` |
| Resource Server | `x402ResourceServer` | `x402ResourceServerSync` |
| Facilitator Client | `HTTPFacilitatorClient` | `HTTPFacilitatorClientSync` |
| HTTP Resource Server | `x402HTTPResourceServer` | `x402HTTPResourceServerSync` |
| HTTP Client wrapper | `x402HTTPClient` | `x402HTTPClientSync` |
| Middleware (FastAPI) | `PaymentMiddlewareASGI` | N/A |
| Middleware (Flask) | N/A | `PaymentMiddleware` |
| HTTP Client (httpx) | `x402HttpxClient` | N/A |
| HTTP Client (requests) | N/A | `x402_requests` |
| Payment info storage | `request.state.payment_payload` | `flask.g.payment_payload` |
## ClientAvmSigner Protocol
Defined in `x402.mechanisms.avm.signer`. Structural typing -- no inheritance required.
```python
class ClientAvmSigner(Protocol):
@property
def address(self) -> str:
"""58-character Algorand address."""
...
def sign_transactions(
self,
unsigned_txns: list[bytes],
indexes_to_sign: list[int],
) -> list[bytes | None]:
"""Sign specified transactions in a group.
Args:
unsigned_txns: Raw msgpack-encoded unsigned transactions.
indexes_to_sign: Indexes this signer should sign.
Returns:
Parallel list: signed bytes at signed indexes, None elsewhere.
"""
...
```
### Implementation Notes
- `unsigned_txns` contains raw msgpack bytes, not base64 strings
- Convert at boundary: `base64.b64encode(txn_bytes).decode()` before `msgpack_decode`
- `Transaction.sign(key)` expects base64-encoded private key string
- Convert back: `base64.b64decode(msgpack_encode(signed))` to return raw bytes
## FacilitatorAvmSigner Protocol
Defined in `x402.mechanisms.avm.signer`. Required for facilitator services.
```python
class FacilitatorAvmSigner(Protocol):
def get_addresses(self) -> list[str]: ...
def sign_transaction(self, txn_bytes: bytes, fee_payer: str, network: str) -> bytes: ...
def sign_group(self, group_bytes: list[bytes], fee_payer: str, indexes_to_sign: list[int], network: str) -> list[bytes]: ...
def simulate_group(self, group_bytes: list[bytes], network: str) -> None: ...
def send_group(self, group_bytes: list[bytes], network: str) -> str: ...
def confirm_transaction(self, txid: str, network: str, rounds: int = 4) -> None: ...
```
### Implementation Patterns
| Method | Key Pattern |
|--------|-------------|
| `simulate_group` | Wrap unsigned `Transaction` with `SignedTransaction(txn, None)`, use `allow_empty_signatures=True` |
| `send_group` | Use `send_raw_transaction(base64.b64encode(b"".join(group_bytes)))` |
| `confirm_transaction` | Use `transaction.wait_for_confirmation(client, txid, rounds)` |
## Registration Functions
### `register_exact_avm_client(client, signer, networks=None, algod_url=None)`
Registers AVM payment scheme on an x402 client.
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `client` | `x402Client \| x402ClientSync` | required | The x402 client instance |
| `signer` | `ClientAvmSigner` | required | Signer implementation |
| `networks` | `str \| list[str] \| None` | `None` | Specific networks; default registers `"algorand:*"` wildcard + V1 names |
| `algod_url` | `str \| None` | `None` | Custom algod endpoint |
### `register_exact_avm_server(server)`
Registers AVM scheme on a resource server.
| Parameter | Type | Description |
|-----------|------|-------------|
| `server` | `x402ResourceServer \| x402ResourceServerSync` | The resource server |
### `register_exact_avm_facilitator(facilitator, signer, networks)`
Registers AVM scheme on a facilitator.
| Parameter | Type | Description |
|-----------|------|-------------|
| `facilitator` | `x402Facilitator` | The facilitator instance |
| `signer` | `FacilitatorAvmSigner` | Facilitator signer implementation |
| `networks` | `list[str]` | CAIP-2 network identifiers to support |
## Constants
Defined in `x402.mechanisms.avm.constants`:
### Network Identifiers
| Constant | Value |
|----------|-------|
| `ALGORAND_MAINNET_CAIP2` | `"algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="` |
| `ALGORAND_TESTNET_CAIP2` | `"algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="` |
| `SUPPORTED_NETWORKS` | `[MAINNET_CAIP2, TESTNET_CAIP2]` |
| `MAINNET_GENESIS_HASH` | `"wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="` |
| `TESTNET_GENESIS_HASH` | `"SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="` |
| `V1_NETWORKS` | `["algorand-mainnet", "algorand-testnet"]` |
### USDC Configuration
| Constant | Value |
|----------|-------|
| `USDC_MAINNET_ASA_ID` | `31566704` |
| `USDC_TESTNET_ASA_ID` | `10458941` |
| `DEFAULT_DECIMALS` | `6` |
### Algod Endpoints
| Constant | Default Value |
|----------|---------------|
| `MAINNET_ALGOD_URL` | env `ALGOD_MAINNET_URL` or `"https://mainnet-api.algonode.cloud"` |
| `TESTNET_ALGOD_URL` | env `ALGOD_TESTNET_URL` or `"https://testnet-api.algonode.cloud"` |
| `FALLBACK_ALGOD_MAINNET` | `"https://mainnet-api.algonode.cloud"` |
| `FALLBACK_ALGOD_TESTNET` | `"https://testnet-api.algonode.cloud"` |
### Transaction Limits
| Constant | Value |
|----------|-------|
| `MAX_GROUP_SIZE` | `16` |
| `MIN_TXN_FEE` | `1000` (microAlgos) |
## Utility Functions
Defined in `x402.mechanisms.avm.utils`:
| Function | Signature | Returns |
|----------|-----------|---------|
| `is_valid_address(addr)` | `str -> bool` | Whether address is valid 58-char Algorand address |
| `to_atomic_amount(amount)` | `float -> int` | Decimal to atomic units (e.g., 1.50 -> 1500000) |
| `from_atomic_amount(amount)` | `int -> float` | Atomic units to decimal (e.g., 1500000 -> 1.5) |
| `decode_transaction_bytes(raw)` | `bytes -> DecodedTransactionInfo` | Decoded transaction details |
| `decode_base64_transaction(b64)` | `str -> DecodedTransactionInfo` | Decode from base64 string |
| `decode_payment_group(group, index)` | `list[str], int -> PaymentGroupInfo` | Full group analysis |
| `encode_transaction_group(txns)` | `list[bytes] -> list[str]` | Encode raw bytes to base64 strings |
| `normalize_network(network)` | `str -> str` | Normalize V1 name to CAIP-2 |
| `is_valid_network(network)` | `str -> bool` | Check if network is recognized |
| `get_network_config(network)` | `str -> dict` | Full config for network |
| `get_usdc_asa_id(network)` | `str -> int` | USDC ASA ID for network |
| `get_genesis_hash(network)` | `str -> str` | Genesis hash for network |
| `network_from_genesis_hash(hash)` | `str -> str` | CAIP-2 from genesis hash |
| `validate_no_security_risks(info)` | `DecodedTransactionInfo -> str \| None` | Error code or None |
| `validate_fee_payer_transaction(info, addr)` | `DecodedTransactionInfo, str -> str \| None` | Error code or None |
| `is_blocked_transaction_type(type)` | `str -> bool` | Whether type is blocked (e.g., keyreg) |
## algosdk Encoding Notes (v2.11.1)
The Python `algosdk` has different encoding conventions than TypeScript algosdk:
| Operation | Python algosdk | TypeScript algosdk |
|-----------|---------------|-------------------|
| `msgpack_decode(s)` | Expects **base64 string** | N/A (uses `decodeUnsignedTransaction(Uint8Array)`) |
| `msgpack_encode(obj)` | Returns **base64 string** | N/A (uses `txn.toByte()` returning `Uint8Array`) |
| `Transaction.sign(key)` | Expects **base64 string** key | `signTransaction(txn, Uint8Array)` |
| SDK protocol | Passes **raw msgpack bytes** | Passes **raw `Uint8Array`** |
Boundary conversions:
```python
# Raw bytes -> algosdk object
txn_obj = encoding.msgpack_decode(base64.b64encode(raw_bytes).decode("utf-8"))
# algosdk object -> raw bytes
raw_bytes = base64.b64decode(encoding.msgpack_encode(txn_obj))
```
## Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `AVM_PRIVATE_KEY` | Base64-encoded 64-byte key (32-byte seed + 32-byte pubkey) | Required |
| `ALGOD_MAINNET_URL` | Custom algod mainnet endpoint | `https://mainnet-api.algonode.cloud` |
| `ALGOD_TESTNET_URL` | Custom algod testnet endpoint | `https://testnet-api.algonode.cloud` |
| `INDEXER_MAINNET_URL` | Custom indexer mainnet endpoint | `https://mainnet-idx.algonode.cloud` |
| `INDEXER_TESTNET_URL` | Custom indexer testnet endpoint | `https://testnet-idx.algonode.cloud` |
| `ALGOD_SERVER` | Algod URL for facilitator examples | N/A |
| `ALGOD_TOKEN` | Algod token for facilitator examples | N/A |
### Private Key Format
The `AVM_PRIVATE_KEY` is a Base64-encoded 64-byte key:
- First 32 bytes: Ed25519 seed (private key)
- Last 32 bytes: Ed25519 public key
- Address derivation: `encoding.encode_address(secret_key[32:])`
## Payment Flow
```
Client -> Resource Server -> Facilitator -> Algorand Network
| | | |
| 1. GET | | |
|--------->| | |
| 2. 402 | | |
|<---------| | |
| 3. Build | | |
| payload| | |
| 4. GET + | | |
| X-PAYMENT| | |
|--------->| 5. verify() | |
| |----------------->| 6. simulate |
| | |--------------->|
| | |<---------------|
| |<-----------------| |
| | 7. settle() | |
| |----------------->| 8. sign + send |
| | |--------------->|
| | |<---------------|
| |<-----------------| 9. txId |
| 10. 200 | | |
|<---------| | |
```
## Testing Notes
- Use Algorand TestNet for development with free test ALGO from the [Algorand Faucet](https://bank.testnet.algorand.network/)
- USDC on TestNet uses ASA ID `10458941` -- ensure receiver has opted in
- Simulation (`simulate_group`) validates transactions without submitting
- Algorand has instant finality -- once confirmed, transactions are permanent
- AlgoNode public endpoints require no authentication token
## External Resources
- [x402-avm on PyPI](https://pypi.org/project/x402-avm/)
- [x402-avm GitHub Repository](https://github.com/GoPlausible/x402-avm/tree/branch-v2-algorand-publish/)
- [x402-avm Examples](https://github.com/GoPlausible/x402-avm/tree/branch-v2-algorand-publish/examples/)
- [x402 Algorand Documentation](https://github.com/GoPlausible/.github/blob/main/profile/algorand-x402-documentation/)
- [Algorand Developer Portal](https://dev.algorand.co/)
- [py-algorand-sdk Documentation](https://py-algorand-sdk.readthedocs.io/)
- [Coinbase x402 Specification](https://github.com/coinbase/x402)
No comments yet. Be the first to comment!