# 10x402 ("ten-ex-four-oh-two") Your 402 works. Agents still cannot pay you. Ship a correct 402 → remove indexing blockers → publish payable terms. 10x402 cannot guarantee indexing, demand or settlement. Its 79-check catalogue covers the HTTP response, v1 body envelope, v2 PAYMENT-REQUIRED header, dual-stack consistency, Bazaar discovery metadata and report safeguards. Every finding includes a specific fix, and every check names the specification section, client source line or CDP requirement its rule comes from. ## Endpoints GET /check — free. Start here: service info, prices, grades, full check catalogue. POST /lint — $0.25. Find conformance blockers to x402 indexing and payment on a live endpoint. takes: a JSON object: { "url": "https://…" } and optionally { "method": "POST" | "GET" }, default POST returns: a JSON lint report: grade, summary, findings[] and checks_run POST /lint/one — $0.02. Run ONE named check against a live endpoint. takes: a JSON object: { "url": "https://…", "check": "V2_B64_URLSAFE" } — exactly one check id from GET /check, plus optionally { "method": "POST" | "GET" } returns: a JSON single-check report: check, applied, passed, the finding with its fix (or null), regime, sources and the envelope summary POST /lint/envelope — $0.10. Check a captured x402 402 for indexing and payment blockers — no fetch. takes: a JSON object: { "status": 402, "headers": { "payment-required": "…", … }, "body": "…" } returns: a JSON lint report: grade, summary, findings[] and checks_run POST /lint/envelope/one — $0.01. Run ONE named check against a response you paste. takes: a JSON object: { "status": 402, "headers": { … }, "body": "…", "check": "V2_B64_URLSAFE" } — exactly one check id from GET /check returns: a JSON single-check report: check, applied, passed, the finding with its fix (or null), regime, sources and the envelope summary ## Paying Every paid call answers 402 first, with an x402 envelope in both protocol versions: v1 as the JSON body, v2 as standard base64 in a PAYMENT-REQUIRED response header. A 402 IS NOT AN ERROR — it is the price, quoted in a form a client can pay. Retry through an x402-capable client holding a wallet with USDC on Base. No account, no API key. asset USDC on Base, 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 network base (v1) / eip155:8453 (v2) prices /lint $0.25, /lint/one $0.02, /lint/envelope $0.10, /lint/envelope/one $0.01 A full 79-check report costs 12.5x one check on a live URL and 10x on a pasted response — a 6.3x and 7.9x per-check advantage. Singles stay the cheaper buy through 12 questions live and 9 pasted; past that, buy the report. The full report is priced for the incident it resolves; a single check is priced to be run in CI. A pasted response costs less than a live one at both scopes, because there is no outbound request to make on your behalf. free tier none, deliberately — one would fail this service's own HTTP_FREE_TIER_200 check You are only charged for reports that are served. A bad URL or a malformed paste settles nothing, even when the payment verified. ## The report {"grade": "A".."F", "summary": {"versions_detected": [...], "payTo", "network", "price", "bazaar_ready": true | false | "n/a", "blockers": [...codes]}, "findings": [{"severity","code","message","fix","core"}], "checks_run": N} checks_run is how many checks APPLIED, not how many exist: a v1-only endpoint legitimately skips every v2 check. ## One named check The two /one routes take the same body plus a required "check", exactly one id from the catalogue below, and answer about that check alone: {"check": "V2_B64_URLSAFE", "applied": true | false, "passed": true | false | null, "finding": {...the finding, with its fix} | null, "note": "present when it did not apply: what did not happen, and why", "regime", "severity", "core", "sources": [...], "summary": {...versions, payTo, network, price...}, "checks_run": 1 | 0} THREE OUTCOMES, NOT TWO. passed null with applied false means the named check did not run against this response — a v2 check against a v1-only endpoint asserted nothing whatsoever. That is not a pass, and reporting it as one would tell a seller their v2 header is fine when they do not have one. summary carries no bazaar_ready here: the second verdict is computed over every bazaar-regime check, and a single-check call bought one check. An unknown or missing check id is a 400 naming the free catalogue. It lints nothing and charges nothing. ## Two verdicts grade can I be PAID. Computed from payment-regime findings only. bazaar_ready can I be FOUND. Computed from bazaar-regime errors, with the blocking codes named in summary.blockers. "n/a" for a v1-only endpoint, whose CDP requirements are a v2 shape. An endpoint can be grade A with bazaar_ready false, and that is the commonest interesting report this service produces: it takes payments correctly and CDP will not catalogue it. Reporting that as a D said the working endpoint was broken and buried the thing that was not. ## Regimes payment 49 checks. The specs' MUSTs and what shipping clients parse, throw on, or refuse to sign. These set the grade. bazaar 24 checks. CDP's validator, prober and seller docs — what it takes to be indexed. These set bazaar_ready, never the grade. hygiene 6 checks. House opinions and client-quirk defenses that break no payment and block no indexing. Info only, always. ## Grades A zero payment-regime errors and zero payment-regime warnings B zero payment-regime errors, one or two warnings C zero payment-regime errors, three or more warnings D one or more payment-regime errors, none of them core F any core error — the envelope is not usable as published Core checks are the ones whose failure makes the envelope unusable as published. Only a payment-regime check can be core. ## Checks Every check carries its sources, so a rule can be traced rather than trusted. Kinds: spec, client-code, cdp-docs, cdp-validator, live, field-report, house-opinion. A house opinion is labelled as one — that is what makes the other citations mean anything. GET /check returns the full array. ### HTTP layer HTTP_STATUS_402 [payment, error, core] an unauthenticated request answers 402 — not core on a 404/405, which is as often the wrong verb as a missing route, and a 200 or a redirect is delegated to HTTP_FREE_TIER_200 and HTTP_REDIRECT rather than counted here twice spec: specs/transports-v2/http.md:7-25 § Payment Required Signaling spec: specs/transports-v1/http.md § Payment Required Signaling client-code: x402-fetch@1.2.0 dist/esm/index.mjs:19 (`if (response.status !== 402) return response`) cdp-validator: cdp-validator-toolshed.json preflight[3] returns_402 (required) HTTP_FREE_TIER_200 [payment, warn] no free tier serving 200s to unauthenticated callers client-code: x402-fetch@1.2.0 dist/esm/index.mjs:19 — a non-402 is returned unpaid; the client never attempts payment cdp-validator: cdp-validator-toolshed.json preflight[3] returns_402 (required) cdp-docs: https://docs.cdp.coinbase.com/x402/seller/get-discovered — endpoints are health-probed on an interval HTTP_SERVER_ERROR [payment, error, core] the endpoint is not 5xx spec: specs/transports-v2/http.md:176-186 § Error Handling client-code: x402-fetch@1.2.0 dist/esm/index.mjs:19 — a 5xx is returned unpaid cdp-validator: cdp-validator-toolshed.json preflight[2] endpoint_reachable (required) HTTP_REDIRECT [payment, warn] the 402 is not behind a redirect client-code: @x402/fetch@2.23.0 dist/esm/index.mjs:10 — `await fetch(request)`, i.e. the default redirect mode, so redirects ARE followed spec: RFC 9110 § 15.4.3 — 301/302 rewrite POST to GET; 307/308 do not cdp-validator: cdp-validator-toolshed.json preflight[0] url_valid — the ADVERTISED url is what is probed HTTP_CONTENT_TYPE_JSON [payment, warn] the v1 envelope body is served as JSON spec: specs/transports-v1/http.md § Payment Required Signaling (Content-Type: application/json) client-code: @x402/core@2.23.0 dist/esm/chunk-BA2VL4DT.mjs:2163 — processResponse parses the body only when content-type includes application/json house-opinion: x402-fetch@1.2.0 dist/esm/index.mjs:22 does NOT branch on content-type, so this costs some client paths and not the main v1 one — hence warn ENVELOPE_PRESENT [payment, error, core] at least one x402 envelope is published spec: specs/transports-v2/http.md:7-25 § Payment Required Signaling spec: specs/transports-v1/http.md § Payment Required Signaling client-code: @x402/core@2.23.0 dist/cjs/http/index.js:1620-1628 — no header and no v1 body throws "Invalid payment required response" ### x402 v2 envelope (the PAYMENT-REQUIRED header) V2_HEADER_PRESENT [bazaar, error] a PAYMENT-REQUIRED response header is present (CDP will not index a v1-only 402) spec: specs/transports-v2/http.md:7-25 § Payment Required Signaling cdp-validator: cdp-validator-toolshed.json preflight[6] payment_required_header (required) client-code: @x402/core@2.23.0 dist/cjs/http/index.js:1620-1628 — the v2 client DOES fall back to a v1 body field-report: x402-foundation/x402#3091 — x402-fetch@1.x is still a live buyer population V2_B64_URLSAFE [payment, error, core] the header is standard base64, not base64url client-code: @x402/core@2.23.0 dist/cjs/utils/index.js:133 — Base64EncodedRegex = /^[A-Za-z0-9+/]*={0,2}$/ client-code: @x402/core@2.23.0 dist/cjs/http/index.js:1778-1781 — the regex is tested on the RAW header, then it throws, before any decode spec: specs/transports-v2/http.md:7-25 § Payment Required Signaling — "Base64-encoded", SILENT on the alphabet V2_B64_DECODE [payment, error, core] the header decodes as base64 client-code: @x402/core@2.23.0 dist/cjs/http/index.js:1781 — JSON.parse(safeBase64Decode(header)), uncaught spec: specs/transports-v2/http.md:7-25 § Payment Required Signaling V2_JSON [payment, error, core] the decoded header is JSON client-code: @x402/core@2.23.0 dist/cjs/http/index.js:1781 — a SyntaxError escapes decodePaymentRequiredHeader spec: specs/x402-specification-v2.md:72-107 § 5.1.1 JSON Payload V2_VERSION [payment, error, core] the v2 payload declares x402Version 2 spec: specs/x402-specification-v2.md:114 § 5.1.2 — x402Version Required, "must be 2" client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:111 — x402Version: z.literal(2), inside a discriminatedUnion field-report: x402-foundation/x402#3045 wire-format bug 1 — a v1-shaped challenge on a v2 resource V2_ACCEPTS_NONEMPTY [payment, error, core] accepts[] is a non-empty array spec: specs/x402-specification-v2.md:117 § 5.1.2 — accepts Required client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:114 — accepts: z.array(PaymentRequirementsV2Schema).min(1) cdp-validator: cdp-validator-toolshed.json preflight[7] has_accepts (required) V2_SCHEME [payment, error, core] each accept names a scheme spec: specs/x402-specification-v2.md:120-131 § 5.1.2 (PaymentRequirements table) client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:102 — scheme: NonEmptyString V2_SCHEME_KNOWN [payment, info] the scheme has a published specification (v2 leaves the field open, so this is an info) spec: specs/schemes/ — exact, upto, batch-settlement, auth-capture each have a scheme document cdp-validator: cdp-validator-toolshed.json preflight[8] accepts[0].scheme, expected "exact or upto" client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:102 — the v2 schema accepts any non-empty string, by design V2_NETWORK_CAIP2 [payment, error, core] network contains a colon (the client’s rule), and is not a v1 plain name spec: specs/x402-specification-v2.md:125 § 5.1.2 — network Required, CAIP-2 format spec: specs/x402-specification-v2.md:616-621 § 11.1 Network Identifiers client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:63-65 — NetworkSchemaV2 = z.string().min(3).refine(v => v.includes(":")) V2_NETWORK_CAIP2_STYLE [hygiene, info] the network string is CAIP-2 shaped (3–8 character namespace) — a style note, not a client rule spec: specs/x402-specification-v2.md:616-621 § 11.1 — "Networks in x402 v2 use CAIP-2 format" house-opinion: no shipping client bounds the namespace; @x402/core requires only min(3) and a colon, so this may only be an info V2_NAMESPACE_KNOWN [hygiene, info] the report says so when a network namespace was checked structurally rather than deeply spec: specs/x402-specification-v2.md:616-621 § 11.1 — namespaces are open-ended; "ach:us" and "sepa:eu" are given as examples spec: specs/schemes/batch-settlement/scheme_batch_settlement_cloudflare.md:7 — cloudflare:402 is a real network with its own scheme document house-opinion: worker/lint.js addressFamily() — eip155 and solana are the namespaces whose address formats this linter knows; everything else is checked structurally, and the report says which V2_NETWORK_SUPPORTED [bazaar, error] the eip155 chain is one CDP’s facilitator settles on cdp-validator: cdp-validator-toolshed.json preflight[9] accepts[0].network, expected "a facilitator-supported network (Base, Solana, Polygon, Arbitrum, World)" house-opinion: a chain outside that set is legal x402 and payable through a self-hosted facilitator — it is CDP indexing that is lost, not payment V2_AMOUNT [payment, error, core] the price is in `amount`, not the v1 `maxAmountRequired` spec: specs/x402-specification-v2.md:120-131 § 5.1.2 (PaymentRequirements table) client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:104 — amount: NonEmptyString; maxAmountRequired is not a v2 key V2_AMOUNT_ATOMIC [payment, error, core] the amount is a string of atomic units spec: specs/x402-specification-v2.md:120-131 § 5.1.2 (PaymentRequirements table) client-code: @x402/evm@2.23.0 dist/cjs/index.js:570 — BigInt(authorization.value); BigInt("0.01") throws client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:433,440 — the reference facilitator schema refines on isInteger V2_AMOUNT_MINIMUM [bazaar, error] the amount clears CDP’s 1000-atomic-unit ($0.001) indexing floor cdp-validator: cdp-validator-toolshed.json preflight[11] accepts[0].amount (required), expected ">= 1000" client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:104 — the client itself applies no numeric bound, so the facilitator is the only enforcer V2_INDEX_AMOUNT [bazaar, error] the amount is a value CDP’s required amount preflight can read at all cdp-validator: cdp-validator-toolshed.json preflight[11] accepts[0].amount (required), expected ">= 1000" — the check compares a value, so an absent or non-integer amount cannot satisfy it V2_INDEX_TIMEOUT [bazaar, error] maxTimeoutSeconds is SET, which is what CDP’s required preflight asks cdp-validator: cdp-validator-toolshed.json preflight[13] accepts[0].maxTimeoutSeconds (required) — "maxTimeoutSeconds is set". Presence is the whole of the provider’s stated rule; the JSON type is a payment question and V2_MAX_TIMEOUT asks it V2_INDEX_ASSET [bazaar, error] asset identifies a token on a chain CDP settles, so its required asset preflight can pass cdp-validator: cdp-validator-toolshed.json preflight[10] accepts[0].asset (required) — "Asset is USDC", captured with a token contract address as the actual value spec: specs/x402-specification-v2.md:127 § 5.1.2 — on a chain, asset is the token contract address; a ticker cannot be the token CDP looks up V2_INDEX_PAYTO [bazaar, error] payTo is an address, which is what CDP’s required payee preflight asks for cdp-validator: cdp-validator-toolshed.json preflight[12] accepts[0].payTo (required) — "payTo address present", captured with a string address as the actual value V2_PAYTO [payment, error, core] payTo has the address shape its network’s namespace requires spec: specs/x402-specification-v2.md:128 § 5.1.2 — "Recipient wallet address or role constant (e.g., \"merchant\")" spec: specs/schemes/exact/scheme_exact_svm.md:53-68 — a base58 payTo on solana:* client-code: @x402/evm@2.23.0 dist/cjs/index.js:537 — `to: getAddress(paymentRequirements.payTo)`; viem throws on a non-address client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:106 — payTo: NonEmptyString, i.e. the shape rule is the scheme’s, not the envelope’s V2_ASSET [payment, error, core] asset names the token in the form its network’s namespace requires spec: specs/x402-specification-v2.md:127 § 5.1.2 — "Token contract address or ISO 4217 currency code for fiat" client-code: @x402/evm@2.23.0 dist/cjs/index.js:565 — verifyingContract: getAddress(requirements.asset) spec: specs/schemes/exact/scheme_exact_svm.md:71 — asset is the token mint public key V2_MAX_TIMEOUT [payment, error, core] maxTimeoutSeconds is a positive JSON number (a string "60" is not one) spec: specs/x402-specification-v2.md:129 § 5.1.2 — maxTimeoutSeconds, type number, Required client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:107 — maxTimeoutSeconds: z.number().positive(), required, no coercion client-code: @x402/evm@2.23.0 dist/cjs/index.js:539 — validBefore is computed from it; undefined yields BigInt("NaN"), which throws cdp-validator: cdp-validator-toolshed.json preflight[13] accepts[0].maxTimeoutSeconds (required) V2_EXTRA_EIP712 [payment, error] extra.{name,version} is present on an eip3009 exact entry, where the client signs from it spec: specs/schemes/exact/scheme_exact_evm.md:72-73 — extra.name and extra.version, both "(required)" spec: specs/schemes/exact/scheme_exact_evm.md:171-172,285-286 — conditional under permit2, optional under erc7710 client-code: @x402/evm@2.23.0 dist/cjs/index.js:555-558 — signEIP3009Authorization throws when either is absent client-code: @x402/evm@2.23.0 dist/cjs/index.js:1261 — assetTransferMethod defaults to "eip3009" V2_ACCEPTS_V1_FIELDS [payment, warn] the accept carries no v1-only fields spec: specs/x402-specification-v2.md:120-131 § 5.1.2 (PaymentRequirements table) client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:101-109 — a plain z.object, so unknown keys are STRIPPED on any re-parse client-code: @x402/core@2.23.0 dist/esm/client/index.mjs:262 — the raw entry is echoed as `accepted`, unstripped V2_RESOURCE_OBJECT [payment, error, core] resource is the v2 object, not a v1 flat string spec: specs/x402-specification-v2.md:116 § 5.1.2 — resource Required, ResourceInfo object client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:113 — resource: ResourceInfoSchema cdp-validator: cdp-validator-toolshed.json preflight[14] has_resource (required) V2_RESOURCE_URL_PARSES [payment, warn] resource.url parses as a URL at all — it is echoed into the payment payload client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:69 — url: NonEmptyString, so the client will happily carry a bare path client-code: @x402/core@2.23.0 dist/cjs/client/index.js:413 — resource is copied verbatim into the outgoing PaymentPayload, which is what a settlement is attributed to field-report: x402-foundation/x402#3045 wire-format bug 3 — "resource.url must be absolute, not a bare path" V2_RESOURCE_URL [bazaar, error] resource.url is an absolute https URL cdp-validator: cdp-validator-toolshed.json preflight[0] url_valid and preflight[1] url_https, both required spec: specs/x402-specification-v2.md:132-141 § 5.1.2 (ResourceInfo table) field-report: x402-foundation/x402#3045 wire-format bug 3 V2_RESOURCE_METHOD [bazaar, warn] resource.method, when published, agrees with bazaar.info.input.method spec: specs/x402-specification-v2.md:132-141 § 5.1.2 (ResourceInfo table) — there is no `method` member, so its absence is conformant spec: specs/extensions/bazaar.md:251-269 — info.input.method is the declared verb live: cdp-validator-toolshed.json paymentRequirements.resource.method — indexed sellers do publish it V2_RESOURCE_DESCRIPTION [bazaar, error] resource.description is under 500 characters (absent is an info; over the limit is an error) spec: specs/x402-specification-v2.md:132-141 § 5.1.2 (ResourceInfo table) — description Optional cdp-docs: https://docs.cdp.coinbase.com/x402/seller/get-discovered — "the CDP Facilitator rejects verify and settle requests whose description exceeds that limit" (500 characters) V2_RESOURCE_MIMETYPE [hygiene, info] resource.mimeType, when published, looks like a media type spec: specs/x402-specification-v2.md:132-141 § 5.1.2 (ResourceInfo table) — mimeType Optional client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:71 — mimeType: z.string().nullish() V2_RESOURCE_URL_MATCHES [hygiene, info] resource.url is the URL that was called client-code: @x402/core@2.23.0 dist/cjs/client/index.js:413 — settlement is attributed to the echoed resource house-opinion: a proxy, a route template or a canonicalised host makes a mismatch legitimate, so this may only ever be an info V2_SERVICE_NAME [bazaar, warn] resource.serviceName, when published, is ≤32 printable-ASCII characters (absence is silent) spec: specs/extensions/bazaar.md:389 — "length ≤ 32 characters"; on violation, "Drop the field." client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:72 — z.string().min(1).max(32).regex(/^[\x20-\x7e]+$/) V2_TAGS [bazaar, warn] resource.tags, when published, are ≤5 entries of ≤32 printable-ASCII characters (absence is silent) spec: specs/extensions/bazaar.md:390 — "at most 5 entries; each entry non-empty, printable ASCII … length ≤ 32" client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:73 — z.array(z.string().min(1).max(32).regex(PRINTABLE_ASCII)).max(5) V2_BAZAAR_PRESENT [bazaar, error] extensions.bazaar is present — in v2 its presence IS the discovery opt-in cdp-validator: cdp-validator-toolshed.json preflight[15] has_bazaar_extension (required) spec: specs/extensions/bazaar.md:512-517 § Client Behavior — omitting the extension means no cataloging field-report: x402-foundation/x402#3045 — a CDP engineer: `extensions.bazaar.discoverable` is "not a valid field" V2_BAZAAR_INFO [bazaar, error] extensions.bazaar.info is present spec: specs/x402-specification-v2.md:143-149 § 5.1.2 (Extensions table) — info Required cdp-validator: cdp-validator-toolshed.json preflight[16] bazaar.info (required) V2_BAZAAR_SCHEMA [bazaar, error] extensions.bazaar.schema is present spec: specs/x402-specification-v2.md:143-149 § 5.1.2 (Extensions table) — schema Required spec: specs/extensions/bazaar.md:322 — "Facilitators must validate info against schema before cataloging" cdp-validator: cdp-validator-toolshed.json preflight[23] bazaar.schema (required) V2_BAZAAR_SCHEMA_CONTENT [bazaar, error] the bazaar schema meets its own content MUSTs: requires `input`, and every $ref/$id is same-document spec: specs/extensions/bazaar.md:313-322 § Schema Validation — Draft 2020-12, "Must define an input property (required)", and "$ref and $id values must be same-document JSON Pointer fragments (starting with #); external references … are not allowed" field-report: x402-foundation/x402#3045 wire-format bug 5 — an external $ref broke CDP’s validator outright V2_BAZAAR_INFO_VALIDATES [bazaar, error] info validates against its own schema spec: specs/extensions/bazaar.md:322 — facilitators MUST validate info against schema before cataloging cdp-validator: cdp-validator-toolshed.json preflight[24] parse (required) field-report: x402-foundation/x402#3045 — an info/schema mismatch is declined silently; nothing reaches the seller’s logs V2_BAZAAR_INPUT [bazaar, error] bazaar.info.input carries a worked sample call spec: specs/extensions/bazaar.md:245-282 § Discovery Info Structure — input is Required in every discriminant cdp-validator: cdp-validator-toolshed.json preflight[17] bazaar.info.input (required) V2_BAZAAR_INPUT_TYPE [bazaar, error] bazaar.info.input.type is the "http" or "mcp" discriminator, with that branch’s required fields spec: specs/extensions/bazaar.md:251-282 — type Required ("http"/"mcp"); bodyType and body Required for POST/PUT/PATCH; toolName and inputSchema Required for mcp cdp-validator: cdp-validator-toolshed.json preflight[18] bazaar.info.input.type (required) field-report: x402-foundation/x402#3045 wire-format bug 4 — the missing `type` discriminator V2_BAZAAR_INPUT_METHOD [bazaar, error] bazaar.info.input.method is an HTTP verb from the spec’s enums, and matches the verb that was probed spec: specs/extensions/bazaar.md:251-269 — method Required, one of GET/HEAD/DELETE or POST/PUT/PATCH cdp-validator: cdp-validator-toolshed.json preflight[19] bazaar.info.input.method and preflight[20] bazaar.info.input.method.matches_request, both required V2_BAZAAR_OUTPUT_TYPE [bazaar, warn] bazaar.info.output, when published, carries its Required `type` spec: specs/extensions/bazaar.md:284-294 § Output Types — output optional; within it, type Required cdp-validator: cdp-validator-toolshed.json preflight[21] bazaar.info.output (advisory) V2_BAZAAR_OUTPUT_EXAMPLE [bazaar, info] bazaar.info.output.example is a computed response — any JSON value, and CDP grades it advisory spec: specs/extensions/bazaar.md:284-294 — the example row is `example | any | No` spec: specs/extensions/bazaar.md:46-53 — the spec’s own GET example gives output.example as an OBJECT cdp-validator: cdp-validator-toolshed.json preflight[22] bazaar.info.output.example (advisory) ### x402 v1 envelope (the 402 body) V1_ABSENT [payment, info] a v1 body envelope is published alongside the v2 header client-code: x402-fetch@1.2.0 dist/esm/index.mjs:22 — the v1 client reads the body and never looks at PAYMENT-REQUIRED field-report: x402-foundation/x402#3091 — the pre-header buyer population is real and shrinking cdp-validator: cdp-validator-toolshed.json preflight[4] valid_json (required) — an EMPTY 402 body fails it, so serve at least `{}` V1_BODY_NOT_ENVELOPE [payment, info] the 402 body is a v1 envelope or is empty, not something a v1 client will misread spec: specs/transports-v2/http.md:172-174 § Response Body ("Response bodies are a server implementation concern") spec: specs/transports-v2/http.md:19-25 — the spec’s own 402 example serves a body of `{}` client-code: x402-fetch@1.2.0 dist/esm/index.mjs:22-23 — an error blob makes accepts undefined and .map throws cdp-validator: cdp-validator-toolshed.json preflight[4] valid_json (required) — the body is parsed as JSON during indexing V1_BODY_PRESENT [payment, warn] a v1 envelope is published in the 402 body spec: specs/transports-v1/http.md § Payment Required Signaling house-opinion: only fires when nothing was published in either transport; ENVELOPE_PRESENT carries the core error for that case V1_BODY_JSON [payment, error, core] the 402 body parses as JSON spec: specs/x402-specification-v1.md § 5.1.1 JSON Payload client-code: x402-fetch@1.2.0 dist/esm/index.mjs:22 — response.json() with no try/catch V1_VERSION [payment, error, core] the body declares x402Version 1 spec: specs/x402-specification-v1.md:99-108 § 5.1.2 client-code: @x402/core@2.23.0 dist/cjs/http/index.js:1625 — the body fallback requires x402Version === 1 exactly client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:388 — x402Versions = [1] V1_ACCEPTS_NONEMPTY [payment, error, core] accepts[] is a non-empty array spec: specs/x402-specification-v1.md:99-108 § 5.1.2 — accepts Required client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:93 — accepts: z.array(PaymentRequirementsV1Schema).min(1) client-code: x402-fetch@1.2.0 dist/esm/index.mjs:23 — accepts.map throws when accepts is absent V1_SCHEME [payment, error, core] each accept names a scheme spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:438 — scheme: z.enum(schemes) V1_SCHEME_KNOWN [payment, error] the v1 scheme is `exact` — v1’s enum is closed where v2’s is open client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:387 — var schemes = ["exact"] client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:438 — scheme: z3.enum(schemes), applied per accepts entry client-code: x402-fetch@1.2.0 dist/esm/index.mjs:22-23 (response.json(), then PaymentRequirementsSchema.parse per entry) V1_MAX_AMOUNT_REQUIRED [payment, error, core] the price is in `maxAmountRequired`, not the v2 `amount` spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:440 — maxAmountRequired is required; `amount` is not a v1 key V1_AMOUNT_ATOMIC [payment, error, core] maxAmountRequired is a string of atomic units spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:433,440 — z3.string().refine(isInteger) client-code: x402-fetch@1.2.0 dist/esm/index.mjs:30 — BigInt(maxAmountRequired) throws on a non-digit string V1_NETWORK_NAME [payment, error, core] network is a v1 plain name, not CAIP-2 spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:16-34 — NetworkSchema is a z.enum of plain names; no member contains a colon V1_NETWORK_KNOWN [payment, error] the v1 network name is one of the seventeen the dominant v1 client’s enum admits client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:16-34 — the closed z.enum: abstract, abstract-testnet, base-sepolia, base, avalanche-fuji, avalanche, iotex, solana-devnet, solana, sei, sei-testnet, polygon, polygon-amoy, peaq, story, educhain, skale-base-sepolia client-code: x402-fetch@1.2.0 dist/esm/index.mjs:22-23 (response.json(), then PaymentRequirementsSchema.parse per entry) house-opinion: @x402/core@2.23.0's v1-compatibility schema is looser (@x402/core@2.23.0 dist/cjs/schemas/index.js:62, NonEmptyString), so this is a claim about the dominant v1 client rather than about every parser — hence error, not core V1_RESOURCE_STRING [payment, error, core] resource is a flat, absolute URL string, not the v2 object spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:441 — resource: z3.string().url(), so a bare path is a hard ZodError field-report: x402-foundation/x402#3045 wire-format bug 3, in its v1 spelling V1_PAYTO [payment, error, core] payTo has the address shape its v1 network requires (EVM 0x, or base58 on solana) spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:435 — EvmOrSvmAddress = EvmAddressRegex.or(SvmAddressRegex) client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:16-34 — the enum includes solana and solana-devnet V1_ASSET [payment, error, core] asset names the token in the form its v1 network requires spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:436,447 — asset: mixedAddressOrSvmAddress client-code: x402@1.2.0 dist/esm/chunk-EJI6X7BV.mjs:75 — verifyingContract: getAddress(asset), which throws on a ticker V1_MIMETYPE [payment, error] mimeType is present (spec: Optional — but the dominant v1 client’s schema requires it) spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) — mimeType Optional client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:443 — mimeType: z3.string(), NOT .optional() client-code: x402-fetch@1.2.0 dist/esm/index.mjs:22-23 (response.json(), then PaymentRequirementsSchema.parse per entry) house-opinion: @x402/core@2.23.0's v1 schema does make it optional (@x402/core@2.23.0 dist/cjs/schemas/index.js:83) — the two v1 parsers disagree V1_DESCRIPTION [payment, error] description is present (missing is an error; present-but-empty is a warn) spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) — description Required client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:442 — description: z3.string(), required client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:82 — required in the modern v1-compatibility schema too V1_MAX_TIMEOUT [payment, error, core] maxTimeoutSeconds is a positive integer JSON number spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) — maxTimeoutSeconds, type number, Required client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:446 — z3.number().int(), so the string "60" is a ZodError client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:86 — z.number().positive(), required V1_EXTRA_EIP712 [payment, error] extra carries the EIP-712 domain the v1 client signs over (EVM networks only) spec: specs/schemes/exact/scheme_exact_evm.md:72-73 — extra.name and extra.version required for eip3009 client-code: x402@1.2.0 dist/esm/chunk-EJI6X7BV.mjs:65-76 — signAuthorization reads extra?.name and extra?.version straight into the typed-data domain, with no fallback house-opinion: the reference facilitator recomputes the domain from its own table, so the mismatch surfaces only as invalid_exact_evm_payload_signature spec: specs/x402-specification-v1.md:261 — v1 Solana exact uses TransferChecked, which has no EIP-712 domain V1_OUTPUT_SCHEMA [bazaar, warn] outputSchema is present for v1 discovery spec: specs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) — outputSchema Optional spec: specs/extensions/bazaar.md:577+ § Backwards Compatibility — v1 discovery rode on outputSchema field-report: x402-foundation/x402#2844 — indexing began after the metadata moved there V1_DISCOVERABLE [bazaar, info] outputSchema.input.discoverable is an opt-OUT — absence means indexed client-code: x402-foundation/x402 go/extensions/v1/facilitator.go (main, read 2026-08-19) — "// Check if discoverable (default to true if not specified)" followed by `discoverable := true`, then an override only when the key is present live: worker/positive-control.js — a live indexed seller nests the flag under outputSchema.input cdp-docs: https://docs.cdp.coinbase.com/x402/bazaar — v1 discovery data reads input.discoverable ### Dual-stack consistency DUAL_PAYTO [payment, error, core] matched offers pay the same address house-opinion: worker/lint.js — two views of one offer; divergence means half the revenue lands elsewhere client-code: @x402/evm@2.23.0 dist/cjs/index.js:568 — getAddress is case-insensitive, so the comparison is too DUAL_PRICE [payment, error, core] matched offers quote the same price house-opinion: worker/lint.js — one offer must not carry two prices; matched on (chain, asset) so different-decimal assets are not compared DUAL_NETWORK [payment, error, core] the two envelopes offer overlapping chains house-opinion: worker/lint.js — a payment signed on one chain is worthless on the other client-code: x402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:52-70 — the client’s own EvmNetworkToChainId map, which is the two spellings of one chain DUAL_ASSET [payment, error, core] matched offers name the same asset house-opinion: worker/lint.js — different assets means the two versions are selling for different money DUAL_RESOURCE [payment, warn] both versions name the same resource URL house-opinion: worker/lint.js — two URLs split one endpoint’s settlement record across two listings field-report: x402-foundation/x402#3045 — discovery keys on the resource URL ### Version-detection hygiene VERSION_HEADER_SAYS_V1 [payment, error] the PAYMENT-REQUIRED header does not carry a v1 payload spec: specs/transports-v2/http.md:7-25 § Payment Required Signaling client-code: @x402/core@2.23.0 dist/cjs/schemas/index.js:128-131 — PaymentRequired is a discriminatedUnion on x402Version, so a v1 payload in the header is legally parsed AS v1 client-code: @x402/core@2.23.0 dist/esm/client/index.mjs:219 — registeredClientSchemes.get(paymentRequired.x402Version): dispatch is on the PAYLOAD’s version, and a v1 client answers with X-PAYMENT while a v2 server reads PAYMENT-SIGNATURE VERSION_BODY_SAYS_V2 [payment, warn] the 402 body does not carry a v2 payload (a core error when no valid v2 header is published) spec: specs/transports-v2/http.md:172-174 § Response Body ("Response bodies are a server implementation concern") client-code: @x402/core@2.23.0 dist/cjs/http/index.js:1620-1628 — the header wins whenever present; the body fallback accepts only x402Version === 1 client-code: x402-fetch@1.2.0 dist/esm/index.mjs:22-23 — a v1 client reads the body with v1 rules whatever it declares ### The report’s own bounds ACCEPTS_TRUNCATED [hygiene, info] at most 8 accepts[] entries are linted per envelope house-opinion: worker/lint.js MAX_ACCEPTS_LINTED = 8 FINDINGS_TRUNCATED [hygiene, info] this report is complete — no bound clipped it house-opinion: worker/lint.js — MAX_FINDINGS = 200, MAX_ACCEPTS_LINTED = 8, and the caller's body byte cap ## Limits POST /lint sends exactly one unauthenticated request with no payment header, follows no redirects, reads at most 256 KB, and gives the whole call — connect, headers and body read — one 10s deadline. It refuses plain http, private/reserved addresses, private-network names, and any port but 443 and 8443. The URL guard does not pre-resolve DNS, so it cannot defend against DNS rebinding. It does not make a payment, query Bazaar's index or measure demand. The report is bounded: at most 8 accepts[] entries are linted, at most 200 findings are returned, and anything quoted back out of your envelope is clipped. Every bound reports itself as an info finding, so a short report is never a quietly truncated one. A non-402 response (a redirect, a free-tier 200, a 405 to the POST this sends) skips the envelope checks entirely and says so in summary.partial — there was never going to be an envelope there. For an endpoint that is not deployed yet, POST /lint/envelope with the response pasted in — same checks, no outbound request. ## Self-lint The test suite lints the 402 that the Worker actually serves. Every build also self-lints all 4 paid endpoint envelopes and fails on any finding. ## Privacy The application store keeps no linted URLs, pasted envelopes or reports. It retains aggregate lint results plus the quota and payment records needed to operate the service. Contact: support@lemon-agent.dev