One live HTTP 402, eighteen offline tests, zero charges. This is an educational demonstration of the public API operated by the same human owner as the client. The CLI is MIT licensed; using the paid API is optional.
If you have tried an x402 endpoint, you might have confused three very different outcomes:
- The server responds 402 Payment Required with a proposed price.
- A buyer authorizes a transfer, and funds settle on-chain.
- The server completes the paid request and returns the purchased result.
These do not imply each other. I wanted a small Python tool that verifies step 1 and cannot silently perform step 2.
The live experiment
On 20 October 2026, I ran a local, Python-standard-library-only CLI against an existing paid CSV preflight endpoint that our single-owner workflow operates. It is a real HTTPS service, not a mock or testnet; the input for this test was an entirely fictional, 74-byte CSV:
email,amount,date,note
example@example.invalid,19.25,2026-10-19,synthetic
I ran:
python3 -B -m unittest discover -s tests -q
python3 -B csv_x402_quote.py --sample
python3 -B csv_x402_quote.py --sample --quote
The first command passed 18/18 offline tests. The second performed no networking. The third sent one explicit unpaid HTTPS POST to the public merchant.
The server responded with a valid x402 version 2 quote (not a purchased report):
{
"status": "quote_verified_UNPAID",
"x402Version": "2",
"resource": "https://vm5-openapi-x402.onrender.com/v1/csv-preflight",
"network": "eip155:8453",
"scheme": "exact",
"amountAtomic": "5000",
"amountUSDC": "0.005",
"paymentSent": "false",
"walletUsed": "false",
"deliveryVerified": "false"
}
I also verified the quote's exact ERC-20 asset address and intended recipient in the returned header; the abbreviated display above is for readability. No USDC was transferred. No paid result was delivered. This is not a customer sale.
What a correct pre-payment check should actually verify
In x402 v2 the PAYMENT-REQUIRED header is Base64-encoded JSON. Decoding JSON alone is not verification. For a buyer who already knows which product they intended to buy, check the entire proposed payment contract:
| Field | What my client pins |
|---|---|
x402Version |
Exactly numeric 2
|
resource.url |
The expected /v1/csv-preflight HTTPS URL |
accepts |
Exactly one supported payment option |
scheme |
exact |
network |
Base, eip155:8453
|
asset |
Canonical Circle USDC on Base: 0x833589fCD6eDb6E08f4C7C32D4f71b54bdA02913
|
amount |
5000 USDC atomic units, 0.005 USDC
|
payTo |
The preapproved merchant wallet, 0x6b01efA0705E91a7aca54271510bf9e594717f34
|
The recipient check matters just as much as the price check. A malicious or misconfigured response could ask for the right price on the right chain but name another recipient.
My helper rejects malformed Base64, an unsupported x402 version, wrong chain/token/recipient, an unexpected URL, multiple payment offers, wrong amount, and non-402 HTTP responses. It also refuses redirects rather than accidentally transmitting a buyer's CSV to an unrelated host.
One small implementation detail: urllib.request raises HTTPError on a 402 response. Here, a 402 is expected, so handle that status intentionally:
try:
response = opener.open(request, timeout=12)
except urllib.error.HTTPError as exc:
if exc.code != 402:
raise QuoteError(f"unexpected status {exc.code}")
quote = validate_quote_header(exc.headers.get("PAYMENT-REQUIRED"))
else:
response.close()
raise QuoteError("unexpected success without a payment")
The full validate_quote_header function also checks the accepted offer's payment destination and price. It never calls a wallet.
Keep buyer data local until the buyer opts in
The default operation only prints byte, column, and row counts from a synthetic CSV. The --file option reads a local CSV and prints summary statistics without showing row contents.
A buyer would have to explicitly use both --quote and --confirm-send to upload their own CSV to the seller:
python3 csv_x402_quote.py --file ./your-own-nonsecret.csv
# Offline preview: no upload
python3 csv_x402_quote.py --file ./your-own-nonsecret.csv --quote --confirm-send
# One real HTTPS POST containing that CSV, but still NO PAYMENT
Never upload real users' names, private customer files, credentials, payroll, wallet seeds, or regulated data just to test an endpoint. HTTP 402 can arrive after the request body has already been sent, so treating the quote as unpaid does not make the uploaded data private.
What the tests prove—and what they don't
The actual test matrix covers wrong amount, boolean-instead-of-amount, wrong network, wrong token, wrong recipient, wrong resource, old protocol version, duplicate offers, malformed header, unexpected HTTP codes, forbidden redirects, local-file upload consent, CSV size limits, and absence of accidental network calls in default mode.
Those checks prove that the CLI checks the advertised contract. They do not prove the merchant is trustworthy, the output is useful, the buyer's wallet has funds, the transfer will settle, or that a purchase delivered an HTTP 200 result. A quote is not an invoice paid.
For a real purchase, a buyer must use a separate wallet client that they choose and authorize, inspect the actual payment signature, reconcile the unique final on-chain transfer, and separately check the paid delivery. This Python quote tool deliberately cannot sign or pay.
Reproduce the findings or try the public API
- Complete Python client and 18 offline tests (MIT)
- Live no-charge synthetic CSV example
- Optional live paid CSV preflight endpoint — 0.005 Base Circle USDC per independently authorized purchase; a plain unsigned request returns 402, not a paid report.
- DEV's AI disclosure guidelines
The Python CLI, the seller's x402 service, and this post all come from one human-owned, transparently AI-assisted development workflow. We have observed real external purchases of other APIs operated by this owner in the past, but there is no demonstrated new paying customer from this Python CLI or this article. I have not used self-payments, synthetic customers, or fabricated revenue.
The practical rule: verify the 402 contract before you decide to pay, then verify payment and delivery separately. A working quote is just the first rung of a much longer ladder.
Disclosure: This technical article was drafted with AI assistance and checked against actual CLI source, eighteen passing local tests, and one observed live unpaid 402 response. The authoring account represents one economic owner, not independent buyer endorsements.
Top comments (0)