79 published checks · self-lints at grade A

Your 402 works.Agents still can't pay you.

A 79-check catalogue against your live 402, with a specific fix for each finding — the rules the Bazaar docs never wrote down.

  1. Ship a correct 402
  2. Get indexed
  3. Get paid

10x402 finds the blockers between those steps that are visible in your response, and gives you the fix for each finding. It cannot guarantee a Bazaar listing, demand, or a payment that settles.

10x402 is new. There are no customer stories, usage claims, or testimonials here. The evidence is the published catalogue, self-lint, and storage boundary.

Start here

The catalogue is free. You pay per report served; there is no free lint tier.

free · no payment

For a person building an endpoint

Read every check and price before you pay anything:

curl -sS https://10x402.com/check

Then use /lint for a public URL, or /lint/envelope for a response you captured from local, staging, or authenticated code. To pay and retry, follow the official x402 buyer quickstart for @x402/fetch or another supported client.

machine surfaces

For an agent

In MCP, call x402_checks first.

  1. Ask for the quote

    Your unpaid call answers 402 with the price and payment terms. That is the quote, not an error.

  2. Your client pays and retries

    An x402-capable client holding USDC on Base reads the terms, pays, and retries the same request. No login, no API key.

  3. Read the report

    A grade, the findings, and a specific fix for each one. You are only charged for a report that is served.

Two questions, two rails
routewhat it readshow much of the catalogueprice
GET /checkCatalogue, prices, and grade rulesfree
POST /lintA live public endpointAll 79 checks$0.25 per report
POST /lint/oneA live public endpointOne named check$0.02 per report
POST /lint/envelopeA captured or local 402 responseAll 79 checks$0.10 per report
POST /lint/envelope/oneA captured or local 402 responseOne named check$0.01 per report

The two scopes are two products. A full report is priced for the incident it resolves: a 402 that passes validate and still is not indexed is the class of problem that eats weeks, because nothing in the stack says which of the 79 things is wrong. At $0.25 it is a fraction of the $25 a signed conformance report costs. A single check is the CI product — run on every commit, against one property — and stays micro for that reason.

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. A pasted response costs less than a live one at both scopes, because there is no outbound request to make on your behalf. Every price is per served report: a bad URL, an unreachable target, a malformed paste or an unknown check id settles nothing, even when the payment verified.

Ship a correct 402 → get indexed → get paid

Ship a correct 402

Check the HTTP response, v1 body, v2 PAYMENT-REQUIRED header, and the fields an agent must sign.

Remove indexing blockers

Check Bazaar metadata, info-to-schema consistency, discoverability flags, and what an unpaid probe receives.

Publish payable terms

Check that an agent can read the amount, asset, network, recipient, and EIP-712 domain. The linter does not make a payment.

Why an x402 endpoint passes validate but is not indexed

Validation, discovery, and payment do not all read the same parts of a 402. If your x402 service is not showing up in Bazaar, the base envelope may be valid while discovery metadata is missing, placed incorrectly, or inconsistent with its schema.

A url-safe base64 v2 envelope can be rejected before it is decoded. Missing EIP-712 extra fields can make the client and facilitator sign different domains. A free response can give an unpaid discovery probe a 200 when it expects a 402. These are response-level blockers 10x402 can surface; it does not inspect Bazaar’s index or infer demand.

Choose a lint, then pay and retry

Every paid route answers 402 first. The v1 terms are in the JSON body and the v2 terms are standard base64 in the PAYMENT-REQUIRED header. An x402-capable client holding USDC on Base reads those terms, pays, and retries the same request. There is no login or API key; the payment is the authorization.

POST /lint$0.25 per report

Sends ONE unauthenticated request to the URL you name and lints the response: HTTP status, the v1 body envelope, the v2 PAYMENT-REQUIRED header envelope, dual-stack consistency, and CDP Bazaar discovery requirements. Returns a grade and a specific fix for each finding. It identifies technical blockers; it does not verify a listing or payment.

First, request the quote. This unpaid call returns HTTP 402 with the price and payment terms. It does not return the report yet.

curl -sS -X POST https://10x402.com/lint \
  -H 'content-type: application/json' \
  -d '{"url":"https://toolshed.lemon-agent.dev/convert/md-html","method":"POST"}'

Then let an x402-capable client pay and retry the same request. A successful paid retry returns the report.

Example paid reportgenerated by the current engine

This build-computed example shows the successful paid response shape. The unpaid curl above returns the 402 quote instead.

{
  "grade": "A",
  "summary": {
    "versions_detected": [
      1,
      2
    ],
    "payTo": "0x0adc7adac7bbaffffbd73505711e42378c4f9f9e",
    "network": "eip155:8453",
    "price": "$0.001 (1000 atomic)",
    "bazaar_ready": true,
    "blockers": []
  },
  "findings": [],
  "checks_run": 76
}

POST /lint/one$0.02 per report

The same outbound probe as /lint, reported for exactly one check you name. For settling a single question — "is my v2 header base64url", "does my bazaar info validate against its own schema" — without buying the whole catalogue. The answer says whether the check PASSED, and when the check did not apply to this response it says that instead of quietly passing. GET /check lists every check id, and publishes the batch arithmetic — so you can work out where the full report becomes the cheaper buy before paying for any of it.

First, request the quote. This unpaid call returns HTTP 402 with the price and payment terms. It does not return the report yet.

curl -sS -X POST https://10x402.com/lint/one \
  -H 'content-type: application/json' \
  -d '{"url":"https://toolshed.lemon-agent.dev/convert/md-html","method":"POST","check":"V2_B64_URLSAFE"}'

Then let an x402-capable client pay and retry the same request. A successful paid retry returns the report.

Example paid reportgenerated by the current engine

This build-computed example shows the successful paid response shape. The unpaid curl above returns the 402 quote instead.

{
  "check": "V2_B64_URLSAFE",
  "applied": true,
  "passed": true,
  "finding": null,
  "regime": "payment",
  "severity": "error",
  "core": true,
  "sources": [
    {
      "kind": "client-code",
      "ref": "@x402/core@2.23.0 dist/cjs/utils/index.js:133 — Base64EncodedRegex = /^[A-Za-z0-9+/]*={0,2}$/"
    },
    {
      "kind": "client-code",
      "ref": "@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"
    },
    {
      "kind": "spec",
      "ref": "specs/transports-v2/http.md:7-25 § Payment Required Signaling — \"Base64-encoded\", SILENT on the alphabet",
      "context": true
    }
  ],
  "summary": {
    "versions_detected": [
      1,
      2
    ],
    "payTo": "0x0adc7adac7bbaffffbd73505711e42378c4f9f9e",
    "network": "eip155:8453",
    "price": "$0.001 (1000 atomic)"
  },
  "checks_run": 1
}

POST /lint/envelope$0.10 per report

Runs the same check catalogue against a response you already have: paste the status, headers and body. Nothing is fetched, so it works for v1/v2 migration work, on staging, on localhost and on an endpoint that is not deployed yet. Cheaper than /lint for that reason: there is no outbound request to make on your behalf.

First, request the quote. This unpaid call returns HTTP 402 with the price and payment terms. It does not return the report yet.

curl -sS -X POST https://10x402.com/lint/envelope \
  -H 'content-type: application/json' \
  -d '{"status":402,"headers":{"content-type":"application/json"},"body":"{\"x402Version\":1,\"accepts\":[{\"scheme\":\"exact\",\"network\":\"base\",\"maxAmountRequired\":\"1000\",\"resource\":\"https://example.com/api/thing\",\"description\":\"an example paid endpoint\",\"mimeType\":\"application/json\",\"payTo\":\"0x0000000000000000000000000000000000000001\",\"maxTimeoutSeconds\":60,\"asset\":\"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\"extra\":{\"name\":\"USD Coin\",\"version\":\"2\"},\"outputSchema\":{\"input\":{\"type\":\"http\",\"method\":\"POST\",\"discoverable\":true,\"bodyType\":\"text\",\"description\":\"the request body\"},\"output\":{\"type\":\"string\",\"description\":\"the response body\"}}}]}"}'

Then let an x402-capable client pay and retry the same request. A successful paid retry returns the report.

Example paid reportgenerated by the current engine

This build-computed example shows the successful paid response shape. The unpaid curl above returns the 402 quote instead.

{
  "grade": "A",
  "summary": {
    "versions_detected": [
      1
    ],
    "payTo": "0x0000000000000000000000000000000000000001",
    "network": "base",
    "price": "$0.001 (1000 atomic)",
    "bazaar_ready": "n/a",
    "blockers": [
      "V2_HEADER_PRESENT"
    ]
  },
  "findings": [
    {
      "severity": "error",
      "code": "V2_HEADER_PRESENT",
      "message": "no PAYMENT-REQUIRED response header — this endpoint publishes no x402 v2 envelope.",
      "fix": "Add a PAYMENT-REQUIRED response header to the 402 carrying the standard-base64 JSON v2 envelope. This costs you DISCOVERY rather than payment, and the distinction is worth being precise about: @x402/core reads the header first but DOES fall back to a v1 body when there is none, so the current client generation can still pay you. What it cannot do is find you — CDP marks the PAYMENT-REQUIRED header a required indexing check, so a v1-only 402 is not catalogued at all, and a strictly-v2 client cannot pay it either. Keep the v1 body exactly as it is; the two versions share a 402 without either noticing the other.",
      "core": false,
      "sources": [
        {
          "kind": "spec",
          "ref": "specs/transports-v2/http.md:7-25 § Payment Required Signaling"
        },
        {
          "kind": "cdp-validator",
          "ref": "cdp-validator-toolshed.json preflight[6] payment_required_header (required)"
        },
        {
          "kind": "client-code",
          "ref": "@x402/core@2.23.0 dist/cjs/http/index.js:1620-1628 — the v2 client DOES fall back to a v1 body"
        },
        {
          "kind": "field-report",
          "ref": "x402-foundation/x402#3091 — x402-fetch@1.x is still a live buyer population"
        }
      ]
    }
  ],
  "checks_run": 28
}

POST /lint/envelope/one$0.01 per report

One named check over a response you already have — the cheapest answer this service sells, and the one to reach for in a test or a CI step that asserts a single property of a 402 it just built. Nothing is fetched. The answer says whether the check PASSED, and when the check did not apply to this response it says that instead of quietly passing. GET /check lists every check id.

First, request the quote. This unpaid call returns HTTP 402 with the price and payment terms. It does not return the report yet.

curl -sS -X POST https://10x402.com/lint/envelope/one \
  -H 'content-type: application/json' \
  -d '{"status":402,"headers":{"content-type":"application/json"},"body":"{\"x402Version\":1,\"accepts\":[{\"scheme\":\"exact\",\"network\":\"base\",\"maxAmountRequired\":\"1000\",\"resource\":\"https://example.com/api/thing\",\"description\":\"an example paid endpoint\",\"mimeType\":\"application/json\",\"payTo\":\"0x0000000000000000000000000000000000000001\",\"maxTimeoutSeconds\":60,\"asset\":\"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\"extra\":{\"name\":\"USD Coin\",\"version\":\"2\"},\"outputSchema\":{\"input\":{\"type\":\"http\",\"method\":\"POST\",\"discoverable\":true,\"bodyType\":\"text\",\"description\":\"the request body\"},\"output\":{\"type\":\"string\",\"description\":\"the response body\"}}}]}","check":"V2_HEADER_PRESENT"}'

Then let an x402-capable client pay and retry the same request. A successful paid retry returns the report.

Example paid reportgenerated by the current engine

This build-computed example shows the successful paid response shape. The unpaid curl above returns the 402 quote instead.

{
  "check": "V2_HEADER_PRESENT",
  "applied": true,
  "passed": false,
  "finding": {
    "severity": "error",
    "code": "V2_HEADER_PRESENT",
    "message": "no PAYMENT-REQUIRED response header — this endpoint publishes no x402 v2 envelope.",
    "fix": "Add a PAYMENT-REQUIRED response header to the 402 carrying the standard-base64 JSON v2 envelope. This costs you DISCOVERY rather than payment, and the distinction is worth being precise about: @x402/core reads the header first but DOES fall back to a v1 body when there is none, so the current client generation can still pay you. What it cannot do is find you — CDP marks the PAYMENT-REQUIRED header a required indexing check, so a v1-only 402 is not catalogued at all, and a strictly-v2 client cannot pay it either. Keep the v1 body exactly as it is; the two versions share a 402 without either noticing the other.",
    "core": false,
    "sources": [
      {
        "kind": "spec",
        "ref": "specs/transports-v2/http.md:7-25 § Payment Required Signaling"
      },
      {
        "kind": "cdp-validator",
        "ref": "cdp-validator-toolshed.json preflight[6] payment_required_header (required)"
      },
      {
        "kind": "client-code",
        "ref": "@x402/core@2.23.0 dist/cjs/http/index.js:1620-1628 — the v2 client DOES fall back to a v1 body"
      },
      {
        "kind": "field-report",
        "ref": "x402-foundation/x402#3091 — x402-fetch@1.x is still a live buyer population"
      }
    ]
  },
  "regime": "bazaar",
  "severity": "error",
  "core": false,
  "sources": [
    {
      "kind": "spec",
      "ref": "specs/transports-v2/http.md:7-25 § Payment Required Signaling"
    },
    {
      "kind": "cdp-validator",
      "ref": "cdp-validator-toolshed.json preflight[6] payment_required_header (required)"
    },
    {
      "kind": "client-code",
      "ref": "@x402/core@2.23.0 dist/cjs/http/index.js:1620-1628 — the v2 client DOES fall back to a v1 body"
    },
    {
      "kind": "field-report",
      "ref": "x402-foundation/x402#3091 — x402-fetch@1.x is still a live buyer population"
    }
  ],
  "summary": {
    "versions_detected": [
      1
    ],
    "payTo": "0x0000000000000000000000000000000000000001",
    "network": "base",
    "price": "$0.001 (1000 atomic)"
  },
  "checks_run": 1
}

Payment terms: USDC on Base at 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; base in v1 and eip155:8453 in v2.

You are only charged for a report that is served. A bad URL, unreachable target, or malformed paste settles nothing, even if the payment verified.

Read the report: fix payment blockers first

The grade ladder
gradewhen
Azero payment-regime errors and zero payment-regime warnings
Bzero payment-regime errors, one or two warnings
Czero payment-regime errors, three or more warnings
Done or more payment-regime errors, none of them core
Fany core error — the envelope is not usable as published

Core checks are the failures that make an envelope unusable as published. One core error is an F. Ordinary errors are a D; warnings count toward B or C.

Severities: error — a client, a facilitator or the discovery index will reject or mis-read this; warn — it works, but it costs you something you probably want; info — a nit; never affects the grade.

Two verdicts, because there are two questions

The grade answers “can I be paid”, and only that. It counts payment-regime findings: the specs’ MUSTs, and what a shipping client parses, throws on, or refuses to sign.

summary.bazaar_ready answers “can I be found”true, false, or "n/a" for a v1-only endpoint — from bazaar-regime errors, with the blocking codes listed in summary.blockers.

They come apart more often than you would expect, and the case that matters is grade A with bazaar_ready: false: an endpoint taking payments correctly that CDP will not catalogue. That is the exact shape sellers describe as “my endpoint passes validate but is not indexed”, and reporting it as a D told them their working endpoint was broken while burying the thing that was actually wrong.

checks_run is the number of catalogue checks that applied, not the total available. A v1-only response legitimately skips v2 checks.

Two things you should not have to take on faith

It has to pass its own lint

The test suite runs the production-configured Worker under workerd, takes the 402 it actually serves for every paid endpoint, and requires grade A with zero findings. Every build also constructs both paid envelopes, self-lints them, and fails on any finding before writing dist/.

What you lint is your business

The application store keeps no linted URLs, no pasted envelopes, and no reports. It retains aggregate lint results plus the quota and payment records needed to operate the service; it does not persist the material being linted.

The suite also keeps a frozen 402 captured from a live production seller as a positive control. It is not presented as a current live-domain check.

The x402 conformance checklist: 79 published checks

77 checks inspect HTTP and x402 conformance. 2 report safeguards disclose truncated input or findings, so a partial report cannot read as clean. Every finding includes a code, message, severity, and specific fix.

Each check also names its regime and its sources. 49 checks are payment — the specs’ MUSTs and what shipping clients parse or throw on, and the only findings that set the grade. 24 are bazaar — what CDP requires to index you, reported as bazaar_ready instead. 6 are hygiene, which are info and never grade. A rule with no citation is an assertion, so every row carries one — including the ones whose honest answer is house-opinion.

HTTP layer6 checks
HTTP layer: 6 checks
codeseverityregimewhat it checks, and where the rule comes from
HTTP_STATUS_402 errorcore payment 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
  • specspecs/transports-v2/http.md:7-25 § Payment Required Signaling
  • specspecs/transports-v1/http.md § Payment Required Signaling
  • client-codex402-fetch@1.2.0 dist/esm/index.mjs:19 (`if (response.status !== 402) return response`)
  • cdp-validatorcdp-validator-toolshed.json preflight[3] returns_402 (required)
HTTP_FREE_TIER_200 warn payment no free tier serving 200s to unauthenticated callers
  • client-codex402-fetch@1.2.0 dist/esm/index.mjs:19 — a non-402 is returned unpaid; the client never attempts payment
  • cdp-validatorcdp-validator-toolshed.json preflight[3] returns_402 (required)
  • cdp-docshttps://docs.cdp.coinbase.com/x402/seller/get-discovered — endpoints are health-probed on an interval
HTTP_SERVER_ERROR errorcore payment the endpoint is not 5xx
  • specspecs/transports-v2/http.md:176-186 § Error Handling
  • client-codex402-fetch@1.2.0 dist/esm/index.mjs:19 — a 5xx is returned unpaid
  • cdp-validatorcdp-validator-toolshed.json preflight[2] endpoint_reachable (required)
HTTP_REDIRECT warn payment 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
  • specRFC 9110 § 15.4.3 — 301/302 rewrite POST to GET; 307/308 do not
  • cdp-validatorcdp-validator-toolshed.json preflight[0] url_valid — the ADVERTISED url is what is probed
HTTP_CONTENT_TYPE_JSON warn payment the v1 envelope body is served as JSON
  • specspecs/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-opinionx402-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 errorcore payment at least one x402 envelope is published
  • specspecs/transports-v2/http.md:7-25 § Payment Required Signaling
  • specspecs/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)43 checks
x402 v2 envelope (the PAYMENT-REQUIRED header): 43 checks
codeseverityregimewhat it checks, and where the rule comes from
V2_HEADER_PRESENT error bazaar a PAYMENT-REQUIRED response header is present (CDP will not index a v1-only 402)
  • specspecs/transports-v2/http.md:7-25 § Payment Required Signaling
  • cdp-validatorcdp-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-reportx402-foundation/x402#3091 — x402-fetch@1.x is still a live buyer population
V2_B64_URLSAFE errorcore payment 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
  • specspecs/transports-v2/http.md:7-25 § Payment Required Signaling — "Base64-encoded", SILENT on the alphabet
V2_B64_DECODE errorcore payment the header decodes as base64
  • client-code@x402/core@2.23.0 dist/cjs/http/index.js:1781 — JSON.parse(safeBase64Decode(header)), uncaught
  • specspecs/transports-v2/http.md:7-25 § Payment Required Signaling
V2_JSON errorcore payment the decoded header is JSON
  • client-code@x402/core@2.23.0 dist/cjs/http/index.js:1781 — a SyntaxError escapes decodePaymentRequiredHeader
  • specspecs/x402-specification-v2.md:72-107 § 5.1.1 JSON Payload
V2_VERSION errorcore payment the v2 payload declares x402Version 2
  • specspecs/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-reportx402-foundation/x402#3045 wire-format bug 1 — a v1-shaped challenge on a v2 resource
V2_ACCEPTS_NONEMPTY errorcore payment accepts[] is a non-empty array
  • specspecs/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-validatorcdp-validator-toolshed.json preflight[7] has_accepts (required)
V2_SCHEME errorcore payment each accept names a scheme
  • specspecs/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 info payment the scheme has a published specification (v2 leaves the field open, so this is an info)
  • specspecs/schemes/ — exact, upto, batch-settlement, auth-capture each have a scheme document
  • cdp-validatorcdp-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 errorcore payment network contains a colon (the client’s rule), and is not a v1 plain name
  • specspecs/x402-specification-v2.md:125 § 5.1.2 — network Required, CAIP-2 format
  • specspecs/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 info hygiene the network string is CAIP-2 shaped (3–8 character namespace) — a style note, not a client rule
  • specspecs/x402-specification-v2.md:616-621 § 11.1 — "Networks in x402 v2 use CAIP-2 format"
  • house-opinionno shipping client bounds the namespace; @x402/core requires only min(3) and a colon, so this may only be an info
V2_NAMESPACE_KNOWN info hygiene the report says so when a network namespace was checked structurally rather than deeply
  • specspecs/x402-specification-v2.md:616-621 § 11.1 — namespaces are open-ended; "ach:us" and "sepa:eu" are given as examples
  • specspecs/schemes/batch-settlement/scheme_batch_settlement_cloudflare.md:7 — cloudflare:402 is a real network with its own scheme document
  • house-opinionworker/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 error bazaar the eip155 chain is one CDP’s facilitator settles on
  • cdp-validatorcdp-validator-toolshed.json preflight[9] accepts[0].network, expected "a facilitator-supported network (Base, Solana, Polygon, Arbitrum, World)"
  • house-opiniona 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 errorcore payment the price is in amount, not the v1 maxAmountRequired
  • specspecs/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 errorcore payment the amount is a string of atomic units
  • specspecs/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-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:433,440 — the reference facilitator schema refines on isInteger
V2_AMOUNT_MINIMUM error bazaar the amount clears CDP’s 1000-atomic-unit ($0.001) indexing floor
  • cdp-validatorcdp-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 error bazaar the amount is a value CDP’s required amount preflight can read at all
  • cdp-validatorcdp-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 error bazaar maxTimeoutSeconds is SET, which is what CDP’s required preflight asks
  • cdp-validatorcdp-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 error bazaar asset identifies a token on a chain CDP settles, so its required asset preflight can pass
  • cdp-validatorcdp-validator-toolshed.json preflight[10] accepts[0].asset (required) — "Asset is USDC", captured with a token contract address as the actual value
  • specspecs/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 error bazaar payTo is an address, which is what CDP’s required payee preflight asks for
  • cdp-validatorcdp-validator-toolshed.json preflight[12] accepts[0].payTo (required) — "payTo address present", captured with a string address as the actual value
V2_PAYTO errorcore payment payTo has the address shape its network’s namespace requires
  • specspecs/x402-specification-v2.md:128 § 5.1.2 — "Recipient wallet address or role constant (e.g., \"merchant\")"
  • specspecs/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 errorcore payment asset names the token in the form its network’s namespace requires
  • specspecs/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)
  • specspecs/schemes/exact/scheme_exact_svm.md:71 — asset is the token mint public key
V2_MAX_TIMEOUT errorcore payment maxTimeoutSeconds is a positive JSON number (a string "60" is not one)
  • specspecs/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-validatorcdp-validator-toolshed.json preflight[13] accepts[0].maxTimeoutSeconds (required)
V2_EXTRA_EIP712 error payment extra.{name,version} is present on an eip3009 exact entry, where the client signs from it
  • specspecs/schemes/exact/scheme_exact_evm.md:72-73 — extra.name and extra.version, both "(required)"
  • specspecs/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 warn payment the accept carries no v1-only fields
  • specspecs/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 errorcore payment resource is the v2 object, not a v1 flat string
  • specspecs/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-validatorcdp-validator-toolshed.json preflight[14] has_resource (required)
V2_RESOURCE_URL_PARSES warn payment 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-reportx402-foundation/x402#3045 wire-format bug 3 — "resource.url must be absolute, not a bare path"
V2_RESOURCE_URL error bazaar resource.url is an absolute https URL
  • cdp-validatorcdp-validator-toolshed.json preflight[0] url_valid and preflight[1] url_https, both required
  • specspecs/x402-specification-v2.md:132-141 § 5.1.2 (ResourceInfo table)
  • field-reportx402-foundation/x402#3045 wire-format bug 3
V2_RESOURCE_METHOD warn bazaar resource.method, when published, agrees with bazaar.info.input.method
  • specspecs/x402-specification-v2.md:132-141 § 5.1.2 (ResourceInfo table) — there is no `method` member, so its absence is conformant
  • specspecs/extensions/bazaar.md:251-269 — info.input.method is the declared verb
  • livecdp-validator-toolshed.json paymentRequirements.resource.method — indexed sellers do publish it
V2_RESOURCE_DESCRIPTION error bazaar resource.description is under 500 characters (absent is an info; over the limit is an error)
  • specspecs/x402-specification-v2.md:132-141 § 5.1.2 (ResourceInfo table) — description Optional
  • cdp-docshttps://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 info hygiene resource.mimeType, when published, looks like a media type
  • specspecs/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 info hygiene 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-opiniona proxy, a route template or a canonicalised host makes a mismatch legitimate, so this may only ever be an info
V2_SERVICE_NAME warn bazaar resource.serviceName, when published, is ≤32 printable-ASCII characters (absence is silent)
  • specspecs/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 warn bazaar resource.tags, when published, are ≤5 entries of ≤32 printable-ASCII characters (absence is silent)
  • specspecs/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 error bazaar extensions.bazaar is present — in v2 its presence IS the discovery opt-in
  • cdp-validatorcdp-validator-toolshed.json preflight[15] has_bazaar_extension (required)
  • specspecs/extensions/bazaar.md:512-517 § Client Behavior — omitting the extension means no cataloging
  • field-reportx402-foundation/x402#3045 — a CDP engineer: `extensions.bazaar.discoverable` is "not a valid field"
V2_BAZAAR_INFO error bazaar extensions.bazaar.info is present
  • specspecs/x402-specification-v2.md:143-149 § 5.1.2 (Extensions table) — info Required
  • cdp-validatorcdp-validator-toolshed.json preflight[16] bazaar.info (required)
V2_BAZAAR_SCHEMA error bazaar extensions.bazaar.schema is present
  • specspecs/x402-specification-v2.md:143-149 § 5.1.2 (Extensions table) — schema Required
  • specspecs/extensions/bazaar.md:322 — "Facilitators must validate info against schema before cataloging"
  • cdp-validatorcdp-validator-toolshed.json preflight[23] bazaar.schema (required)
V2_BAZAAR_SCHEMA_CONTENT error bazaar the bazaar schema meets its own content MUSTs: requires input, and every $ref/$id is same-document
  • specspecs/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-reportx402-foundation/x402#3045 wire-format bug 5 — an external $ref broke CDP’s validator outright
V2_BAZAAR_INFO_VALIDATES error bazaar info validates against its own schema
  • specspecs/extensions/bazaar.md:322 — facilitators MUST validate info against schema before cataloging
  • cdp-validatorcdp-validator-toolshed.json preflight[24] parse (required)
  • field-reportx402-foundation/x402#3045 — an info/schema mismatch is declined silently; nothing reaches the seller’s logs
V2_BAZAAR_INPUT error bazaar bazaar.info.input carries a worked sample call
  • specspecs/extensions/bazaar.md:245-282 § Discovery Info Structure — input is Required in every discriminant
  • cdp-validatorcdp-validator-toolshed.json preflight[17] bazaar.info.input (required)
V2_BAZAAR_INPUT_TYPE error bazaar bazaar.info.input.type is the "http" or "mcp" discriminator, with that branch’s required fields
  • specspecs/extensions/bazaar.md:251-282 — type Required ("http"/"mcp"); bodyType and body Required for POST/PUT/PATCH; toolName and inputSchema Required for mcp
  • cdp-validatorcdp-validator-toolshed.json preflight[18] bazaar.info.input.type (required)
  • field-reportx402-foundation/x402#3045 wire-format bug 4 — the missing `type` discriminator
V2_BAZAAR_INPUT_METHOD error bazaar bazaar.info.input.method is an HTTP verb from the spec’s enums, and matches the verb that was probed
  • specspecs/extensions/bazaar.md:251-269 — method Required, one of GET/HEAD/DELETE or POST/PUT/PATCH
  • cdp-validatorcdp-validator-toolshed.json preflight[19] bazaar.info.input.method and preflight[20] bazaar.info.input.method.matches_request, both required
V2_BAZAAR_OUTPUT_TYPE warn bazaar bazaar.info.output, when published, carries its Required type
  • specspecs/extensions/bazaar.md:284-294 § Output Types — output optional; within it, type Required
  • cdp-validatorcdp-validator-toolshed.json preflight[21] bazaar.info.output (advisory)
V2_BAZAAR_OUTPUT_EXAMPLE info bazaar bazaar.info.output.example is a computed response — any JSON value, and CDP grades it advisory
  • specspecs/extensions/bazaar.md:284-294 — the example row is `example | any | No`
  • specspecs/extensions/bazaar.md:46-53 — the spec’s own GET example gives output.example as an OBJECT
  • cdp-validatorcdp-validator-toolshed.json preflight[22] bazaar.info.output.example (advisory)
x402 v1 envelope (the 402 body)21 checks
x402 v1 envelope (the 402 body): 21 checks
codeseverityregimewhat it checks, and where the rule comes from
V1_ABSENT info payment a v1 body envelope is published alongside the v2 header
  • client-codex402-fetch@1.2.0 dist/esm/index.mjs:22 — the v1 client reads the body and never looks at PAYMENT-REQUIRED
  • field-reportx402-foundation/x402#3091 — the pre-header buyer population is real and shrinking
  • cdp-validatorcdp-validator-toolshed.json preflight[4] valid_json (required) — an EMPTY 402 body fails it, so serve at least `{}`
V1_BODY_NOT_ENVELOPE info payment the 402 body is a v1 envelope or is empty, not something a v1 client will misread
  • specspecs/transports-v2/http.md:172-174 § Response Body ("Response bodies are a server implementation concern")
  • specspecs/transports-v2/http.md:19-25 — the spec’s own 402 example serves a body of `{}`
  • client-codex402-fetch@1.2.0 dist/esm/index.mjs:22-23 — an error blob makes accepts undefined and .map throws
  • cdp-validatorcdp-validator-toolshed.json preflight[4] valid_json (required) — the body is parsed as JSON during indexing
V1_BODY_PRESENT warn payment a v1 envelope is published in the 402 body
  • specspecs/transports-v1/http.md § Payment Required Signaling
  • house-opiniononly fires when nothing was published in either transport; ENVELOPE_PRESENT carries the core error for that case
V1_BODY_JSON errorcore payment the 402 body parses as JSON
  • specspecs/x402-specification-v1.md § 5.1.1 JSON Payload
  • client-codex402-fetch@1.2.0 dist/esm/index.mjs:22 — response.json() with no try/catch
V1_VERSION errorcore payment the body declares x402Version 1
  • specspecs/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-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:388 — x402Versions = [1]
V1_ACCEPTS_NONEMPTY errorcore payment accepts[] is a non-empty array
  • specspecs/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-codex402-fetch@1.2.0 dist/esm/index.mjs:23 — accepts.map throws when accepts is absent
V1_SCHEME errorcore payment each accept names a scheme
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table)
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:438 — scheme: z.enum(schemes)
V1_SCHEME_KNOWN error payment the v1 scheme is exact — v1’s enum is closed where v2’s is open
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:387 — var schemes = ["exact"]
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:438 — scheme: z3.enum(schemes), applied per accepts entry
  • client-codex402-fetch@1.2.0 dist/esm/index.mjs:22-23 (response.json(), then PaymentRequirementsSchema.parse per entry)
V1_MAX_AMOUNT_REQUIRED errorcore payment the price is in maxAmountRequired, not the v2 amount
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table)
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:440 — maxAmountRequired is required; `amount` is not a v1 key
V1_AMOUNT_ATOMIC errorcore payment maxAmountRequired is a string of atomic units
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table)
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:433,440 — z3.string().refine(isInteger)
  • client-codex402-fetch@1.2.0 dist/esm/index.mjs:30 — BigInt(maxAmountRequired) throws on a non-digit string
V1_NETWORK_NAME errorcore payment network is a v1 plain name, not CAIP-2
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table)
  • client-codex402@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 error payment the v1 network name is one of the seventeen the dominant v1 client’s enum admits
  • client-codex402@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-codex402-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 errorcore payment resource is a flat, absolute URL string, not the v2 object
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table)
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:441 — resource: z3.string().url(), so a bare path is a hard ZodError
  • field-reportx402-foundation/x402#3045 wire-format bug 3, in its v1 spelling
V1_PAYTO errorcore payment payTo has the address shape its v1 network requires (EVM 0x, or base58 on solana)
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table)
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:435 — EvmOrSvmAddress = EvmAddressRegex.or(SvmAddressRegex)
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:16-34 — the enum includes solana and solana-devnet
V1_ASSET errorcore payment asset names the token in the form its v1 network requires
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table)
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:436,447 — asset: mixedAddressOrSvmAddress
  • client-codex402@1.2.0 dist/esm/chunk-EJI6X7BV.mjs:75 — verifyingContract: getAddress(asset), which throws on a ticker
V1_MIMETYPE error payment mimeType is present (spec: Optional — but the dominant v1 client’s schema requires it)
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) — mimeType Optional
  • client-codex402@1.2.0 dist/esm/chunk-V3RMM5AE.mjs:443 — mimeType: z3.string(), NOT .optional()
  • client-codex402-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 error payment description is present (missing is an error; present-but-empty is a warn)
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) — description Required
  • client-codex402@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 errorcore payment maxTimeoutSeconds is a positive integer JSON number
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) — maxTimeoutSeconds, type number, Required
  • client-codex402@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 error payment extra carries the EIP-712 domain the v1 client signs over (EVM networks only)
  • specspecs/schemes/exact/scheme_exact_evm.md:72-73 — extra.name and extra.version required for eip3009
  • client-codex402@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-opinionthe reference facilitator recomputes the domain from its own table, so the mismatch surfaces only as invalid_exact_evm_payload_signature
  • specspecs/x402-specification-v1.md:261 — v1 Solana exact uses TransferChecked, which has no EIP-712 domain
V1_OUTPUT_SCHEMA warn bazaar outputSchema is present for v1 discovery
  • specspecs/x402-specification-v1.md:110-124 § 5.1.2 (PaymentRequirements table) — outputSchema Optional
  • specspecs/extensions/bazaar.md:577+ § Backwards Compatibility — v1 discovery rode on outputSchema
  • field-reportx402-foundation/x402#2844 — indexing began after the metadata moved there
V1_DISCOVERABLE info bazaar outputSchema.input.discoverable is an opt-OUT — absence means indexed
  • client-codex402-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
  • liveworker/positive-control.js — a live indexed seller nests the flag under outputSchema.input
  • cdp-docshttps://docs.cdp.coinbase.com/x402/bazaar — v1 discovery data reads input.discoverable
Dual-stack consistency5 checks
Dual-stack consistency: 5 checks
codeseverityregimewhat it checks, and where the rule comes from
DUAL_PAYTO errorcore payment matched offers pay the same address
  • house-opinionworker/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 errorcore payment matched offers quote the same price
  • house-opinionworker/lint.js — one offer must not carry two prices; matched on (chain, asset) so different-decimal assets are not compared
DUAL_NETWORK errorcore payment the two envelopes offer overlapping chains
  • house-opinionworker/lint.js — a payment signed on one chain is worthless on the other
  • client-codex402@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 errorcore payment matched offers name the same asset
  • house-opinionworker/lint.js — different assets means the two versions are selling for different money
DUAL_RESOURCE warn payment both versions name the same resource URL
  • house-opinionworker/lint.js — two URLs split one endpoint’s settlement record across two listings
  • field-reportx402-foundation/x402#3045 — discovery keys on the resource URL
Version-detection hygiene2 checks
Version-detection hygiene: 2 checks
codeseverityregimewhat it checks, and where the rule comes from
VERSION_HEADER_SAYS_V1 error payment the PAYMENT-REQUIRED header does not carry a v1 payload
  • specspecs/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 warn payment the 402 body does not carry a v2 payload (a core error when no valid v2 header is published)
  • specspecs/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-codex402-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 bounds2 checks
The report’s own bounds: 2 checks
codeseverityregimewhat it checks, and where the rule comes from
ACCEPTS_TRUNCATED info hygiene at most 8 accepts[] entries are linted per envelope
  • house-opinionworker/lint.js MAX_ACCEPTS_LINTED = 8
FINDINGS_TRUNCATED info hygiene this report is complete — no bound clipped it
  • house-opinionworker/lint.js — MAX_FINDINGS = 200, MAX_ACCEPTS_LINTED = 8, and the caller's body byte cap

x402 discovery and migration FAQ

Why does my x402 endpoint pass validate but not get indexed?

Base envelope validation and discovery are different layers. Bazaar metadata can be missing or fail its own schema, discoverable can be in the wrong place, or the unauthenticated probe can receive something other than a 402. 10x402 checks those technical blockers, but it cannot confirm whether Bazaar has crawled or approved a URL.

Why is my x402 service not showing up in Bazaar?

Check the HTTP response and the discovery metadata together: extensions.bazaar, the info-to-schema match, the v1 discoverable flag, and the status returned to an unpaid probe. A conformant response removes common listing blockers; it does not guarantee a listing.

What should I check during an x402 v1 vs v2 migration?

Check the version-specific network spelling, price field, resource shape, header encoding, and EIP-712 extra fields. If both versions are published, also check that payTo, price, chain, asset, and resource agree.

What is on the x402 conformance checklist?

79 published checks: HTTP behavior, x402 v1 and v2 envelopes, dual-stack consistency, version hygiene, Bazaar discovery metadata, and two report safeguards that disclose truncation. Every finding includes a specific fix.

Why is my x402 endpoint not discoverable?

Discoverability depends on more than returning status 402. The response must publish readable payment terms and the discovery fields expected by the indexer. 10x402 can identify response-level blockers; it cannot measure demand or inspect the index itself.

Can I check just one thing instead of buying the whole report?

Yes. POST /lint/one and POST /lint/envelope/one answer about exactly one check id you name — for settling a single question like "is my v2 header base64url" without buying the catalogue. 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. A single-check answer distinguishes three outcomes: it passed, it failed with the fix attached, or it did not apply to this response at all — which is not a pass and is never reported as one.

Does 10x402 store my URL, envelope, or report?

No linted URL, pasted envelope, or report is persisted in the application store. It retains aggregate lint results plus the quota and payment records needed to operate the service. What you lint is your business.

Limits, stated plainly