x402

IDCheck NameSpec ReferenceWhat It ChecksPass Criteria
X402-01402 Response Statusx402 spec, HTTP semanticsAn unpaid request must be answered with status code 402Response status is exactly 402, not 401/403/other
X402-02Payment Header Presentx402 built-on-stellar guideThe 402 response must include a payment headerEither PAYMENT-REQUIRED or X-Payment header is present (both are checked — the spec itself is not yet consistent, see note in README)
X402-03Header Payload Decodablex402 spec §payment-required-objectThe header value must be valid base64 that decodes to JSONatob() + JSON.parse() succeed without error
X402-04Required Fields Presentx402 spec §payment-required-objectThe payload must include the core payment terms, under the field names its own advertised version requiresnetwork and payTo are present and non-empty, and the price field matches the advertised x402Version: maxAmountRequired for v1, amount for v2 (renamed in v2, which also drops the embedded resource object). The version is read from the challenge rather than accepting whichever name happens to appear, because a service advertising x402Version: 2 while emitting the v1 field name is not conformant to the version it claims — and reporting that as a merely absent price would hide the actual defect. An unrecognised version fails: the field names cannot be checked against a version whose schema is unknown.
X402-05Network Identifier Validx402 built-on-stellar guideNetwork id format follows CAIP-2Matches the pattern stellar:testnet or stellar:pubnet
X402-06Signature Resubmit Acceptedx402 spec §payment-flowA resubmitted request carrying a valid signature must be acceptedResponse is no longer 402; a 2xx returns the original resource. The challenge is re-read immediately before signing, so the payment answers a challenge the target issued just now rather than a stale one. Settles a real payment — see the cost note below.
X402-07Invalid Signature Rejected (negative)x402 spec §payment-flowA deliberately corrupted signature must be REJECTEDThe target answers with any status other than 200. Rejection is established only by an answer: a target that cannot be reached, or whose challenge cannot be read, produces no verdict and is reported as ERROR or SKIP. Treating a thrown error as proof of rejection would let an unreachable host pass a security check. The payload is corrupted after signing, so it is well-formed in every respect except the signature it carries, and only signature verification can explain a rejection.

Note on the x402 payment checks' cost (Week 2). X402-06 and X402-07 are not free. X402-06 settles a real payment against the target, and X402-07 attempts one with a corrupted signature; both move or risk moving testnet funds from the payer key, and repeated runs spend repeatedly. Like MPP-01 this is inherent rather than an implementation choice — a payment flow that was never exercised cannot be verified. X402-01 through X402-05 read the challenge only and cost nothing; --read-only (CLI) or readOnly: true (MCP) restricts a run to those. The payment checks are also skipped entirely when no payer key is present, so the default posture is the cheap one.

Note on cascading failures (Week 2). The read-only checks inspect progressively deeper parts of one challenge: the status, then the header, then its payload, then the fields inside it. When one fails, the checks after it have nothing left to inspect, and they are skipped rather than failed. A target answering 404 produces one finding, not five. The same applies across the payment checks: when X402-06 cannot exercise the payment flow at all, X402-07 is skipped rather than credited with a rejection it never observed.