402xAgent checks an x402 endpoint right before your agent pays: pay, skip or recheck.
POST https://api.402xagent.com/mcp (JSON-RPC, tools listed by tools/list)Quick start: GET https://api.402xagent.com/v1/products/endpoint-spot-check?url=<endpoint>&mode=dry-run
New receipts (/v1/receipts/<id>) carry kid and signature: ed25519 (base64url, 64 bytes) over the RFC 8785 (JCS) canonical JSON of the receipt with only signature removed. Public keys: /.well-known/402xagent-keys.json (match kid). Older receipts are unsigned. A signature proves 402xAgent issued the receipt; it does not change the verdict.
Offline, with x402-spotcheck 1.1.0+: await verifyReceipt(receipt, { publicKey }). Or with Node 20+ and no dependencies:
import { createPublicKey, verify } from "node:crypto";
const jcs = (v) => v === null || typeof v !== "object" ? JSON.stringify(v)
: Array.isArray(v) ? "[" + v.map(jcs).join(",") + "]"
: "{" + Object.keys(v).filter((k) => v[k] !== undefined).sort().map((k) => JSON.stringify(k) + ":" + jcs(v[k])).join(",") + "}";
const receipt = await (await fetch("https://402xagent.com/v1/receipts/sc-...")).json();
const { keys } = await (await fetch("https://api.402xagent.com/.well-known/402xagent-keys.json")).json(); // or a saved copy
const jwk = keys.find((k) => k.kid === receipt.kid);
const { signature, ...signed } = receipt;
const ok = verify(null, Buffer.from(jcs(signed)), createPublicKey({ key: { kty: "OKP", crv: "Ed25519", x: jwk.x }, format: "jwk" }), Buffer.from(signature, "base64url"));
console.log(ok ? "valid" : "INVALID");