Skip to main content

Official Python port of the @blockchain0x/x402 wire primitives + client + server adapters

Project description

blockchain0x-x402 (Python)

License: Apache-2.0 Python ≥ 3.9

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.1a0 ships the wire primitives + the X402Client 402-aware fetch wrapper + ASGI middleware (Starlette / FastAPI / Quart) + a Flask before_request hook.

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 with header.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:

  1. Parses the 402 body and picks the requirement matching the SDK's network.
  2. Calls sdk.payments.create(...) to settle on-chain. The SDK auto-attaches an Idempotency-Key so a flaky retry does not double-spend.
  3. Polls sdk.transactions.get(payment_id) every 1s for up to 30s until the transaction confirms.
  4. Rebuilds the request with the X-Payment header 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 no accepts entry 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 to failed status 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


Download files

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

Source Distribution

blockchain0x_x402-0.0.1a0.tar.gz (23.9 kB view details)

Uploaded Source

Built Distribution

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

blockchain0x_x402-0.0.1a0-py3-none-any.whl (23.9 kB view details)

Uploaded Python 3

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

Hashes for blockchain0x_x402-0.0.1a0.tar.gz
Algorithm Hash digest
SHA256 7627b0597ad3a2243fd251d6ed4225e748c0671435586756d87b45792a0efa17
MD5 8b797e55cc64932fd584bc00f91ddf42
BLAKE2b-256 87932a10ee0b9743a2d60635732bcb1cdde3f1779c3e50901e07fbb1fd203a49

See more details on using hashes here.

Provenance

The following attestation bundles were made for blockchain0x_x402-0.0.1a0.tar.gz:

Publisher: publish.yml on Tosh-Labs/blockchain0x-x402-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file blockchain0x_x402-0.0.1a0-py3-none-any.whl.

File metadata

File hashes

Hashes for blockchain0x_x402-0.0.1a0-py3-none-any.whl
Algorithm Hash digest
SHA256 bca7afac3cd628d6548c1379d3359244f6cabafbf87710611b41007f273b0f71
MD5 cf17fc0dab2cf93648874bce6ac60d79
BLAKE2b-256 f78e584e393f793476360968852ff5a2aacbd1a301577a2e00098918e1703689

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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