402xAgent · Pricing · Docs · Blog
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)Free check, no signup: GET https://api.402xagent.com/v1/products/endpoint-spot-check?url=<endpoint>&mode=dry-run
Your paid call timed out, or came back 5xx or an empty 402. Did the money move? POST https://api.402xagent.com/v1/products/payment-status with JSON {"payment_payload":"<base64 PAYMENT-SIGNATURE you sent>","seller_url":"<url you paid>"} (or tx_hash, or from + nonce + valid_before). Base USDC (EIP-3009 exact) only for now.
wait_until).receipt (same keys as below). Same price as the check, $0.02, and the same 5 free per day. A bare request returns the x402 402. In x402-spotcheck 1.2.0: afterPay() or spotCheckFetch(fetch, { afterPay: true }).A real case from our own client. Facts only; times are Pacific (UTC-7).
1000, USDC on Base) to payTo 0xf567…cb98, maxTimeoutSeconds 300. The client signed and sent the paid retry.0x2b4cc694…13ee, from 0x37cf…8674, relayer 0xa32c…d101).tx_hash, from, nonce and seller_url (no payload needed when you have these).Answer: status landed (reason settled_onchain, 634 confirmations), amount and payTo match the seller's 402 terms, two RPC sources (Alchemy and Infura) agreed, safe_to_resign false. So: don't sign a new payment; the money moved, and the next step is to ask the seller for the response or a refund, using the tx as evidence. Signed receipt: https://402xagent.com/v1/receipts/ps-65a4fdffae01d2b6.
Add &check_expiry=1 to endpoint-spot-check (optional &skew_s= 0 to 300, default 30). If the check would say pay but every Base USDC option in the live 402 is already expired, or expires within skew_s (extra.validBefore, expiresAt, expiry or deadline; or maxTimeoutSeconds of 5 or less), the verdict is skip with reason challenge_expired, and the answer and receipt carry an expiry_check block. Without the parameter nothing changes. In x402-spotcheck 1.4.0: { checkExpiry: true }.
For routers and wallets that run checks for many agents. Opt in by asking us for a key, then send Authorization: Bearer 402x_live_<id>_<secret> (or x-402xagent-key) on the check or on payment status. Optionally add x-402xagent-end-user: <your opaque agent id>; we store only a salted hash of it.
x-402xagent-hosted: fallback: credit_limit).tier/access_tier hosted with a hosted block: integrator id, end-user hash, price_atomic, band (free_allowance, standard, volume), month and billed_on: invoice.GET /v1/integrators/me with the same key. A bad, suspended or revoked key gets 401 (never a silent free check); 120 checks per minute per key.spotCheckFetch(fetch, { mode: "service", apiKey }).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");