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). An x402 v1 challenge in the response body fails this check, and X402-03–05 still inspect it; see the note on v1 below
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 requiresChecked in every payment option in accepts, each reported by its index when the challenge offers more than one; a challenge with no options fails. In each option, every field the advertised x402Version requires is present: for v2 scheme, network, amount, asset, payTo and maxTimeoutSeconds (spec 5.1.2); for v1 scheme, network, maxAmountRequired, asset, payTo, resource, description and maxTimeoutSeconds (v1 spec 5.1). Each is a non-empty string, except maxTimeoutSeconds, a positive number of seconds; a field present with the wrong type is reported as such rather than as missing. The price field follows the version: maxAmountRequired for v1, amount for v2 (renamed in v2, which also moves the resource out of the option). 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 v2 spec §11.1; CAIP-2Every advertised network id is CAIP-2Every option's network is a CAIP-2 identifier, namespace:reference with a 3 to 8 character lowercase namespace and a reference of at most 32 characters, as x402 v2 requires. Where the namespace's own CAIP-2 definition fixes the reference, that is checked too: stellar is testnet or pubnet; eip155 is the chain id in base 10 (eip155:84532, not eip155:0x14a34); solana is the first 32 characters of the base58 genesis hash. A well-formed id in another namespace passes, and the result says only the format was checked there: x402 v2 asks for CAIP-2 and nothing more, so failing it would report Wasit's own lack of rules as the target's defect. An option without a network is left to X402-04.
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. A 2xx alone does not pass. The settlement the response reports in its PAYMENT-RESPONSE header (x402 v2 HTTP transport) must name a Stellar transaction hash, and that transaction is then looked up on Stellar RPC and held to the advertised terms exactly as MPP-01 does: it must have succeeded and emitted exactly one transfer event, from this run's payer, to the advertised payTo, for the advertised amount of the advertised asset. A missing header, a reported failure, or a hash that does not match fails. A settlement_pending response, which the spec defines as broadcast but unconfirmed, is reconciled on chain rather than failed. Uses the same RPC wait as MPP-01. On Base Sepolia (eip155:84532) the reference is an EVM transaction hash, and the receipt's ERC-20 Transfer log is held to the same terms: the transaction succeeded and logged exactly one token transfer, from this run's payer, to payTo, for amount of asset (an ERC-721 transfer, which shares the event signature, is not counted). The receipt is awaited for 30 blocks before the transaction counts as missing; an RPC that stops advancing gives no verdict.
X402-07Invalid Signature Rejected (negative)x402 spec §payment-flow; exact scheme on StellarA payment whose authorization signature is wrong must be REJECTEDThe target answers with a non-2xx status. The payment is built exactly as for X402-06, then only the client's authorization signature is corrupted: in the exact scheme on Stellar the client signs a Soroban authorization entry rather than the envelope, and one byte of that entry's signature is flipped. The transaction still decodes and carries the same amount, payer and recipient, so a target can refuse it only by verifying the signature. Measured against the x402.org facilitator on 2026-09-30, the rejection is invalid_exact_stellar_payload_simulation_failed, reached at the Soroban simulation that checks authorization; the pre-0.6.0 corruption, which overwrote the base64 tail and broke XDR decoding, drew invalid_exact_stellar_payload_malformed instead, and a target that decoded the envelope without verifying the signature passed it. 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, and a payload with no authorization signature to corrupt reports ERROR (setup). On Base Sepolia the client signs an EIP-3009 transferWithAuthorization off-chain; the first byte of that signature is flipped and the authorization left intact, so the signer it recovers to is no longer the payer and only signature verification can refuse it. Measured against the x402.org facilitator on 2026-10-05: refused with 402.

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.

Note on x402 v1 challenges (0.5.0). x402 v1 signals payment in the 402 response body, as a PaymentRequirementsResponse with x402Version: 1 (transports-v1/http.md). v2 moved it into the PAYMENT-REQUIRED header (transports-v2/http.md), and the exact scheme on Stellar is defined for v2 only, with CAIP-2 network identifiers (scheme_exact_stellar.md: "❌ v1 - we don't plan to support v1 for now"). So a v1 challenge from a Stellar service fails X402-02, and the failure says a v1 challenge was found in the body. Its terms are still worth reading, so X402-03–05 inspect the body instead of being skipped: X402-04 applies the v1 field names, and X402-05 reports whether the network is a CAIP-2 identifier (v1 used plain names such as base-sepolia, and the failure says so). X402-06 and X402-07 are skipped: Wasit pays through the v2 exact scheme, so no payment is built or sent, and neither check has a verdict. The same holds for any challenge the payment client cannot read. Before 0.5.0 both reported FAIL in that case, contradicting the X402-07 row above, and a v1 challenge left X402-03–05 skipped.

Note on networks (0.7.0). X402-01–05 read the challenge only, so they apply to an x402 service on any chain. The payment checks pay through the exact scheme on the network the run names: stellar:testnet (the default), stellar:pubnet, or eip155:84532 (Base Sepolia, with the EIP-3009 method, where the facilitator pays the gas). When a challenge offers several options, the payment is built for the option on that network; a challenge with no such option, or only one in another scheme, gets X402-06 and X402-07 skipped with the networks it does offer, since nothing was paid and nothing refused. Asking for any other network, for pubnet without an RPC endpoint, or paying with a key for the wrong chain, stops the run before any payment, as no settlement could be verified.