Skip to content

Free live x402 check: POST /api/x402/check and the page tokenizen.nl/x402-check - #105

Merged
holistis merged 1 commit into
mainfrom
x402-live-check
Oct 24, 2026
Merged

holistis merged 1 commit into
mainfrom
x402-live-check

Conversation

@holistis

Copy link
Copy Markdown
Owner

A visitor pastes the URL of an x402 route they run. Our server sends it one anonymous request through net-guard, never pays, stores nothing, and answers with a dated verdict: does the payment request pass the official x402 buyer schema (read from the Payment-Required header or the body), and how far up the receipt ladder of agent-receipt-verify does it get (levels 0 to 2, the ones that need no payment).

This reverses the rule written in x402-badge.ts (never measure live). The badge keeps that rule. The live route answers the worry with limits instead of refusing: https and port 443 only, public domain names only, GET and POST with a fixed body, redirects only within the pasted host or its www sibling, any other host asked only for /.well-known/did.json, 64 KB response cap (8 KB for a DID document), at most 6 requests and a 45 second deadline per check with the sockets aborted, 8 checks at once, a two minute cache, 12 per host and 200 in total per hour, 8 per 10 minutes per IP. Body parser errors answer 4xx and log nothing.

Why not x402-lint for the buyer check: it read only the body, and a v2 seller keeps its requirements in the header. Fixed separately in #103 after it called our own live paid route invalid.

agent-receipt-verify is pinned to the commit that passes its injected fetch on to the did:web lookup (holistis/agent-receipt-verify#46). The measured party chooses that lookup, so before the fix it skipped every guard. A test here fails if the global fetch is ever used for it.

Reviews, both ours and neither independent: an adversarial read of the first version found a request relay through redirects and did:web, a response body echoed through a library error, a quadratic key decode, a log leak through the body parser, mislabelled failures and a few smaller things. All of those are fixed in this branch and each has a test that fails without the fix. After that, an automated read-only security scan of the diff (five readers, high effort) raised no candidates. Neither ran the code against the live service.

Known limits that code does not close, written in the README: a party with many IP addresses can use up the hourly global budget, twelve checks of one host lock its owner out for an hour, and a name server that never answers can keep a thread of the shared pool busy (bounded by the eight-at-once cap; UV_THREADPOOL_SIZE=16 in the service environment gives room).

Deploy is by hand on the api server (pull as the service user, npm ci, build, restart the unit). The lockfile on the server has local changes and will be replaced by this one.

Tests: self-check-server and website suites, typecheck and build.

…heck

Pastes the url of an x402 route, our server sends it one anonymous request through net-guard and
answers with a dated verdict: whether the payment request passes the official x402 buyer schema (read
from the Payment-Required header or the body) and how far up the receipt ladder of agent-receipt-verify
it gets (levels 0 to 2, no payment). It never pays, stores nothing and returns verdicts only.

Limits in code: https and 443 only, public domain names only, GET and POST with a fixed body, redirects
only within the pasted host or its www sibling, any other host asked only for /.well-known/did.json,
64 KB response cap (8 KB for a DID document), 6 requests and a 45 second deadline per check with the
sockets aborted, 8 checks at once, 2 minute cache, 12 per host and 200 in total per hour, 8 per 10
minutes per IP. Body parser errors answer 4xx and log nothing. Optional HOST env for the listen address.

agent-receipt-verify is pinned to the commit that passes its injected fetch on to the did:web lookup
(agent-receipt-verify#46). Tests include a did:web case that fails if the global fetch is ever used.

The page /x402-check, sitemap and llms.txt entries, README with the reversal of the badge rule and the
known limits that an adversarial review found and code does not close.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
tokenizen 2dd5b78 Commit Preview URL

Branch Preview URL
Oct 24 2026, 12:00 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
tokenizen-website 2dd5b78 Commit Preview URL

Branch Preview URL
Oct 24 2026, 12:01 PM

@holistis
holistis merged commit 5d7b9d1 into main Oct 24, 2026
6 checks passed
@holistis
holistis deleted the x402-live-check branch October 24, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant