Python SDK for x402 payments - gasless crypto payments across 21 blockchains (including Scroll, SKALE). Features: ERC-8004 Trustless Agents, Escrow/Refunds, multi-stablecoin (USDC, EURC, AUSD, PYUSD, USDT)
Project description
uvd-x402-sdk
Python SDK for integrating x402 cryptocurrency payments via the Ultravioleta DAO facilitator.
Accept gasless stablecoin payments across 21 blockchain networks with a single integration. The SDK handles signature verification, on-chain settlement, and all the complexity of multi-chain payments.
New in v0.20.0: WalletAdapter protocol (EnvKeyAdapter, OWSWalletAdapter), [wallet] install extra, eth-account bumped to >=0.11.0.
Features
- 21 Networks: EVM chains (13 including Scroll, SKALE), SVM chains (Solana, Fogo), NEAR, Stellar, Algorand, and Sui
- 5 Stablecoins: USDC, EURC, AUSD, PYUSD, USDT (EVM chains)
- x402 v1 & v2: Full support for both protocol versions with auto-detection
- Framework Integrations: Flask, FastAPI, Django, AWS Lambda
- Gasless Payments: Users sign EIP-712/EIP-3009 authorizations, facilitator pays all network fees
- Simple API: Decorators and middleware for quick integration
- Type Safety: Full Pydantic models and type hints
- Extensible: Register custom networks and tokens easily
- ERC-8004 Trustless Agents: On-chain reputation and identity for AI agents (EVM + Solana)
- Escrow & Refunds: Hold payments in escrow with dispute resolution
/acceptsNegotiation: Discover facilitator capabilities before constructing payments- Bazaar Discovery: Register and discover paid resources across the x402 network
- Facilitator Info: Query version, supported networks, blacklist, and health
- WalletAdapter: Abstract protocol for wallet signing (EnvKeyAdapter, OWSWalletAdapter)
Quick Start (5 Lines)
from decimal import Decimal
from uvd_x402_sdk import X402Client
client = X402Client(recipient_address="0xYourWallet...")
result = client.process_payment(request.headers["X-PAYMENT"], Decimal("10.00"))
print(f"Paid by {result.payer_address}, tx: {result.transaction_hash}")
Complete Usage Example
Here's a complete example showing the full x402 payment flow - returning a 402 response when no payment is provided, and processing the payment when it arrives:
from decimal import Decimal
from uvd_x402_sdk import (
X402Client,
X402Config,
create_402_response,
PaymentRequiredError,
)
# 1. Configure the client with your recipient addresses
config = X402Config(
recipient_evm="0xYourEVMWallet...", # For Base, Ethereum, etc.
recipient_solana="YourSolanaAddress...", # For Solana, Fogo
recipient_near="your-account.near", # For NEAR
recipient_stellar="G...YourStellarAddress", # For Stellar
recipient_algorand="YOUR_ALGO_ADDRESS...", # For Algorand
recipient_sui="0xYourSuiAddress...", # For Sui
)
client = X402Client(config=config)
def handle_api_request(request):
"""
Handle an API request that requires payment.
"""
price = Decimal("1.00") # $1.00 USD
# Check if payment header exists
x_payment = request.headers.get("X-PAYMENT")
if not x_payment:
# No payment provided - return 402 Payment Required
return {
"status": 402,
"headers": {
"Content-Type": "application/json",
},
"body": create_402_response(
amount_usd=price,
config=config,
resource="/api/premium",
description="Premium API access",
)
}
# Payment provided - verify and settle
try:
result = client.process_payment(x_payment, price)
# Payment successful!
return {
"status": 200,
"body": {
"success": True,
"message": "Payment verified and settled!",
"payer": result.payer_address,
"network": result.network,
"transaction_hash": result.transaction_hash,
"amount_paid": str(result.amount),
}
}
except PaymentRequiredError as e:
# Payment verification failed
return {
"status": 402,
"body": {"error": str(e)}
}
# The 402 response includes payment options for all configured networks:
# {
# "x402Version": 1,
# "accepts": [
# {"network": "base", "asset": "0x833589fCD...", "amount": "1000000", "payTo": "0xYour..."},
# {"network": "solana", "asset": "EPjFWdd5...", "amount": "1000000", "payTo": "Your..."},
# {"network": "near", "asset": "17208628...", "amount": "1000000", "payTo": "your.near"},
# {"network": "stellar", "asset": "CCW67Q...", "amount": "10000000", "payTo": "G..."},
# {"network": "algorand", "asset": "31566704", "amount": "1000000", "payTo": "YOUR..."},
# {"network": "sui", "asset": "0xdba346...", "amount": "1000000", "payTo": "0xYour..."},
# ],
# "payTo": "0xYour...",
# "maxAmountRequired": "1000000",
# "resource": "/api/premium",
# "description": "Premium API access"
# }
Using the Decorator (Simpler)
For even simpler integration, use the @require_payment decorator:
from decimal import Decimal
from uvd_x402_sdk import require_payment, configure_x402
# Configure once at startup
configure_x402(
recipient_address="0xYourEVMWallet...",
recipient_solana="YourSolanaAddress...",
)
@require_payment(amount_usd=Decimal("1.00"))
def premium_endpoint(payment_result):
"""
This function only runs if payment is verified.
Returns 402 automatically if no valid payment.
"""
return {
"data": "Premium content here!",
"paid_by": payment_result.payer_address,
"tx": payment_result.transaction_hash,
}
Supported Networks
| Network | Type | Chain ID | CAIP-2 | Status |
|---|---|---|---|---|
| Base | EVM | 8453 | eip155:8453 |
Active |
| Ethereum | EVM | 1 | eip155:1 |
Active |
| Polygon | EVM | 137 | eip155:137 |
Active |
| Arbitrum | EVM | 42161 | eip155:42161 |
Active |
| Optimism | EVM | 10 | eip155:10 |
Active |
| Avalanche | EVM | 43114 | eip155:43114 |
Active |
| Celo | EVM | 42220 | eip155:42220 |
Active |
| HyperEVM | EVM | 999 | eip155:999 |
Active |
| Unichain | EVM | 130 | eip155:130 |
Active |
| Monad | EVM | 143 | eip155:143 |
Active |
| Scroll | EVM | 534352 | eip155:534352 |
Active |
| SKALE | EVM | 1187947933 | eip155:1187947933 |
Active |
| SKALE Testnet | EVM | 324705682 | eip155:324705682 |
Active |
| Solana | SVM | - | solana:5eykt... |
Active |
| Fogo | SVM | - | solana:fogo |
Active |
| NEAR | NEAR | - | near:mainnet |
Active |
| Stellar | Stellar | - | stellar:pubnet |
Active |
| Algorand | Algorand | - | algorand:mainnet |
Active |
| Algorand Testnet | Algorand | - | algorand:testnet |
Active |
| Sui | Sui | - | sui:mainnet |
Active |
| Sui Testnet | Sui | - | sui:testnet |
Active |
Supported Tokens
| Token | Networks | Decimals |
|---|---|---|
| USDC | All networks | 6 |
| EURC | Ethereum, Base, Avalanche | 6 |
| AUSD | Ethereum, Arbitrum, Avalanche, Polygon, Monad, Sui | 6 |
| PYUSD | Ethereum | 6 |
| USDT | Ethereum, Arbitrum, Optimism, Avalanche, Polygon | 6 |
Installation
# Core SDK (minimal dependencies)
pip install uvd-x402-sdk
# With wallet signing support (EIP-3009)
pip install uvd-x402-sdk[wallet] # WalletAdapter + EnvKeyAdapter
pip install uvd-x402-sdk[signer] # Alias for wallet (backward compat)
# With framework support
pip install uvd-x402-sdk[flask] # Flask integration
pip install uvd-x402-sdk[fastapi] # FastAPI/Starlette integration
pip install uvd-x402-sdk[django] # Django integration
pip install uvd-x402-sdk[aws] # AWS Lambda helpers
pip install uvd-x402-sdk[algorand] # Algorand atomic group helpers
# All integrations
pip install uvd-x402-sdk[all]
Framework Examples
Flask
from decimal import Decimal
from flask import Flask, g, jsonify
from uvd_x402_sdk.integrations import FlaskX402
app = Flask(__name__)
x402 = FlaskX402(
app,
recipient_address="0xYourEVMWallet...",
recipient_solana="YourSolanaAddress...",
recipient_near="your-account.near",
recipient_stellar="G...YourStellarAddress",
)
@app.route("/api/premium")
@x402.require_payment(amount_usd=Decimal("5.00"))
def premium():
return jsonify({
"message": "Premium content!",
"payer": g.payment_result.payer_address,
"tx": g.payment_result.transaction_hash,
"network": g.payment_result.network,
})
@app.route("/api/basic")
@x402.require_payment(amount_usd=Decimal("0.10"))
def basic():
return jsonify({"data": "Basic tier data"})
if __name__ == "__main__":
app.run(debug=True)
FastAPI
from decimal import Decimal
from fastapi import FastAPI, Depends
from uvd_x402_sdk.config import X402Config
from uvd_x402_sdk.models import PaymentResult
from uvd_x402_sdk.integrations import FastAPIX402
app = FastAPI()
x402 = FastAPIX402(
app,
recipient_address="0xYourEVMWallet...",
recipient_solana="YourSolanaAddress...",
recipient_near="your-account.near",
recipient_stellar="G...YourStellarAddress",
)
@app.get("/api/premium")
async def premium(
payment: PaymentResult = Depends(x402.require_payment(amount_usd="5.00"))
):
return {
"message": "Premium content!",
"payer": payment.payer_address,
"network": payment.network,
}
@app.post("/api/generate")
async def generate(
body: dict,
payment: PaymentResult = Depends(x402.require_payment(amount_usd="1.00"))
):
# Dynamic processing based on request
return {"result": "generated", "payer": payment.payer_address}
Django
# settings.py
X402_FACILITATOR_URL = "https://facilitator.ultravioletadao.xyz"
X402_RECIPIENT_EVM = "0xYourEVMWallet..."
X402_RECIPIENT_SOLANA = "YourSolanaAddress..."
X402_RECIPIENT_NEAR = "your-account.near"
X402_RECIPIENT_STELLAR = "G...YourStellarAddress"
X402_PROTECTED_PATHS = {
"/api/premium/": "5.00",
"/api/basic/": "1.00",
}
MIDDLEWARE = [
# ...other middleware...
"uvd_x402_sdk.integrations.django_integration.DjangoX402Middleware",
]
# views.py
from django.http import JsonResponse
from uvd_x402_sdk.integrations import django_x402_required
@django_x402_required(amount_usd="5.00")
def premium_view(request):
payment = request.payment_result
return JsonResponse({
"message": "Premium content!",
"payer": payment.payer_address,
})
AWS Lambda
import json
from decimal import Decimal
from uvd_x402_sdk.config import X402Config
from uvd_x402_sdk.integrations import LambdaX402
config = X402Config(
recipient_evm="0xYourEVMWallet...",
recipient_solana="YourSolanaAddress...",
recipient_near="your-account.near",
recipient_stellar="G...YourStellarAddress",
)
x402 = LambdaX402(config=config)
def handler(event, context):
# Calculate price based on request
body = json.loads(event.get("body", "{}"))
quantity = body.get("quantity", 1)
price = Decimal(str(quantity * 0.01))
# Process payment or return 402
result = x402.process_or_require(event, price)
# If 402 response, return it
if isinstance(result, dict) and "statusCode" in result:
return result
# Payment verified!
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"success": True,
"payer": result.payer_address,
"tx": result.transaction_hash,
"network": result.network,
"quantity": quantity,
})
}
Network-Specific Examples
EVM Chains (Base, Ethereum, Polygon, etc.)
EVM chains use ERC-3009 TransferWithAuthorization with EIP-712 signatures.
from uvd_x402_sdk import X402Client, X402Config
# Accept payments on Base and Ethereum only
config = X402Config(
recipient_evm="0xYourEVMWallet...",
supported_networks=["base", "ethereum"],
)
client = X402Client(config=config)
result = client.process_payment(x_payment_header, Decimal("10.00"))
# The payload contains EIP-712 signature + authorization
payload = client.extract_payload(x_payment_header)
evm_data = payload.get_evm_payload()
print(f"From: {evm_data.authorization.from_address}")
print(f"To: {evm_data.authorization.to}")
print(f"Value: {evm_data.authorization.value}")
Solana & Fogo (SVM Chains)
SVM chains use partially-signed VersionedTransactions with SPL token transfers.
from uvd_x402_sdk import X402Client, X402Config
# Accept payments on Solana and Fogo
config = X402Config(
recipient_solana="YourSolanaAddress...",
supported_networks=["solana", "fogo"],
)
client = X402Client(config=config)
result = client.process_payment(x_payment_header, Decimal("5.00"))
# The payload contains a base64-encoded VersionedTransaction
payload = client.extract_payload(x_payment_header)
svm_data = payload.get_svm_payload()
print(f"Transaction: {svm_data.transaction[:50]}...")
# Fogo has ultra-fast finality (~400ms)
if result.network == "fogo":
print("Payment confirmed in ~400ms!")
Stellar
Stellar uses Soroban Authorization Entries with fee-bump transactions.
from uvd_x402_sdk import X402Client, X402Config
config = X402Config(
recipient_stellar="G...YourStellarAddress",
supported_networks=["stellar"],
)
client = X402Client(config=config)
result = client.process_payment(x_payment_header, Decimal("1.00"))
# Stellar uses 7 decimals (stroops)
payload = client.extract_payload(x_payment_header)
stellar_data = payload.get_stellar_payload()
print(f"From: {stellar_data.from_address}")
print(f"Amount (stroops): {stellar_data.amount}")
print(f"Token Contract: {stellar_data.tokenContract}")
NEAR Protocol
NEAR uses NEP-366 meta-transactions with Borsh serialization.
from uvd_x402_sdk import X402Client, X402Config
config = X402Config(
recipient_near="your-recipient.near",
supported_networks=["near"],
)
client = X402Client(config=config)
result = client.process_payment(x_payment_header, Decimal("2.00"))
# NEAR payload contains a SignedDelegateAction
payload = client.extract_payload(x_payment_header)
near_data = payload.get_near_payload()
print(f"SignedDelegateAction: {near_data.signedDelegateAction[:50]}...")
# Validate NEAR payload structure
from uvd_x402_sdk.networks.near import validate_near_payload
validate_near_payload(payload.payload) # Raises ValueError if invalid
Algorand
Algorand uses atomic groups with ASA (Algorand Standard Assets) transfers.
from uvd_x402_sdk import X402Client, X402Config
config = X402Config(
recipient_algorand="NCDSNUQ2QLXDMJXRALAW4CRUSSKG4IS37MVOFDQQPC45SE4EBZO42U6ZX4",
supported_networks=["algorand"],
)
client = X402Client(config=config)
result = client.process_payment(x_payment_header, Decimal("1.00"))
# Algorand uses atomic groups: [fee_tx, payment_tx]
from uvd_x402_sdk.networks.algorand import (
validate_algorand_payload,
get_algorand_fee_payer,
build_atomic_group,
)
# Get the facilitator fee payer address
fee_payer = get_algorand_fee_payer("algorand")
print(f"Fee payer: {fee_payer}") # KIMS5H6Q...
# Validate payload structure
payload = client.extract_payload(x_payment_header)
validate_algorand_payload(payload.payload) # Raises ValueError if invalid
Building Algorand Payments (requires pip install uvd-x402-sdk[algorand])
from uvd_x402_sdk.networks.algorand import (
build_atomic_group,
build_x402_payment_request,
get_algorand_fee_payer,
)
from algosdk.v2client import algod
# Connect to Algorand node
client = algod.AlgodClient("", "https://mainnet-api.algonode.cloud")
# Build atomic group
payload = build_atomic_group(
sender_address="YOUR_ADDRESS...",
recipient_address="MERCHANT_ADDRESS...",
amount=1000000, # 1 USDC (6 decimals)
asset_id=31566704, # USDC ASA ID on mainnet
facilitator_address=get_algorand_fee_payer("algorand"),
sign_transaction=lambda txn: txn.sign(private_key),
algod_client=client,
)
# Build x402 payment request
request = build_x402_payment_request(payload, network="algorand")
Sui
Sui uses sponsored transactions with Move-based programmable transaction blocks.
from uvd_x402_sdk import X402Client, X402Config
config = X402Config(
recipient_sui="0xYourSuiAddress...",
supported_networks=["sui"],
)
client = X402Client(config=config)
result = client.process_payment(x_payment_header, Decimal("1.00"))
# Sui payload contains a user-signed PTB that the facilitator sponsors
payload = client.extract_payload(x_payment_header)
sui_data = payload.get_sui_payload()
print(f"From: {sui_data.from_address}")
print(f"To: {sui_data.to}")
print(f"Amount: {sui_data.amount}")
print(f"Coin Object ID: {sui_data.coinObjectId}")
print(f"Transaction Bytes: {sui_data.transactionBytes[:50]}...")
# Sui uses sponsored transactions (user pays ZERO SUI for gas)
# Facilitator adds sponsor signature and pays gas fees
Sui-Specific Utilities
from uvd_x402_sdk.networks.sui import (
validate_sui_payload,
is_valid_sui_address,
is_valid_sui_coin_type,
get_sui_fee_payer,
get_sui_usdc_coin_type,
get_sui_ausd_coin_type,
SUI_FEE_PAYER_MAINNET,
SUI_USDC_COIN_TYPE_MAINNET,
SUI_AUSD_COIN_TYPE_MAINNET,
)
# Validate Sui addresses (0x + 64 hex chars)
assert is_valid_sui_address("0xe7bbf2b13f7d72714760aa16e024fa1b35a978793f9893d0568a4fbf356a764a")
# Validate coin types (package::module::type format)
assert is_valid_sui_coin_type(SUI_USDC_COIN_TYPE_MAINNET)
# Get fee payer (sponsor) address
fee_payer = get_sui_fee_payer("sui") # Returns mainnet sponsor
print(f"Sui sponsor: {fee_payer}")
# Get USDC coin type
usdc_type = get_sui_usdc_coin_type("sui")
# '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'
# Get AUSD coin type (mainnet only)
ausd_type = get_sui_ausd_coin_type("sui")
# '0x2053d08c1e2bd02791056171aab0fd12bd7cd7efad2ab8f6b9c8902f14df2ff2::ausd::AUSD'
# Validate Sui payment payload
payload = client.extract_payload(x_payment_header)
validate_sui_payload(payload.payload) # Raises ValueError if invalid
x402 v1 vs v2
The SDK supports both x402 protocol versions with automatic detection.
Version Differences
| Aspect | v1 | v2 |
|---|---|---|
| Network ID | String ("base") |
CAIP-2 ("eip155:8453") |
| Payment delivery | JSON body | PAYMENT-REQUIRED header |
| Multiple options | Limited | accepts array |
| Discovery | Implicit | Optional extension |
Auto-Detection
from uvd_x402_sdk import PaymentPayload
# The SDK auto-detects based on network format
payload = PaymentPayload(
x402Version=1,
scheme="exact",
network="base", # v1 format
payload={"signature": "...", "authorization": {...}}
)
print(payload.is_v2()) # False
payload_v2 = PaymentPayload(
x402Version=2,
scheme="exact",
network="eip155:8453", # v2 CAIP-2 format
payload={"signature": "...", "authorization": {...}}
)
print(payload_v2.is_v2()) # True
# Both work the same way
print(payload.get_normalized_network()) # "base"
print(payload_v2.get_normalized_network()) # "base"
Creating v2 Responses
from uvd_x402_sdk import X402Config, create_402_response_v2, Payment402BuilderV2
config = X402Config(
recipient_evm="0xYourEVM...",
recipient_solana="YourSolana...",
recipient_near="your.near",
recipient_stellar="G...Stellar",
)
# Simple v2 response
response = create_402_response_v2(
amount_usd=Decimal("5.00"),
config=config,
resource="/api/premium",
description="Premium API access",
)
# Returns:
# {
# "x402Version": 2,
# "scheme": "exact",
# "resource": "/api/premium",
# "accepts": [
# {"network": "eip155:8453", "asset": "0x833...", "amount": "5000000", "payTo": "0xYour..."},
# {"network": "solana:5eykt...", "asset": "EPjF...", "amount": "5000000", "payTo": "Your..."},
# {"network": "near:mainnet", "asset": "1720...", "amount": "5000000", "payTo": "your.near"},
# ...
# ]
# }
# Builder pattern for more control
response = (
Payment402BuilderV2(config)
.amount(Decimal("10.00"))
.resource("/api/generate")
.description("AI generation credits")
.networks(["base", "solana", "near"]) # Limit to specific networks
.build()
)
Payload Validation
Each network type has specific payload validation:
EVM Validation
from uvd_x402_sdk.models import EVMPayloadContent, EVMAuthorization
# Parse and validate EVM payload
payload = client.extract_payload(x_payment_header)
evm_data = payload.get_evm_payload()
# Validate authorization fields
auth = evm_data.authorization
assert auth.from_address.startswith("0x")
assert auth.to.startswith("0x")
assert int(auth.value) > 0
assert int(auth.validBefore) > int(auth.validAfter)
SVM Validation
from uvd_x402_sdk.networks.solana import validate_svm_payload, is_valid_solana_address
# Validate SVM payload
payload = client.extract_payload(x_payment_header)
validate_svm_payload(payload.payload) # Raises ValueError if invalid
# Validate Solana addresses
assert is_valid_solana_address("YourSolanaAddress...")
NEAR Validation
from uvd_x402_sdk.networks.near import (
validate_near_payload,
is_valid_near_account_id,
BorshSerializer,
)
# Validate NEAR payload
payload = client.extract_payload(x_payment_header)
validate_near_payload(payload.payload) # Raises ValueError if invalid
# Validate NEAR account IDs
assert is_valid_near_account_id("your-account.near")
assert is_valid_near_account_id("0xultravioleta.near")
Stellar Validation
from uvd_x402_sdk.networks.stellar import (
is_valid_stellar_address,
is_valid_contract_address,
stroops_to_usd,
)
# Validate Stellar addresses
assert is_valid_stellar_address("G...YourStellarAddress") # G...
assert is_valid_contract_address("C...USDCContract") # C...
# Convert stroops to USD (7 decimals)
usd = stroops_to_usd(50000000) # Returns 5.0
Configuration
Environment Variables
# Core configuration
X402_FACILITATOR_URL=https://facilitator.ultravioletadao.xyz
X402_VERIFY_TIMEOUT=30
X402_SETTLE_TIMEOUT=55
# Recipient addresses (at least one required)
X402_RECIPIENT_EVM=0xYourEVMWallet
X402_RECIPIENT_SOLANA=YourSolanaAddress
X402_RECIPIENT_NEAR=your-account.near
X402_RECIPIENT_STELLAR=G...YourStellarAddress
# Optional
X402_FACILITATOR_SOLANA=F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq
X402_RESOURCE_URL=https://api.example.com
X402_DESCRIPTION=API access payment
Programmatic Configuration
from uvd_x402_sdk import X402Config, MultiPaymentConfig
# Full configuration
config = X402Config(
facilitator_url="https://facilitator.ultravioletadao.xyz",
# Recipients
recipient_evm="0xYourEVMWallet",
recipient_solana="YourSolanaAddress",
recipient_near="your-account.near",
recipient_stellar="G...YourStellarAddress",
# Timeouts
verify_timeout=30.0,
settle_timeout=55.0,
# Limit to specific networks
supported_networks=["base", "solana", "near", "stellar"],
# Metadata
resource_url="https://api.example.com/premium",
description="Premium API access",
# Protocol version (1, 2, or "auto")
x402_version="auto",
)
# From environment
config = X402Config.from_env()
Facilitator Addresses
The SDK includes all facilitator addresses as embedded constants. You don't need to configure them manually.
Fee Payer Addresses (Non-EVM)
Non-EVM chains require a fee payer address for gasless transactions:
from uvd_x402_sdk import (
# Algorand
ALGORAND_FEE_PAYER_MAINNET, # KIMS5H6QLCUDL65L5UBTOXDPWLMTS7N3AAC3I6B2NCONEI5QIVK7LH2C2I
ALGORAND_FEE_PAYER_TESTNET, # 5DPPDQNYUPCTXRZWRYSF3WPYU6RKAUR25F3YG4EKXQRHV5AUAI62H5GXL4
# Solana
SOLANA_FEE_PAYER_MAINNET, # F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq
SOLANA_FEE_PAYER_DEVNET, # 6xNPewUdKRbEZDReQdpyfNUdgNg8QRc8Mt263T5GZSRv
# Fogo
FOGO_FEE_PAYER_MAINNET, # F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq
FOGO_FEE_PAYER_TESTNET, # 6xNPewUdKRbEZDReQdpyfNUdgNg8QRc8Mt263T5GZSRv
# NEAR
NEAR_FEE_PAYER_MAINNET, # uvd-facilitator.near
NEAR_FEE_PAYER_TESTNET, # uvd-facilitator.testnet
# Stellar
STELLAR_FEE_PAYER_MAINNET, # GCHPGXJT2WFFRFCA5TV4G4E3PMMXLNIDUH27PKDYA4QJ2XGYZWGFZNHB
STELLAR_FEE_PAYER_TESTNET, # GBBFZMLUJEZVI32EN4XA2KPP445XIBTMTRBLYWFIL556RDTHS2OWFQ2Z
# Sui
SUI_FEE_PAYER_MAINNET, # 0xe7bbf2b13f7d72714760aa16e024fa1b35a978793f9893d0568a4fbf356a764a
SUI_FEE_PAYER_TESTNET, # 0xabbd16a2fab2a502c9cfe835195a6fc7d70bfc27cffb40b8b286b52a97006e67
# Helper function
get_fee_payer, # Get fee payer for any network
)
# Get fee payer for any network
fee_payer = get_fee_payer("algorand") # Returns KIMS5H6Q...
fee_payer = get_fee_payer("solana") # Returns F742C4VfF...
fee_payer = get_fee_payer("sui") # Returns 0xe7bbf2b...
fee_payer = get_fee_payer("base") # Returns None (EVM doesn't need fee payer)
EVM Facilitator Addresses
EVM chains use EIP-3009 transferWithAuthorization (gasless by design), but the facilitator wallet addresses are available for reference:
from uvd_x402_sdk import (
EVM_FACILITATOR_MAINNET, # 0x103040545AC5031A11E8C03dd11324C7333a13C7
EVM_FACILITATOR_TESTNET, # 0x34033041a5944B8F10f8E4D8496Bfb84f1A293A8
)
Helper Functions
from uvd_x402_sdk import (
get_fee_payer, # Get fee payer address for a network
requires_fee_payer, # Check if network needs fee payer
get_all_fee_payers, # Get all registered fee payers
build_payment_info, # Build payment info with auto feePayer
DEFAULT_FACILITATOR_URL, # https://facilitator.ultravioletadao.xyz
)
# Check if network needs fee payer
requires_fee_payer("algorand") # True
requires_fee_payer("base") # False
# Build payment info with automatic fee payer
info = build_payment_info(
network="algorand",
pay_to="MERCHANT_ADDRESS...",
max_amount_required="1000000",
description="API access"
)
# info = {
# 'network': 'algorand',
# 'payTo': 'MERCHANT_ADDRESS...',
# 'maxAmountRequired': '1000000',
# 'description': 'API access',
# 'asset': '31566704',
# 'extra': {
# 'token': 'usdc',
# 'feePayer': 'KIMS5H6QLCUDL65L5UBTOXDPWLMTS7N3AAC3I6B2NCONEI5QIVK7LH2C2I'
# }
# }
Registering Custom Networks
from uvd_x402_sdk.networks import NetworkConfig, NetworkType, register_network
# Register a custom EVM network
custom_chain = NetworkConfig(
name="mychain",
display_name="My Custom Chain",
network_type=NetworkType.EVM,
chain_id=12345,
usdc_address="0xUSDCContractAddress",
usdc_decimals=6,
usdc_domain_name="USD Coin", # Check actual EIP-712 domain!
usdc_domain_version="2",
rpc_url="https://rpc.mychain.com",
enabled=True,
)
register_network(custom_chain)
# Now you can use it
config = X402Config(
recipient_evm="0xYourWallet...",
supported_networks=["base", "mychain"],
)
Multi-Token Support
The SDK supports 6 stablecoins on EVM chains. Use the token helper functions to query and work with different tokens.
Querying Token Support
from uvd_x402_sdk import (
TokenType,
get_token_config,
get_supported_tokens,
is_token_supported,
get_networks_by_token,
)
# Check which tokens a network supports
tokens = get_supported_tokens("ethereum")
print(tokens) # ['usdc', 'eurc', 'ausd', 'pyusd']
tokens = get_supported_tokens("base")
print(tokens) # ['usdc', 'eurc']
# Check if a specific token is supported
if is_token_supported("ethereum", "eurc"):
print("EURC is available on Ethereum!")
# Get token configuration
config = get_token_config("ethereum", "eurc")
if config:
print(f"EURC address: {config.address}")
print(f"Decimals: {config.decimals}")
print(f"EIP-712 name: {config.name}")
print(f"EIP-712 version: {config.version}")
# Find all networks that support a token
networks = get_networks_by_token("eurc")
for network in networks:
print(f"EURC available on: {network.display_name}")
# Output: EURC available on: Ethereum, Base, Avalanche C-Chain
Token Configuration
Each token has specific EIP-712 domain parameters required for signing:
from uvd_x402_sdk import TokenConfig, get_token_config
# TokenConfig structure
# - address: Contract address
# - decimals: Token decimals (6 for all supported stablecoins)
# - name: EIP-712 domain name (e.g., "USD Coin", "EURC", "Gho Token")
# - version: EIP-712 domain version
# Example: Get EURC config on Base
eurc = get_token_config("base", "eurc")
# TokenConfig(
# address="0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42",
# decimals=6,
# name="EURC",
# version="2"
# )
# Example: Get PYUSD config on Ethereum
pyusd = get_token_config("ethereum", "pyusd")
# TokenConfig(
# address="0x6c3ea9036406852006290770BEdFcAbA0e23A0e8",
# decimals=6,
# name="PayPal USD",
# version="1"
# )
Available Tokens
| Token | Description | Decimals | Issuer |
|---|---|---|---|
usdc |
USD Coin | 6 | Circle |
eurc |
Euro Coin | 6 | Circle |
ausd |
Agora USD | 6 | Agora Finance |
pyusd |
PayPal USD | 6 | PayPal/Paxos |
Critical Implementation Notes
EIP-712 Domain Names Vary by Chain
The same token may use different EIP-712 domain names on different chains. This affects signature verification.
| Token | Ethereum | Base | Avalanche |
|---|---|---|---|
| EURC | "Euro Coin" |
"EURC" |
"Euro Coin" |
| USDC | "USD Coin" |
"USD Coin" |
"USD Coin" |
| AUSD | "Agora Dollar" |
N/A | "Agora Dollar" |
| PYUSD | "PayPal USD" |
N/A | N/A |
Important: Always use get_token_config() to get the correct domain name. Never hardcode domain names.
# CORRECT: Use get_token_config for each chain
eurc_base = get_token_config("base", "eurc")
# TokenConfig(name="EURC", version="2", ...)
eurc_ethereum = get_token_config("ethereum", "eurc")
# TokenConfig(name="Euro Coin", version="2", ...)
PYUSD Signature Format (PayPal USD)
PYUSD uses the Paxos implementation which only supports the v,r,s signature variant of transferWithAuthorization. This is different from Circle's USDC/EURC which support both compact bytes and v,r,s variants.
Backend implications:
- The x402 facilitator (v1.9.0+) automatically handles this by detecting PYUSD and using
transferWithAuthorization_1(v,r,s)instead oftransferWithAuthorization_0(bytes signature) - If using a custom facilitator, ensure it supports the v,r,s variant for PYUSD
Token Info Must Be Passed to Facilitator
When using non-USDC tokens, your backend must pass the token info (including EIP-712 domain) to the facilitator. This is done via the extra field in paymentRequirements:
# When building payment requirements for the facilitator
payment_requirements = {
"asset": token_address, # Use actual token address, NOT hardcoded USDC
"extra": {
"name": token_config.name, # EIP-712 domain name
"version": token_config.version, # EIP-712 domain version
}
}
Without this, the facilitator will use wrong EIP-712 domain and signature verification will fail with "invalid signature" error.
Error Handling
from uvd_x402_sdk.exceptions import (
X402Error,
PaymentRequiredError,
PaymentVerificationError,
PaymentSettlementError,
UnsupportedNetworkError,
InvalidPayloadError,
FacilitatorError,
X402TimeoutError,
)
try:
result = client.process_payment(header, amount)
except PaymentVerificationError as e:
# Signature invalid, amount mismatch, expired, etc.
print(f"Verification failed: {e.reason}")
print(f"Errors: {e.errors}")
except PaymentSettlementError as e:
# On-chain settlement failed (insufficient balance, nonce used, etc.)
print(f"Settlement failed on {e.network}: {e.message}")
except UnsupportedNetworkError as e:
# Network not recognized or disabled
print(f"Network {e.network} not supported")
print(f"Supported: {e.supported_networks}")
except InvalidPayloadError as e:
# Malformed X-PAYMENT header
print(f"Invalid payload: {e.message}")
except FacilitatorError as e:
# Facilitator returned error
print(f"Facilitator error: {e.status_code} - {e.response_body}")
except X402TimeoutError as e:
# Request timed out
print(f"{e.operation} timed out after {e.timeout_seconds}s")
except X402Error as e:
# Catch-all for x402 errors
print(f"Payment error: {e.message}")
ERC-8004 Trustless Agents
Build verifiable on-chain reputation for AI agents and services. Supports 18 networks (16 EVM + Solana + Solana devnet).
On EVM networks, agent IDs are sequential uint256 integers. On Solana, agent IDs are base58 pubkey strings (NFT asset addresses). The AgentId type (Union[int, str]) handles both.
from uvd_x402_sdk import Erc8004Client, AgentId
async with Erc8004Client() as client:
# EVM: agent_id is an integer
identity = await client.get_identity("ethereum", 42)
print(f"Agent URI: {identity.agent_uri}")
# Solana: agent_id is a base58 pubkey string
identity = await client.get_identity("solana", "8oo4dC4JvBLwy5...")
print(f"Agent URI: {identity.agent_uri}")
# Get agent reputation
reputation = await client.get_reputation("ethereum", 42)
print(f"Score: {reputation.summary.summary_value}")
# Submit feedback after payment
result = await client.submit_feedback(
network="ethereum",
agent_id=42,
value=95,
tag1="quality",
proof=settle_response.proof_of_payment,
)
# Respond to feedback (agents only)
# seal_hash is required for Solana, optional for EVM
await client.append_response(
network="ethereum",
agent_id=42,
feedback_index=1,
response_text="Thank you for your feedback!",
)
/accepts Negotiation
Discover what the facilitator can settle before constructing payment authorizations. Used by Faremeter middleware and clients.
from uvd_x402_sdk import X402Client
client = X402Client(recipient_address="0xMerchant...")
# Ask facilitator what it can settle
enriched = client.negotiate_accepts([
{
"scheme": "exact",
"network": "base-mainnet",
"maxAmountRequired": "1000000",
"resource": "https://api.example.com/data",
"payTo": "0xMerchant...",
}
])
# enriched[0]["extra"] now has feePayer, tokens, escrow config
Escrow & Refunds
Hold payments in escrow with dispute resolution.
from uvd_x402_sdk import EscrowClient
async with EscrowClient() as client:
# Create escrow payment
escrow = await client.create_escrow(
payment_header=request.headers["X-PAYMENT"],
requirements=payment_requirements,
escrow_duration=86400, # 24 hours
)
# Release after service delivery
await client.release(escrow.id)
# Or request refund if service failed
await client.request_refund(
escrow_id=escrow.id,
reason="Service not delivered",
)
Bazaar Discovery
Register and discover paid x402 resources across the network.
from uvd_x402_sdk import BazaarClient
async with BazaarClient() as bazaar:
# List available resources
resources = await bazaar.list_resources(category="finance", network="base-mainnet")
for r in resources.items:
print(f"{r.url} - {r.description}")
# Register your own resource
await bazaar.register_resource(
url="https://api.example.com/data",
resource_type="http",
description="Premium data API",
accepts=[{
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "10000",
"payTo": "0xYourWallet...",
}],
metadata={"category": "finance", "tags": ["market-data"]},
)
WalletAdapter
Abstract wallet interface for signing EIP-3009 authorizations. Use EnvKeyAdapter for raw private keys or OWSWalletAdapter for Open Wallet Standard (future).
pip install uvd-x402-sdk[wallet]
from uvd_x402_sdk import EnvKeyAdapter
# Reads WALLET_PRIVATE_KEY or PRIVATE_KEY from env
wallet = EnvKeyAdapter()
print(wallet.get_address()) # 0x...
# Sign an EIP-3009 ReceiveWithAuthorization
auth = wallet.sign_eip3009({
"to": "0xRecipient...",
"amount_usdc": 0.10,
"network": "base",
})
print(auth["signature"]) # Use as X-PAYMENT header
# Sign arbitrary EIP-712 typed data
result = wallet.sign_typed_data({
"domain": {"name": "MyDapp", "version": "1", "chainId": 8453},
"types": {"Message": [{"name": "content", "type": "string"}]},
"message": {"content": "Hello"},
})
# Sign a personal message (EIP-191)
sig = wallet.sign_message("Hello, world!")
Custom WalletAdapter
Any class implementing the WalletAdapter protocol can be used:
from uvd_x402_sdk import WalletAdapter
class MyWallet:
def get_address(self) -> str: ...
def sign_message(self, message: str) -> str: ...
def sign_typed_data(self, typed_data: dict) -> "SignedTypedData": ...
def sign_eip3009(self, params: "EIP3009Params") -> "EIP3009Authorization": ...
assert isinstance(MyWallet(), WalletAdapter) # True (runtime_checkable)
Facilitator Info
Query the facilitator for version, supported networks, blacklist, and health.
from uvd_x402_sdk import X402Client
client = X402Client(recipient_address="0xYourWallet...")
# Check version
version = client.get_version()
print(f"Facilitator: v{version['version']}")
# List supported networks
supported = client.get_supported()
for kind in supported["kinds"]:
print(f" {kind['network']} - {kind['scheme']}")
# Check blacklist
bl = client.get_blacklist()
print(f"Blocked addresses: {bl['totalBlocked']}")
# Health check
is_healthy = client.health_check()
Escrow State Queries
Query on-chain escrow state without performing settlement.
from uvd_x402_sdk import EscrowClient
async with EscrowClient() as escrow:
state = await escrow.get_escrow_state(
network="base-mainnet",
payer="0xPayer...",
recipient="0xRecipient...",
nonce="0x1234...",
)
print(f"Status: {state['status']}, Balance: {state.get('balance')}")
How x402 Works
The x402 protocol enables gasless stablecoin payments (USDC, EURC, AUSD, PYUSD):
1. User Request --> Client sends request without payment
2. 402 Response <-- Server returns payment requirements
3. User Signs --> Wallet signs authorization (NO GAS!)
4. Frontend Sends --> X-PAYMENT header with signed payload
5. SDK Verifies --> Validates signature with facilitator
6. SDK Settles --> Facilitator executes on-chain transfer
7. Success <-- Payment confirmed, request processed
The facilitator (https://facilitator.ultravioletadao.xyz) handles all on-chain interactions and pays gas fees on behalf of users.
Payment Flow by Network Type
| Network Type | User Signs | Facilitator Does |
|---|---|---|
| EVM | EIP-712 message | Calls transferWithAuthorization() |
| SVM | Partial transaction | Co-signs + submits transaction |
| NEAR | DelegateAction (Borsh) | Wraps in Action::Delegate |
| Stellar | Auth entry (XDR) | Wraps in fee-bump transaction |
| Algorand | ASA transfer tx | Signs fee tx + submits atomic group |
| Sui | Programmable tx block | Sponsors gas + submits transaction |
Error Codes
| Exception | Description |
|---|---|
PaymentRequiredError |
No payment header provided |
PaymentVerificationError |
Signature invalid, amount mismatch, expired |
PaymentSettlementError |
On-chain settlement failed |
UnsupportedNetworkError |
Network not recognized or disabled |
InvalidPayloadError |
Malformed X-PAYMENT header |
FacilitatorError |
Facilitator service error |
ConfigurationError |
Invalid SDK configuration |
X402TimeoutError |
Request timed out |
Security
- Users NEVER pay gas or submit transactions directly
- EVM: Users sign EIP-712 structured messages for any supported stablecoin (USDC, EURC, AUSD, PYUSD)
- Solana/Fogo: Users sign partial transactions (facilitator co-signs and submits)
- Stellar: Users sign Soroban authorization entries only
- NEAR: Users sign NEP-366 meta-transactions (DelegateAction)
- Sui: Users sign programmable transaction blocks (facilitator sponsors gas)
- The facilitator submits and pays for all on-chain transactions
- All signatures include expiration timestamps (
validBefore) for replay protection - Nonces prevent double-spending of authorizations
- Each token has verified contract addresses and EIP-712 domain parameters
Troubleshooting
Common Issues
"Unsupported network"
- Check that the network is in
supported_networks - Verify the network is enabled
- For v2, ensure CAIP-2 format is correct
"Payment verification failed"
- Amount mismatch between expected and signed
- Recipient address mismatch
- Authorization expired (
validBeforein the past) - Nonce already used (replay attack protection)
"Settlement timed out"
- Network congestion - increase
settle_timeout - Facilitator under load - retry after delay
"Invalid payload"
- Check base64 encoding of X-PAYMENT header
- Verify JSON structure matches expected format
- Ensure
x402Versionis 1 or 2
Debug Logging
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("uvd_x402_sdk").setLevel(logging.DEBUG)
Development
# Clone and install
git clone https://github.com/UltravioletaDAO/uvd-x402-sdk-python
cd uvd-x402-sdk-python
pip install -e ".[dev]"
# Run tests
pytest
# Format code
black src tests
ruff check src tests
# Type checking
mypy src
Links
License
MIT License - see LICENSE file.
Changelog
v0.20.0 (2026-04-02)
- WalletAdapter Protocol: Abstract wallet interface for signing operations (
wallet.py)WalletAdapter- runtime-checkable Protocol for any wallet backendEnvKeyAdapter- raw private key from env var or direct paramOWSWalletAdapter- stub for Open Wallet Standard (not yet on PyPI)EIP3009Params,EIP3009Authorization,SignedTypedDataTypedDict types- Auto-detects USDC contract addresses and EIP-712 domain names per network
- Uses proven
encode_typed_data()+sign_message()signing pattern
- New
[wallet]install extra:pip install uvd-x402-sdk[wallet](eth-account>=0.11.0) - eth-account bumped to
>=0.11.0across all extras (signer,wallet,web3)
v0.16.0 (2026-03-03)
- Bazaar Discovery: New
BazaarClientfor resource registration and discoverylist_resources()with pagination, category, and network filteringregister_resource()for publishing paid resources to the BazaarDiscoveryResourceandDiscoveryResponsePydantic models
- Facilitator Info Endpoints: New methods on
X402Clientget_version()- query facilitator version (GET /version)get_supported()- list supported networks/schemes (GET /supported)get_blacklist()- check blocked/sanctioned addresses (GET /blacklist)health_check()- check facilitator availability (GET /health)
- Escrow State Queries: New
get_escrow_state()method onEscrowClient- Query on-chain escrow state via
POST /escrow/state - Read status, balance, timestamps without settlement
- Query on-chain escrow state via
- Bug Fix: Fixed
negotiate_accepts()referencing undefinedself.facilitator_urlandself.timeout- Now correctly uses
self.config.facilitator_urland the HTTP client pool
- Now correctly uses
v0.15.0 (2026-03-03)
- ERC-8004 Solana Support: Full integration with QuantuLabs 8004-solana Anchor program + ATOM Engine
AgentIdtype alias (Union[int, str]) for dual EVM/Solana agent IDs- Solana and Solana-devnet added to
Erc8004Network(18 networks total) - Solana program ID constants (
agent_registry_program,atom_engine_program) - All ERC-8004 methods now accept
AgentId(int for EVM, string for Solana) seal_hashparameter added torevoke_feedback()andappend_response()(SEAL v1 support)
/acceptsNegotiation: Newnegotiate_accepts()method onX402Client- Sends merchant payment requirements to facilitator POST
/accepts - Returns enriched requirements with feePayer, tokens, escrow config
- Faremeter middleware compatibility
- Sends merchant payment requirements to facilitator POST
- Solana Smart Wallet Support: Transparent CPI inner instruction scanning on server side
v0.6.0 (2026-01-30)
- ERC-8004 Trustless Agents: Full client for on-chain reputation system
Erc8004Clientclass with identity, reputation, and feedback methodsappend_response()method for agents to respond to feedbackProofOfPaymentmodel for reputation submission authorizationbuild_erc8004_payment_requirements()helper
- Escrow & Refund Support: Complete escrow payment flow
EscrowClientclass with create, release, refund, dispute methodsEscrowPayment,RefundRequest,Disputemodels- Helper functions:
can_release_escrow(),can_refund_escrow(), etc.
- New Networks: Scroll (534352) and SKALE (1187947933, testnet: 324705682)
- SKALE is gasless L3 with sFUEL
- Scroll is zkEVM Layer 2
- SDK now supports 21 blockchain networks
v0.5.6 (2025-12-31)
- Added
SuiPayloadContentPydantic model for Sui sponsored transactions - Added
coinObjectIdas required field (CRITICAL for facilitator deserialization) - Added
get_sui_payload()method toPaymentPayload - Updated
validate_sui_payload()to requirecoinObjectId
v0.5.5 (2025-12-30)
- Added AUSD (Agora USD) support for Sui mainnet
- Added
SUI_AUSD_COIN_TYPE_MAINNETconstant - Added
get_sui_ausd_coin_type()helper function
v0.5.4 (2025-12-30)
- Sui Blockchain Support: Added Sui mainnet and testnet networks
- Added
NetworkType.SUIfor Sui Move VM chains - Added
SUI_FEE_PAYER_MAINNETandSUI_FEE_PAYER_TESTNETsponsor addresses - Added CAIP-2 support for
sui:mainnetandsui:testnet - Added Sui-specific utilities:
validate_sui_payload(),is_valid_sui_address(),is_valid_sui_coin_type() - SDK now supports 18 blockchain networks
v0.5.3 (2025-12-27)
- Documentation updates for Algorand support
- Updated README with facilitator addresses and changelog
v0.5.2 (2025-12-26)
- Added EVM facilitator addresses for reference
EVM_FACILITATOR_MAINNET: 0x103040545AC5031A11E8C03dd11324C7333a13C7EVM_FACILITATOR_TESTNET: 0x34033041a5944B8F10f8E4D8496Bfb84f1A293A8
v0.5.1 (2025-12-26)
- Changed default Algorand mainnet network name from
algorand-mainnettoalgorand - Aligns with facilitator v1.9.5+ which now uses
algorandas the primary network identifier
v0.5.0 (2025-12-26)
- Facilitator Module: Added
facilitator.pywith all fee payer addresses embedded as constants - SDK users no longer need to configure facilitator addresses manually
- Added constants:
ALGORAND_FEE_PAYER_MAINNET,SOLANA_FEE_PAYER_MAINNET,NEAR_FEE_PAYER_MAINNET,STELLAR_FEE_PAYER_MAINNET, etc. - Added helper functions:
get_fee_payer(),requires_fee_payer(),build_payment_info() - Network-specific helpers:
get_algorand_fee_payer(),get_svm_fee_payer(),get_near_fee_payer(),get_stellar_fee_payer()
v0.4.2 (2025-12-26)
- Algorand Atomic Group Fix: Rewrote Algorand payload format to use GoPlausible x402-avm atomic group spec
- New
AlgorandPaymentPayloaddataclass withpaymentIndexandpaymentGroupfields - Added
build_atomic_group()helper for constructing two-transaction atomic groups - Added
validate_algorand_payload()for payload validation - Added
build_x402_payment_request()for building complete x402 requests
v0.4.1 (2025-12-26)
- Added AUSD (Agora USD) support on Solana using Token2022 program
- Added
TOKEN_2022_PROGRAM_IDconstant - Added
get_token_program_id()andis_token_2022()helpers
v0.4.0 (2025-12-26)
- Algorand Support: Added Algorand mainnet and testnet networks
- Added
ALGORANDNetworkType - Added
algorandoptional dependency (py-algorand-sdk>=2.0.0) - SDK now supports 16 blockchain networks
v0.3.4 (2025-12-22)
- Added USDT support (USDT0 omnichain via LayerZero) on Ethereum, Arbitrum, Optimism, Avalanche, Polygon
- SDK now supports 5 stablecoins: USDC, EURC, AUSD, PYUSD, USDT
v0.3.3 (2025-12-22)
- Fixed EIP-712 domain names: AUSD uses "Agora Dollar" (not "Agora USD")
- Fixed EURC domain name on Ethereum/Avalanche: "Euro Coin" (not "EURC")
v0.3.2 (2025-12-21)
- Added critical implementation notes for multi-token support:
- EIP-712 domain names vary by chain (e.g., EURC is "Euro Coin" on Ethereum but "EURC" on Base)
- PYUSD uses v,r,s signature variant (Paxos implementation)
- Token info must be passed to facilitator via
extrafield
v0.3.1 (2025-12-21)
- Removed GHO and crvUSD token support (not EIP-3009 compatible)
- SDK now supports 4 stablecoins: USDC, EURC, AUSD, PYUSD
v0.3.0 (2025-12-20)
- Multi-Stablecoin Support: Added support for 4 stablecoins on EVM chains
- USDC (all EVM chains)
- EURC (Ethereum, Base, Avalanche)
- AUSD (Ethereum, Arbitrum, Avalanche, Polygon, Monad)
- PYUSD (Ethereum)
- Added
TokenTypeliteral type andTokenConfigdataclass - Added token helper functions:
get_token_config(),get_supported_tokens(),is_token_supported(),get_networks_by_token() - Added
tokensfield toNetworkConfigfor multi-token configurations - Updated EVM network configurations with token contract addresses and EIP-712 domain parameters
v0.2.2 (2025-12-16)
- Added Security section to documentation
- Added Error Codes table
- Updated links to new GitHub repository
- Synced documentation with TypeScript SDK
v0.2.1 (2025-12-16)
- Removed BSC network (doesn't support ERC-3009)
- Added GitHub Actions workflow for PyPI publishing
- Updated to 14 supported networks
v0.2.0 (2025-12-15)
- Added NEAR Protocol support with NEP-366 meta-transactions
- Added Fogo SVM chain support
- Added x402 v2 protocol support with CAIP-2 network identifiers
- Added
acceptsarray for multi-network payment options - Refactored Solana to generic SVM type (supports Solana, Fogo, future SVM chains)
- Added CAIP-2 parsing utilities (
parse_caip2_network,to_caip2_network) - Added
MultiPaymentConfigfor multi-network recipient configuration - Added
Payment402BuilderV2for v2 response construction
v0.1.0 (2025-12-01)
- Initial release
- EVM, Solana, Stellar network support
- Flask, FastAPI, Django, Lambda integrations
- Full Pydantic models
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file uvd_x402_sdk-0.20.0.tar.gz.
File metadata
- Download URL: uvd_x402_sdk-0.20.0.tar.gz
- Upload date:
- Size: 132.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2fb3e000e2a06ec53992fa4e19f4181124246da36589dfdd358c6a393603575
|
|
| MD5 |
513490ed1fb7a4de4bd5b1fe95963d05
|
|
| BLAKE2b-256 |
f36282883db34c6ca97d452ef615830626b4d005af397f746cd72dba9caa979e
|
File details
Details for the file uvd_x402_sdk-0.20.0-py3-none-any.whl.
File metadata
- Download URL: uvd_x402_sdk-0.20.0-py3-none-any.whl
- Upload date:
- Size: 115.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12a09cd12ca8eac5e9975dd43e5844e904f04c6643b4065f7b65215011e05aa5
|
|
| MD5 |
2f84b8e9396769c8d99e9e6acd70f32d
|
|
| BLAKE2b-256 |
a1566b4ef4cb150cd596d559ef0dc2aee4b46e7a6a0b1d73a9e8e7ab4e520c0f
|