Skip to main content

t402: An internet native payments protocol

Project description

t402 Python

Python SDK for the T402 HTTP-native stablecoin payments protocol.

PyPI version Python 3.10+

Installation

pip install t402

# or with uv
uv add t402

Features

  • Multi-Chain Support: EVM (19 USDT0 networks), TON, TRON, Solana, NEAR, Aptos, Tezos, Polkadot, Stacks, Cosmos
  • Server Middleware: FastAPI, Flask, Django, and Starlette integrations
  • Client Libraries: httpx and requests adapters
  • ERC-4337 Account Abstraction: Gasless payments with smart accounts
  • USDT0 Cross-Chain Bridge: LayerZero-powered bridging
  • WDK Integration: Tether Wallet Development Kit support

FastAPI Integration

The simplest way to add t402 payment protection to your FastAPI application:

from fastapi import FastAPI
from t402.fastapi.middleware import require_payment

app = FastAPI()
app.middleware("http")(
    require_payment(price="0.01", pay_to_address="0x209693Bc6afc0C5328bA36FaF03C514EF312287C")
)

@app.get("/")
async def root():
    return {"message": "Hello World"}

To protect specific routes:

app.middleware("http")(
    require_payment(price="0.01",
    pay_to_address="0x209693Bc6afc0C5328bA36FaF03C514EF312287C"),
    path="/foo"  # <-- this can also be a list ex: ["/foo", "/bar"]
)

Flask Integration

The simplest way to add t402 payment protection to your Flask application:

from flask import Flask
from t402.flask.middleware import PaymentMiddleware

app = Flask(__name__)

# Initialize payment middleware
payment_middleware = PaymentMiddleware(app)

# Add payment protection for all routes
payment_middleware.add(
    price="$0.01",
    pay_to_address="0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
)

@app.route("/")
def root():
    return {"message": "Hello World"}

To protect specific routes:

# Protect specific endpoint
payment_middleware.add(
    path="/foo",
    price="$0.001",
    pay_to_address="0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
)

Client Integration

Simple Usage

Httpx Client

from eth_account import Account
from t402.clients.httpx import t402HttpxClient

# Initialize account
account = Account.from_key("your_private_key")

# Create client and make request
async with t402HttpxClient(account=account, base_url="https://api.example.com") as client:
    response = await client.get("/protected-endpoint")
    print(await response.aread())

Requests Session Client

from eth_account import Account
from t402.clients.requests import t402_requests

# Initialize account
account = Account.from_key("your_private_key")

# Create session and make request
session = t402_requests(account)
response = session.get("https://api.example.com/protected-endpoint")
print(response.content)

Advanced Usage

Httpx Extensible Example

import httpx
from eth_account import Account
from t402.clients.httpx import t402_payment_hooks

# Initialize account
account = Account.from_key("your_private_key")

# Create httpx client with t402 payment hooks
async with httpx.AsyncClient(base_url="https://api.example.com") as client:
    # Add payment hooks directly to client
    client.event_hooks = t402_payment_hooks(account)
    
    # Make request - payment handling is automatic
    response = await client.get("/protected-endpoint")
    print(await response.aread())

Requests Session Extensible Example

import requests
from eth_account import Account
from t402.clients.requests import t402_http_adapter

# Initialize account
account = Account.from_key("your_private_key")

# Create session and mount the t402 adapter
session = requests.Session()
adapter = t402_http_adapter(account)

# Mount the adapter for both HTTP and HTTPS
session.mount("http://", adapter)
session.mount("https://", adapter)

# Make request - payment handling is automatic
response = session.get("https://api.example.com/protected-endpoint")
print(response.content)

Manual Server Integration

If you're not using the FastAPI middleware, you can implement the t402 protocol manually. Here's what you'll need to handle:

  1. Return 402 error responses with the appropriate response body
  2. Use the facilitator to validate payments
  3. Use the facilitator to settle payments
  4. Return the appropriate response header to the caller

Here's an example of manual integration:

from typing import Annotated
from fastapi import FastAPI, Request
from t402.types import PaymentRequiredResponse, PaymentRequirements
from t402.encoding import safe_base64_decode

payment_requirements = PaymentRequirements(...)
facilitator = FacilitatorClient(facilitator_url)

@app.get("/foo")
async def foo(req: request: Request):
    payment_required = PaymentRequiredResponse(
        t402_version: 2,
        accepts=[payment_requirements],
        error="",
    )
    payment_header = req.headers.get("PAYMENT-SIGNATURE", "") or req.headers.get("X-PAYMENT", "")

    if payment_header == "":
        payment_required.error = "PAYMENT-SIGNATURE header not set"
        return JSONResponse(
            content=payment_required.model_dump(by_alias=True),
            status_code=402,
        )
    
    payment = PaymentPayload(**json.loads(safe_base64_decode(payment_header)))

    verify_response = await facilitator.verify(payment, payment_requirements)
    if not verify_response.is_valid:
        payment_required.error = "Invalid payment"
        return JSONResponse(
            content=payment_required.model_dump(by_alias=True),
            status_code=402,
        )

    settle_response = await facilitator.settle(payment, payment_requirements)
    if settle_response.success:
        response.headers["PAYMENT-RESPONSE"] = base64.b64encode(
            settle_response.model_dump_json().encode("utf-8")
        ).decode("utf-8")
    else:
        payment_required.error = "Settle failed: " + settle_response.error
        return JSONResponse(
            content=payment_required.model_dump(by_alias=True),
            status_code=402,
        )

For more examples and advanced usage patterns, check out our examples directory.

Multi-Chain Support

TON Network

from t402 import (
    TON_MAINNET,
    TON_TESTNET,
    validate_ton_address,
    prepare_ton_payment_header,
    get_ton_network_config,
)

# Validate address
is_valid = validate_ton_address("EQD...")

# Get network config
config = get_ton_network_config(TON_MAINNET)

TRON Network

from t402 import (
    TRON_MAINNET,
    TRON_NILE,
    validate_tron_address,
    prepare_tron_payment_header,
    get_tron_network_config,
)

# Validate address
is_valid = validate_tron_address("T...")

# Get network config
config = get_tron_network_config(TRON_MAINNET)

Solana (SVM) Network

from t402 import (
    SOLANA_MAINNET,
    SOLANA_DEVNET,
    SOLANA_TESTNET,
    validate_svm_address,
    prepare_svm_payment_header,
    get_svm_network_config,
    get_svm_usdc_address,
    is_svm_network,
)

# Validate address
is_valid = validate_svm_address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")

# Get network config
config = get_svm_network_config(SOLANA_MAINNET)

# Get USDC mint address
usdc_mint = get_svm_usdc_address(SOLANA_MAINNET)

# Check if network is Solana
is_solana = is_svm_network("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")

Install with optional Solana dependencies:

pip install t402[svm]

ERC-4337 Account Abstraction

Gasless payments using smart accounts and paymasters:

from t402 import (
    create_bundler_client,
    create_paymaster,
    create_smart_account,
    SafeAccountConfig,
)

# Create bundler client
bundler = create_bundler_client(
    bundler_type="pimlico",
    api_key="your_api_key",
    chain_id=8453  # Base
)

# Create paymaster for sponsored transactions
paymaster = create_paymaster(
    paymaster_type="pimlico",
    api_key="your_api_key",
    chain_id=8453
)

# Create Safe smart account
account = create_smart_account(
    config=SafeAccountConfig(
        owner_private_key="0x...",
        chain_id=8453,
    ),
    bundler=bundler,
    paymaster=paymaster,
)

USDT0 Cross-Chain Bridge

Bridge USDT0 across chains using LayerZero:

from t402 import (
    create_usdt0_bridge,
    create_cross_chain_payment_router,
    get_bridgeable_chains,
)

# Check supported chains
chains = get_bridgeable_chains()

# Create bridge client
bridge = create_usdt0_bridge(
    private_key="0x...",
    source_chain_id=1,  # Ethereum
)

# Get quote
quote = await bridge.get_quote(
    destination_chain_id=8453,  # Base
    amount="1000000",  # 1 USDT0
)

# Execute bridge
result = await bridge.bridge(
    destination_chain_id=8453,
    amount="1000000",
    recipient="0x...",
)

Deprecation Notice: exact-legacy Scheme

⚠️ Deprecated: The exact-legacy scheme is deprecated and will be removed in a future major version.

The exact-legacy scheme uses the traditional approve + transferFrom pattern for legacy USDT tokens. This has been superseded by the exact scheme with USDT0.

Why Migrate?

Feature exact-legacy exact (USDT0)
Transactions 2 (approve + transfer) 1 (single signature)
Gas Cost User pays gas Gasless (EIP-3009)
Chains ~5 chains 19+ chains
Cross-chain ✅ LayerZero bridge

Migration Guide

# Before (deprecated)
from t402.schemes.evm import ExactLegacyEvmClientScheme, ExactLegacyEvmServerScheme

client_scheme = ExactLegacyEvmClientScheme(signer)
server_scheme = ExactLegacyEvmServerScheme()

# After (recommended)
from t402.schemes.evm import ExactEvmClientScheme, ExactEvmServerScheme

client_scheme = ExactEvmClientScheme(signer)
server_scheme = ExactEvmServerScheme()

USDT0 Token Addresses

Chain USDT0 Address
Ethereum 0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee
Arbitrum 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9
Ink 0x0200C29006150606B650577BBE7B6248F58470c1
Berachain 0x779Ded0c9e1022225f8E0630b35a9b54bE713736
And 15+ more... See USDT0 documentation

WDK Integration

Tether Wallet Development Kit support:

from t402 import (
    WDKSigner,
    generate_seed_phrase,
    WDKConfig,
    get_wdk_usdt0_chains,
)

# Generate new wallet
seed = generate_seed_phrase()

# Create WDK signer
signer = WDKSigner(
    config=WDKConfig(
        seed_phrase=seed,
        chains=get_wdk_usdt0_chains(),
    )
)

# Get address
address = await signer.get_address(chain_id=8453)

# Sign payment
signature = await signer.sign_payment(
    chain_id=8453,
    amount="1000000",
    recipient="0x...",
)

API Reference

Core Types

Type Description
PaymentRequirements Payment configuration
PaymentPayload Signed payment data
VerifyResponse Verification result
SettleResponse Settlement result

Network Utilities

Function Description
is_evm_network(network) Check if EVM network
is_ton_network(network) Check if TON network
is_tron_network(network) Check if TRON network
is_svm_network(network) Check if Solana SVM network
get_network_type(network) Get network type string

Facilitator Client

from t402 import FacilitatorClient, FacilitatorConfig

client = FacilitatorClient(FacilitatorConfig(
    url="https://facilitator.t402.io"
))

# Verify payment
result = await client.verify(payload, requirements)

# Settle payment
result = await client.settle(payload, requirements)

Requirements

  • Python 3.10+
  • pip or uv package manager

Documentation

Full documentation available at docs.t402.io

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

t402-1.12.0.tar.gz (2.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

t402-1.12.0-py3-none-any.whl (2.0 MB view details)

Uploaded Python 3

File details

Details for the file t402-1.12.0.tar.gz.

File metadata

  • Download URL: t402-1.12.0.tar.gz
  • Upload date:
  • Size: 2.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for t402-1.12.0.tar.gz
Algorithm Hash digest
SHA256 c0a5873f88264cffb2674941fb4b0a53092ff7b4acabd4f8fc53c93315ad0253
MD5 f3bccd4d82fa52ba08ec210f290e998f
BLAKE2b-256 23cde43316fe63805e3127a9a1df088c0cdcb10c7edc8fa6e76976c53b60518b

See more details on using hashes here.

File details

Details for the file t402-1.12.0-py3-none-any.whl.

File metadata

  • Download URL: t402-1.12.0-py3-none-any.whl
  • Upload date:
  • Size: 2.0 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for t402-1.12.0-py3-none-any.whl
Algorithm Hash digest
SHA256 37b27b1c2042d985c26bf3962516c7303aaff392057763c98905a6c01c2d9645
MD5 8bc227d2942b50b5d189eead703f913b
BLAKE2b-256 89984c155673f4c567eb3827a8016f424b5915f42c7c3d06b9d07d769458f1ba

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page