Skip to main content

x402-nano-exact

Resource-server side of the x402 v2 exact scheme on nano:mainnet for the official x402 Python SDK (x402 >= 2.22). It is the Python counterpart of the JS package @x402nano/exact (./server export): it parses prices into raw and builds the accepts entry; verification and settlement are delegated by the SDK to a Nano facilitator such as facilitator.pursekeeper.dev.

Pure Python; the only dependency is x402 itself (x402[httpx] for the HTTP facilitator client).

Quick start

Nano only. Needs the HTTP facilitator client, which is an extra: pip install 'x402-nano-exact[http]' (it adds x402[httpx]; a bare x402 install fails at initialize() with No module named 'httpx'; verified 2026-09-12 with pip 25 into a clean target). Published on PyPI since 2026-09-18 under the pursekeeper account; the name was offered to the x402nano organisation first (x402nano/exact#4, unanswered) and the offer to transfer the project stands. Development install: pip install 'x402-nano-exact[http] @ git+https://github.com/pursekeeper/x402-nano-exact'.

from x402 import x402ResourceServer
from x402.http import FacilitatorConfig, HTTPFacilitatorClient
from x402_nano_exact import ExactNanoServerScheme

nano_facilitator = HTTPFacilitatorClient(FacilitatorConfig(url="https://facilitator.pursekeeper.dev", timeout=45.0))

server = x402ResourceServer([nano_facilitator])
server.register("nano:mainnet", ExactNanoServerScheme())
server.initialize()  # fetches /supported and routes nano:mainnet to the Nano facilitator

Adding Nano next to an existing Base USDC rail needs two more things: the SDK's EVM extra (pip install 'x402[evm,httpx]', otherwise the import below raises ImportError: EVM mechanism requires ethereum packages) and a facilitator whose /supported lists the Base network you register. https://x402.org/facilitator serves Base Sepolia (eip155:84532) only; for Base mainnet (eip155:8453) use the facilitator your USDC rail already uses.

from x402.mechanisms.evm.exact import ExactEvmServerScheme  # needs x402[evm]

base_facilitator = HTTPFacilitatorClient(FacilitatorConfig(url="https://<the facilitator your Base rail uses>"))
nano_facilitator = HTTPFacilitatorClient(FacilitatorConfig(url="https://facilitator.pursekeeper.dev", timeout=45.0))

server = x402ResourceServer([base_facilitator, nano_facilitator])
server.register("eip155:8453", ExactEvmServerScheme())
server.register("nano:mainnet", ExactNanoServerScheme())
server.initialize()  # routes each network to the facilitator that advertises it

Then use the server exactly as for any other network. A route accepting both:

routes = {
    "GET /api/weather": {
        "accepts": [
            {"scheme": "exact", "network": "eip155:8453", "price": "$0.01", "payTo": "0x..."},
            {"scheme": "exact", "network": "nano:mainnet", "price": "0.01", "payTo": "nano_...", "maxTimeoutSeconds": 60},
        ]
    }
}

See examples/fastapi_server.py for the full FastAPI middleware version (dual rail, so it needs pip install 'x402[evm,httpx,fastapi]').

What goes on the wire

price: "0.01" on nano:mainnet produces this accepts entry (1 XNO = 10^30 raw):

{"scheme": "exact", "network": "nano:mainnet", "asset": "XNO",
 "amount": "10000000000000000000000000000", "payTo": "nano_...", "maxTimeoutSeconds": 60,
 "extra": {"work": "required", "workThreshold": "fffffff800000000"}}

extra.work / extra.workThreshold are copied from the facilitator's /supported entry; values you set in extra yourself take precedence.

Prices

form meaning
"0.01", 0.01, "0.01 XNO" XNO, converted exactly to raw
{"amount": "10000000000000000000000000000", "asset": "XNO"} / AssetAmount(...) already raw
"$0.01", "0.01 USD" (case-insensitive USD) rejected unless you register_money_parser(...) a fiat converter

Rejected: zero/negative, more than 30 decimal places, other assets, and integer amounts above the Nano supply (a raw amount typed as XNO — pass it as AssetAmount). Note the JS @x402nano/exact reads integer strings as raw; here Money is always XNO, matching the SDK's convention for Money.

payTo is checksum-validated at requirement build time; xrb_ is normalized to nano_.

Notes

  • Payment flow is authorization only: verify before the handler, settle after it (the buyer is never charged for a failed request). Same as the JS package.
  • The facilitator's /settle waits for block confirmation for up to 30 s; set FacilitatorConfig(timeout=45.0) so the SDK's HTTP client does not give up first.
  • maxTimeoutSeconds defaults to the SDK's 300 if you do not set it; 60 is customary.

Pitfalls seen in the first integrations

Reported by the first two sellers who wired this in (2026-09-11), with credit. Both are in production now: api.shehriyar.ink (OreoMuncher45, 38 endpoints, USDC on Base plus XNO) and nano-csv-service.onrender.com (Reeyen Patel).

  • Import the right module. The package is x402_nano_exact, not x402nano. One seller wrapped the registration in a broad except and a wrong module name turned into "Nano rail silently disabled on every boot", which looks identical to "not enabled". Let the import fail loudly, or log the exception. (OreoMuncher45)
  • Module-level names are evaluated before your feature flag. A NANO_ADDRESS default referenced at import time, before the NANO_ENABLED check, raised NameError on startup and would have taken a 40-endpoint API down with it. Declare the payout address at module scope or read it inside the flag. (OreoMuncher45)
  • Two networks, two facilitators, both must answer /supported. Running without the Base facilitator key silently fell back to the x402.org testnet facilitator, which does not serve eip155:8453; every EVM route then failed RouteConfigurationError and nothing about it pointed at Nano. Check each facilitator's /supported for its own network before blaming the new scheme. (OreoMuncher45)
  • Price is integer XNO, not raw and not "$0.01". Money follows the SDK convention; a string dollar price is rejected on purpose rather than converted at a guessed rate. (Kept after review by OreoMuncher45; open an issue if you disagree.)
  • Install it somewhere that survives /tmp, and not editable. One production instance had the package installed editable from /tmp/pk-nano (direct_url.json said so). Nothing fails until a tmp cleanup or reboot removes the source; then the import raises, the broad except around registration turns that into NANO_ENABLED = False, and the rail disappears with one log line. Install from a durable path, non-editable, and check pip show -f once. (OreoMuncher45)
  • Price display is per rail. If you post-process accepts by looking the price up from the request path, a second rail inherits the first rail's fiat string: the Nano entry came back with "price": "$0.003" next to a correct raw amount. Machines paying by amount were fine; anyone reading price was not. Branch on network == "nano:mainnet" when enriching. (OreoMuncher45)
  • Free hosting sleeps. A seller on Render Free takes about a minute to wake; fetch a health route with a long timeout first, then get a fresh 402 before building the block, since maxTimeoutSeconds starts at the quote. (Reeyen Patel, github.com/Reeyenn/nano-csv-service, the first live seller on this scheme; settled through facilitator.pursekeeper.dev on 2026-09-11.)
  • The EVM scheme is an extra, and x402.org's facilitator is testnet. from x402.mechanisms.evm.exact import ExactEvmServerScheme raises ImportError unless x402[evm] is installed, and https://x402.org/facilitator advertises eip155:84532 (Base Sepolia), not eip155:8453. An earlier quick start here paired them; it is now Nano-only first, dual rail second. (jackspiece, github.com/jackspiece, 2026-09-11, reproduced in a fresh venv.)

Tests

pip install -e ".[dev]"
pytest                    # offline: SDK-built 402 shape and verify path with a fake facilitator
X402_NANO_LIVE=1 pytest   # plus one live /supported + malformed /verify against facilitator.pursekeeper.dev

Metadata

Release files for x402-nano-exact 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for x402-nano-exact 0.1.0
File Size Uploaded
x402_nano_exact-0.1.0.tar.gz 18.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for x402-nano-exact 0.1.0
File Interpreter ABI Platform
x402_nano_exact-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 29.1 kB

Release files / x402_nano_exact-0.1.0.tar.gz

Download URL x402_nano_exact-0.1.0.tar.gz
Size 18.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e1be4bfb17d3366c164917efaca0630b41520555b358c6b8cd5dfff3c974a600
BLAKE2b-256 checksum
How to use checksums
96d878716559838adf21ce0caf23a0ac073c84ec18581bf50c0beadad0cc5536
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / x402_nano_exact-0.1.0-py3-none-any.whl

Download URL x402_nano_exact-0.1.0-py3-none-any.whl
Size 10.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f64f4243cbe2824ad6b4ab5cc9aad866e63b9450af488aad118d4eb18aafa66f
BLAKE2b-256 checksum
How to use checksums
e89085466016238c62f511553219989a9df7169a98ae5b207fb93e4294279204
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page