Official Python port of the @blockchain0x/x402 wire primitives + client + server adapters
Project description
blockchain0x-x402 (Python)
Official Python port of @blockchain0x/x402.
Ships the wire primitives + a 402-aware fetch wrapper. Sibling
package to blockchain0x; install only when your service either
issues x402-aware HTTP calls (a payer) or verifies inbound x402
payments (a recipient).
Pre-release:
0.0.1a0ships the wire primitives + theX402Client402-aware fetch wrapper + ASGI middleware (Starlette / FastAPI / Quart) + a Flaskbefore_requesthook.
Why a separate package
x402 is a separable concern from the rest of the Blockchain0x SDK:
- A consumer who only verifies inbound webhooks does not need the x402 client stack.
- A service that exposes paid HTTP routes does not need the webhook verifier bundled with it.
Keeping them as two pip-installable packages lets each downstream service depend only on what it actually uses.
Install
pip install blockchain0x-x402
For the payer path (X402Client) you also need the main SDK:
pip install blockchain0x blockchain0x-x402
For the recipient/verifier path you only need blockchain0x-x402.
Verify an inbound x402 payment (recipient)
from blockchain0x_x402 import parse_payment_header, X402WireError
def verify(request):
raw = request.headers.get("X-Payment")
try:
payment = parse_payment_header(raw)
except X402WireError as e:
return JSONResponse({"code": e.code}, status_code=400)
# payment.payment_request_id, payment.tx_hash, payment.network
# ...
The verifier:
- Accepts only
exact-usdc:<base64>scheme; anything else rejects withheader.unknown_scheme. - Validates txHash, payerAddress, amountUsdc, and network shape; any
drift rejects with
header.payload_malformed. - Lowercases hex fields so downstream comparisons against on-chain transaction logs are deterministic.
Issue x402-aware HTTP calls (payer)
import os
from blockchain0x import Client
from blockchain0x_x402 import X402Client
sdk = Client(api_key=os.environ["BLOCKCHAIN0X_API_KEY"])
x402 = X402Client(sdk=sdk, agent_id="agt_...")
response = x402.fetch("https://service-b.com/llm-query", method="POST")
response.raise_for_status()
The wrapper handles a 402 response transparently:
- Parses the 402 body and picks the requirement matching the SDK's network.
- Calls
sdk.payments.create(...)to settle on-chain. The SDK auto-attaches anIdempotency-Keyso a flaky retry does not double-spend. - Polls
sdk.transactions.get(payment_id)every 1s for up to 30s until the transaction confirms. - Rebuilds the request with the
X-Paymentheader and re-issues it once. The second 200 response is returned to the caller.
Failures surface as X402ClientError with stable codes:
no_matching_requirement- the 402 had noacceptsentry for the SDK's network mode.settlement_timeout- the on-chain payment did not confirm within the poll window.chain_failed- the payment row flipped tofailedstatus before confirming.
Expose a paid HTTP route (recipient, server-side)
Two ready-made adapters wrap the verifier into a framework-level gate so paid routes do not have to repeat the parse + settle dance themselves.
Starlette / FastAPI / any ASGI app
from starlette.applications import Starlette
from blockchain0x import Client
from blockchain0x_x402.server import X402Middleware, PricingEntry
sdk = Client(api_key=os.environ["BLOCKCHAIN0X_API_KEY"])
app = Starlette(routes=[...])
app.add_middleware(
X402Middleware,
sdk=sdk,
pricing={
"POST /llm-query": PricingEntry(
amount_usdc="0.10",
pay_to_address="0xabc...",
payment_request_id="pr_demo",
),
},
)
A miss in the pricing table is a no-op (the route is free). A hit
with no valid X-Payment short-circuits the response with HTTP 402
and the canonical accepts[] body the payer needs. A hit with a
valid payment attaches the parsed payload to scope["x402_payment"]
for downstream handlers and lets the request proceed.
Flask
from flask import Flask, g
from blockchain0x import Client
from blockchain0x_x402.server import x402_before_request_factory, PricingEntry
app = Flask(__name__)
app.before_request(x402_before_request_factory(
sdk=Client(api_key=os.environ["BLOCKCHAIN0X_API_KEY"]),
pricing={
"POST /llm-query": PricingEntry(
amount_usdc="0.10",
pay_to_address="0xabc...",
payment_request_id="pr_demo",
),
},
))
@app.post("/llm-query")
def handler():
# g.x402_payment is the verified ExactUsdcPayment payload.
...
Both adapters call sdk.payment_requests.settle() once per request
to anchor trust; the backend's settle route is the chain-of-custody
boundary. The settle() impl may be sync OR async - the adapter
awaits whichever shape it returns.
Wire-format cross-compatibility
The Python build_payment_header output is byte-for-byte identical
to the Node SDK's. A Python payer can pay a Node server, a Node
payer can pay a Python server - the canonical JSON shape is:
{
"scheme": "exact-usdc",
"version": 1,
"paymentRequestId": "...",
"txHash": "...",
"payerAddress": "...",
"amountUsdc": "...",
"network": "..."
}
Keys are insertion-ordered; no whitespace between separators. The
hex fields (txHash, payerAddress) are lowercased before encoding.
License
Apache-2.0.
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 blockchain0x_x402-0.0.1a0.tar.gz.
File metadata
- Download URL: blockchain0x_x402-0.0.1a0.tar.gz
- Upload date:
- Size: 23.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7627b0597ad3a2243fd251d6ed4225e748c0671435586756d87b45792a0efa17
|
|
| MD5 |
8b797e55cc64932fd584bc00f91ddf42
|
|
| BLAKE2b-256 |
87932a10ee0b9743a2d60635732bcb1cdde3f1779c3e50901e07fbb1fd203a49
|
Provenance
The following attestation bundles were made for blockchain0x_x402-0.0.1a0.tar.gz:
Publisher:
publish.yml on Tosh-Labs/blockchain0x-x402-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
blockchain0x_x402-0.0.1a0.tar.gz -
Subject digest:
7627b0597ad3a2243fd251d6ed4225e748c0671435586756d87b45792a0efa17 - Sigstore transparency entry: 1675323519
- Sigstore integration time:
-
Permalink:
Tosh-Labs/blockchain0x-x402-python@650ce2c0365c0f68b569dee9458bfbd61ac9c2b8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Tosh-Labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@650ce2c0365c0f68b569dee9458bfbd61ac9c2b8 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file blockchain0x_x402-0.0.1a0-py3-none-any.whl.
File metadata
- Download URL: blockchain0x_x402-0.0.1a0-py3-none-any.whl
- Upload date:
- Size: 23.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bca7afac3cd628d6548c1379d3359244f6cabafbf87710611b41007f273b0f71
|
|
| MD5 |
cf17fc0dab2cf93648874bce6ac60d79
|
|
| BLAKE2b-256 |
f78e584e393f793476360968852ff5a2aacbd1a301577a2e00098918e1703689
|
Provenance
The following attestation bundles were made for blockchain0x_x402-0.0.1a0-py3-none-any.whl:
Publisher:
publish.yml on Tosh-Labs/blockchain0x-x402-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
blockchain0x_x402-0.0.1a0-py3-none-any.whl -
Subject digest:
bca7afac3cd628d6548c1379d3359244f6cabafbf87710611b41007f273b0f71 - Sigstore transparency entry: 1675323558
- Sigstore integration time:
-
Permalink:
Tosh-Labs/blockchain0x-x402-python@650ce2c0365c0f68b569dee9458bfbd61ac9c2b8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Tosh-Labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@650ce2c0365c0f68b569dee9458bfbd61ac9c2b8 -
Trigger Event:
workflow_dispatch
-
Statement type: