Guide for developing and contributing to the x402 Python SDK.
- Repository Structure
- Development Setup
- Development Workflow
- Adding Features
- Testing
- Code Quality
- Changelog
The Python SDK is a single package using uv for dependency management.
python/
└── x402/
├── pyproject.toml
├── uv.lock
├── src/
│ └── x402/
│ ├── __init__.py
│ ├── types.py # Core types (Pydantic models)
│ ├── encoding.py # Base64 encoding utilities
│ ├── exact.py # Exact scheme implementation
│ ├── facilitator.py # Facilitator client
│ ├── clients/
│ │ ├── base.py # Base client logic
│ │ ├── httpx.py # httpx client integration
│ │ └── requests.py # requests client integration
│ ├── fastapi/
│ │ └── middleware.py # FastAPI middleware
│ └── flask/
│ └── middleware.py # Flask middleware
└── tests/
├── clients/
├── fastapi_tests/
└── flask_tests/
- Python >= 3.10
- uv (recommended) or pip
cd python/x402
# Install uv if you don't have it
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install dependencies
uv sync --all-extras --devcd python/x402
pip install -e ".[dev]"From the python/x402/ directory:
| Command | Description |
|---|---|
uv sync --dev |
Install/update dependencies |
uv run pytest |
Run tests |
uvx ruff check |
Lint code |
uvx ruff check --fix |
Lint and fix |
uvx ruff format |
Format code |
# Install in development mode
uv sync --dev
# Import and use
uv run python -c "from x402 import PaymentRequirements; print(PaymentRequirements)"To add support for a new HTTP client library:
- Create a new file in
src/x402/clients/:
# src/x402/clients/your_client.py
from x402.clients.base import BaseX402Client
class x402YourClient(BaseX402Client):
"""x402 client wrapper for your-library."""
def __init__(self, account, **kwargs):
super().__init__(account)
# Initialize your client
# Implement payment handling hooks-
Export from
src/x402/clients/__init__.py -
Add tests in
tests/clients/test_your_client.py
To add middleware for a new web framework:
- Create a new directory in
src/x402/:
src/x402/your_framework/
├── __init__.py
└── middleware.py
-
Implement the middleware pattern. Reference
src/x402/fastapi/middleware.pyorsrc/x402/flask/middleware.py. -
Key responsibilities:
- Check for payment header on protected routes
- Return 402 with
PaymentRequiredResponseif no/invalid payment - Call facilitator to verify and settle payments
- Add
X-PAYMENT-RESPONSEheader on success
-
Add the dependency to
pyproject.toml:
dependencies = [
# ... existing deps
"your-framework>=1.0.0",
]- Add tests in
tests/your_framework_tests/
See New Chains in the root contributing guide for protocol-level requirements.
To add support for a new blockchain in Python:
- Create the mechanism file in
src/x402/your_chain.py
# src/x402/your_chain.py
from x402.types import PaymentPayload, PaymentRequirements
def sign_payload(
payload: PaymentPayload,
requirements: PaymentRequirements,
signer: YourChainSigner
) -> PaymentPayload:
"""Sign a payment payload for your chain."""
# Implement signing logic
pass- Integrate with the client in
src/x402/clients/base.py - Reference
src/x402/exact.pyfor the existing EVM implementation pattern
# All tests
uv run pytest
# Specific test file
uv run pytest tests/test_types.py
# Specific test
uv run pytest tests/test_types.py::test_payment_requirements
# With verbose output
uv run pytest -v
# With coverage
uv run pytest --cov=x402tests/
├── clients/
│ ├── test_base.py
│ ├── test_httpx.py
│ └── test_requests.py
├── fastapi_tests/
│ └── test_middleware.py
├── flask_tests/
│ └── test_middleware.py
├── test_encoding.py
├── test_exact.py
├── test_paywall.py
└── test_types.py
The package uses pytest-asyncio with auto mode. Async tests work automatically:
async def test_async_operation():
result = await some_async_function()
assert result is not NoneThe project uses Ruff for linting:
# Check for issues
uvx ruff check
# Fix auto-fixable issues
uvx ruff check --fixuvx ruff formatThe package uses Pydantic for runtime validation and includes py.typed for type checker support. All public APIs should have type hints:
def create_payment(
amount: str,
pay_to: str,
network: str = "eip155:8453"
) -> PaymentRequirements:
...These instructions apply to the python/x402 package (v2).
For user-facing changes (behavior changes, bug fixes, new features, removals), add a Towncrier fragment:
- Location:
python/x402/changelog.d/<PR>.<type>.md - Naming convention:
<PR>.<type>.md(for example,123.bugfix.md) - Allowed types:
feature|bugfix|doc|removal|misc
Create a fragment (from python/x402/):
uv run towncrier create --content "Fixed ..." 123.bugfix.mdDuring release, consolidate fragments:
uv run towncrier build --yes --version=X.Y.ZExamples live in examples/python/. When adding a new example:
- Create a directory under the appropriate category (
clients/,servers/,fullstack/) - Add a
pyproject.tomlwith dependencies - Add a
README.mdwith setup and run instructions
Package publishing to PyPI is handled by maintainers via GitHub Actions. Version bumps are made in pyproject.toml.