Repository navigation
Free live x402 check: POST /api/x402/check and the page tokenizen.nl/x402-check - #105
Merged
Merged
Conversation
…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.
Deploying with
|
| 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 |
Deploying with
|
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.