402xAgent
402xAgent es la verificación que un agente realiza antes de pagar cualquier endpoint x402. Sondea el 402 del endpoint sin pagar y devuelve un veredicto de pagar / omitir / reverificar con una razón. Cada verificación deja un recibo público. Nunca paga al objetivo.
Servidor MCP alojado
npx add-mcp 'https://api.402xagent.com/mcp'Se instala en Claude Code, Codex, Cursor y más
Documentación
x402-spotcheck: verifica antes de pagar
Un guardián para clientes y routers x402. Justo antes de que tu cliente firme, evalúa el 402 que el vendedor envió: ¿son términos USDC razonables en Base, y coinciden con tu listado (precio, destinatario de pago, red)? Un skip bloquea el pago, con un código de razón. Cualquier otra cosa, incluyendo desconocido, un tiempo de espera agotado o un error, deja pasar el pago.
- Local por defecto (1.0.0). Evalúa el 402 que tu cliente ya recibió con spotcheck-rules (MIT, incluido como
x402-spotcheck/rules). No hace llamadas de red, no necesita servicio y no tiene dependencias. - Desconocido significa pagar. Un
skipbloquea solo con un código de razón de rules.json:price_mismatch,pay_to_mismatch,network_mismatch,asset_not_usdc,bad_challenge(local), másnetwork_unsupported,ssrf_blocked,ambiguous(servicio). Un destinatario sin puntuación o historial nunca es rechazado. - Sin seguimiento. Por defecto no envía id de cliente, ni ref, ni cabeceras. El modo local no envía nada en absoluto.
- Solo Base por defecto. Los requisitos en otras cadenas pasan sin cambios. Solana es opcional con
solana: true. - El servicio 402xAgent es opcional (
mode: "service"). Su tiempo de espera es un límite estricto (timeoutMs, por defecto 1500 ms) y falla abierto por defecto.onUnavailable: "block"se respeta exactamente, en un tiempo de espera agotado y en cualquier error. - Nunca ve tus claves.
npm i github:withgrokbot/x402-spotcheck#v1.0.0
En una línea
@x402/fetch:
const pay = wrapFetchWithPayment(spotCheckFetch(fetch, { expected: (url) => myListing.get(url) }), client);
Hook de cliente x402 (onBeforePaymentCreation, x402-foundation/x402 @x402/core 2.x; registra tu límite de gasto primero):
client.onBeforePaymentCreation(mySpendingCap).onBeforePaymentCreation(spotCheckBeforePaymentHook({ expected: (url) => myListing.get(url) }));
three.ws mcp-bridge (buildSpendingCapHook en mcp-bridge/src/x402-axios-client.js; el límite se ejecuta primero):
client.onBeforePaymentCreation(threeWsSpendingCapThenSpotCheck(buildSpendingCapHook));
@x402/axios: wrapAxiosWithPayment(spotCheckAxios(axios.create(), opts), client).
expected(url, intent) devuelve tu listado { price, payTo, network } o nada. Sin un listado, comprueba los términos en sí mismos: un importe legible, una dirección de destinatario de pago válida y USDC canónico.
Promesa de semver
El comportamiento del veredicto (qué se paga, qué se omite y por qué) cambia solo en una versión mayor. Las versiones menores y de parche pueden añadir opciones (desactivadas por defecto), corregir fallos o mejorar la documentación. Nunca convierten un pay en un skip. Fija exactamente:
npm i github:withgrokbot/x402-spotcheck#v1.0.0 # package.json: "x402-spotcheck": "github:withgrokbot/x402-spotcheck#v1.0.0"
npm i github:withgrokbot/spotcheck-rules#v1.0.0 # the rules alone
Migración desde 0.x
Las instalaciones 0.x fijadas a una etiqueta no se ven afectadas. Para mantener el comportamiento 0.5, fija github:withgrokbot/x402-spotcheck#v0.5.0. Para obtenerlo en 1.0.0:
spotCheckFetch(fetch, { mode: "service", ref: "via-x402-spotcheck", onRecheck: "block", solana: true, timeoutMs: 15000 });
Lo que cambió en 1.0.0: el modo local es el predeterminado (0.x siempre llamaba a 402xAgent); recheck, un skip sin un código conocido, y un desajuste de hash de términos de nivel gratuito que las reglas locales no pueden nombrar ahora se pagan; no se envía ref por defecto; los requisitos que no son Base pasan a menos que solana: true; el tiempo de espera del servicio es de 1,5 s y un límite estricto (era 15 s); y una comprobación fallida se recuerda durante 10 s, para que el reintento firmado no espere una segunda vez (unavailableTtlMs). Los términos de nivel de pago todavía se aplican, con códigos de razón.
Kit de pruebas (vitest y node:test)
Cualquier integración que llame a una comprobación previa al pago puede demostrar cuatro cosas: con la opción desactivada no hace llamadas; un tiempo de espera agotado deja pasar el pago; una respuesta {} lo deja pasar; una omisión bloquea.
import { test } from "node:test"; // or: import { it as test } from "vitest";
import { spotcheckContract } from "x402-spotcheck/testkit";
spotcheckContract(test, ({ enabled, fetch, timeoutMs }) => (enabled ? myHook({ fetch, timeoutMs }) : undefined));
build devuelve un hook x402 onBeforePaymentCreation y debe usar el fetch que se le da.
Todo lo siguiente describe el modo servicio opcional (mode: "service"), donde 402xAgent sondea el objetivo en sí mismo.
Un caso real de /v1/skips
Nuestro rastreo semanal autoverificado de listas x402 públicas (CDP Bazaar, PayAI Bazaar, awesome-x402) publica cada listado cuyo 402 en vivo no coincide con el listado en /v1/skips. El recibo b5e13e8271 es uno de estos:
| listado (CDP Bazaar) | 402 en vivo (rastreo del 2026-10-07 21:27 UTC) | |
|---|---|---|
| url | https://topagentx402.vercel.app/api/send-token | mismo |
| precio | $0.001 | $0.001 |
| red | eip155:84532 (Base Sepolia, dinero de prueba) | eip155:8453 (Base mainnet, USDC real) |
| pay_to | 0xb1f6…Ec74 | 0xb1f6…Ec74 |
Un router que eligiera este endpoint del listado pensaría que está pagando tokens de testnet. Un cliente x402 configurado con eip155:* firmaría USDC real de mainnet. Con el guardián, 402xAgent compara el 402 en vivo contra el listado y responde:
{ "verdict": "skip", "reason": "network_mismatch", "expected_network": "eip155:84532", "network": "eip155:8453", "expected_source": "listing" }
Así que pay(...) lanza SpotCheckBlockedError y nada se firma en la red. (En el nivel gratuito la razón viene en palabras simples: "listed $0.001, asks for a different network than expected, details locked".)
Qué se comprueba
402xAgent sondea el objetivo una vez (seguro contra SSRF, GET, o POST para solicitudes POST) y nunca le paga. El veredicto:
pay: el 402 se analiza, pide el USDC canónico en una mainnet compatible, y su precio, red y destinatario de pago coinciden con lo esperado.skip: sin muro de pago (sin términos 402 en absoluto), un precio, red o destinatario de pago que difiere del listado, una testnet o red no compatible, un token distinto del USDC canónico, o un 402 ilegible.recheck: solo casos transitorios (tiempo de espera agotado, error de red, 5xx) yfree_trial_active(el objetivo envía cabecerasx-free-trial). Bloqueado por defecto (onRecheck).
402xAgent reutiliza una sonda por URL durante 5 minutos, así que dos comprobaciones seguidas coinciden.
"Esperado" significa tu propio listado cuando pasas expected, de lo contrario el listado de nuestro rastreo (500 endpoints, actualizado semanalmente) cuando tenemos la URL:
spotCheckFetch(fetch, {
mode: "service",
expected: (url, intent) => myCatalog.get(url), // { price: 0.01, payTo: "0x…", network: "eip155:8453" }
});
Paso de pago: firma solo el pago aprobado
Desde 0.2.0 un veredicto pay viene con el pago exacto que 402xAgent aprobó. Se toma del 402 en vivo del objetivo y se comprueba contra el listado:
"payment": { "scheme": "exact", "network": "eip155:8453", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "asset_is_usdc": true, "amount_atomic": "1000", "amount_usd": 0.001, "pay_to": "0xf567Cfe0FDb87A1D6Ca330e3f30f0D3DA0F7cb98" }
Esa es la respuesta en vivo para https://api.402rates.com/v1/ping. El nivel gratuito obtiene payment_terms_sha256 en lugar de los términos: un sha256 de network|asset|amount_atomic|pay_to, con la red en minúsculas, el activo EVM y pay_to en minúsculas, y el mint y pay_to de Solana tal cual (base58 distingue mayúsculas; desde 0.5.0, coincidiendo con el Worker).
El guardián aplica esos términos antes de que tu cliente x402 pueda firmar nada:
skipsignifica sin firma y sin gasto. El 402 nunca llega al cliente; se lanzaSpotCheckBlockedError.- El 402 se reduce a los requisitos que encajan. Red, activo y
pay_todeben ser idénticos, y el importe debe ser igual o inferior al aprobado; en el nivel gratuito el hash de términos debe coincidir. Si nada encaja, lanzarefused to sign: pay_to differs (402 0x…, approved 0x…), onetwork differs,asset differs,amount above approved. - Una última comprobación antes de enviar. Si un
PAYMENT-SIGNATUREfirmado todavía no encaja, lanzarefused to send: ….
try {
await pay(url);
} catch (e) {
if (e instanceof SpotCheckBlockedError) console.log(e.reason, e.receiptUrl); // show as the abort reason
}
Cada comprobación en vivo deja un recibo público gratuito con la URL del listado, los términos del 402 en vivo, veredicto, razón y hora, p. ej. sc-96e5586bcffcfab8. El recibo más reciente para cualquier URL está en /v1/receipts/by-url?url=<endpoint>. El mensaje de error termina con — receipt: <url>.
Los agentes que firman pagos ellos mismos pueden llamar a assertApprovedPayment(await checkBeforePay(url), requirement) primero.
Coste
Obtienes 1 comprobación gratuita por cliente por día UTC. Después, una comprobación cuesta una décima parte del precio citado del objetivo, mínimo $0.01, tope $0.25, en USDC en Base vía x402. Pasa payFetch para pagar las comprobaciones con tu propio cliente x402, limitado por maxCheckUsd (por defecto $0.05):
const pay = wrapFetchWithPayment(spotCheckFetch(fetch, { mode: "service", payFetch: wrapFetchWithPayment(fetch, client) }), client);
Si no pasas payFetch y la comprobación gratuita se agota, el guardián cuenta 402xAgent como no disponible. Eso falla abierto por defecto (onUnavailable: "allow"), así que una interrupción o un presupuesto faltante nunca detiene tus pagos.
Primer router: 1,000 comprobaciones gratuitas. Damos al primer router o framework de agentes que integre un id de cliente 1,000 comprobaciones completas (detalle de nivel de pago, sin pago). Abre un issue en este repositorio para pedir una.
Routers: pide un id de cliente de router y las comprobaciones cuestan $0.001 cada una. Se facturan como un pago x402 de $0.01 por paquete de 10 comprobaciones, y las otras 9 están prepagadas en ese id. Se necesita un nivel de router porque el facilitador cobra alrededor de $0.002 por liquidación, así que un pago de $0.001 por comprobación no lo cubriría.
Verifica un resultado de Bazaar antes de pagar (comprobación de pago)
402xagent.com/bazaar muestra una comprobación gratuita diaria de los mejores resultados de CDP Bazaar. Eso es una instantánea. Antes de que tu agente pague uno, ejecuta su propia comprobación contra lo que Bazaar lista, luego vuelve a obtener el 402 en vivo y firma solo si todavía encaja. Con payFetch, la comprobación es el nivel de pago (términos aprobados completos; mismo precio que arriba, limitado por maxCheckUsd):
import { checkBeforePay, assertApprovedPayment } from "x402-spotcheck";
// 1. Pick a Bazaar result (public discovery API, no key needed)
const q = new URLSearchParams({ query: "weather forecast", limit: "20" });
const { resources } = await (await fetch("https://api.cdp.coinbase.com/platform/v2/x402/discovery/search?" + q)).json();
const r = resources[0];
const listed = r.accepts.find((a) => a.network === "eip155:8453") || r.accepts[0];
const method = r.extensions?.bazaar?.info?.input?.method || "GET";
// 2. Check it against the listing (paid: payFetch pays the check, up to maxCheckUsd)
const decision = await checkBeforePay(r.resource, {
mode: "service",
method,
price: Number(listed.amount) / 1e6, // USDC has 6 decimals
payTo: listed.payTo,
network: listed.network,
payFetch: wrapFetchWithPayment(fetch, client),
maxCheckUsd: 0.05,
});
if (!decision.allowed) throw new Error(`skip: ${decision.reason}`); // no signature, no spend
// 3. Re-fetch the live 402 right before paying and sign only a requirement that matches the approved terms
const live = await fetch(r.resource, { method });
if (live.status !== 402) throw new Error(`no live 402 (HTTP ${live.status}); recheck later`);
const pr = live.headers.get("payment-required"); // x402 v2 header, else v1 body
const { accepts } = pr ? JSON.parse(atob(pr)) : await live.json();
const requirement = accepts.find((a) => a.network === decision.approved?.payment?.network) || accepts[0];
await assertApprovedPayment(decision, requirement); // throws "refused to sign: ..." if terms changed since the check
// ...now pay with your x402 client
Opciones
| opción | predeterminado | |
|---|---|---|
mode | "local" | "service" pregunta a 402xAgent (opt-in) |
expected(url, intent) | ninguno | tu listado { price, payTo, network } |
solana | false | juzga también Solana mainnet; de lo contrario, lo que no es Base pasa |
tolerance | 0.01 | tolerancia de precio local |
onDecision(d) | ninguno | registra o mide cada decisión (los errores en ello se ignoran) |
timeoutMs | 1500 | servicio: límite estricto para una comprobación |
onUnavailable | "allow" | servicio: "block" para fallar cerrado en tiempo de espera agotado o error |
onRecheck | "allow" | servicio: "block" para rechazar en re-comprobación |
client, ref | no enviados | servicio: atribución opt-in |
payFetch, maxCheckUsd | ninguno, 0.05 | servicio: paga el propio precio de 402xAgent |
autoPayCheck | desactivado | servicio: auto-pago limitado de la tarifa de comprobación (abajo) |
cacheTtlMs | 300000 | servicio: caché de veredictos |
endpoint | https://api.402xagent.com/v1/products/endpoint-spot-check | servicio: URL de comprobación; los hosts anteriores aún funcionan (LEGACY_ENDPOINT) |
Errores: SpotCheckBlockedError tiene decision (veredicto, razón, términos aprobados), reason, y receiptUrl (el recibo público para esa comprobación, cuando el Worker devuelve uno).
Agentes y MCP
Servidor MCP remoto (gratuito, Streamable HTTP): https://api.402xagent.com/mcp, herramienta endpoint_spot_check. Añádelo a tu cliente MCP, luego pon una línea en las instrucciones del agente:
Antes de pagar cualquier endpoint x402, llama a
endpoint_spot_checkcon suurl(másclaimed_price,pay_to,networkdel listado si los tienes). Paga solo siverdictespay.
Función simple, para cualquier herramienta de framework de agentes:
import { checkBeforePay } from "x402-spotcheck";
const d = await checkBeforePay(url, { accepts, price: 0.01, network: "eip155:8453" }); // local; add mode: "service" to ask 402xAgent
if (!d.allowed) return `not paying: ${d.verdict} (${d.reason})`;
Hay más ejemplos en examples/: Python, una configuración MCP y una herramienta estilo LangChain.
Pruebas
npm test ejecuta pruebas unitarias sin red: el contrato 1.0.0 (predeterminado local, tiempo de espera agotado, desconocido = pagar, sin seguimiento, solo Base, hooks con un cliente @x402/core real, el kit de pruebas), incluidos los casos del paso de pago: coincidencia, un pay_to/red/activo diferente, un importe superior al aprobado, un 402 mixto reducido a un requisito, un hash de nivel gratuito y omisión. npm i && npm run test:integration ejecuta el @x402/fetch, @x402/axios y @x402/evm reales (2.28) contra un vendedor simulado, firmando localmente con una clave desechable. Cuenta cada payload que el cliente crea, para demostrar que un pago rechazado u omitido nunca se firma. (Los paquetes v1 x402-fetch y x402-axios actualmente fallan al instalarse desde npm porque su dependencia x402@^1.2.1 no se puede encontrar, así que están cubiertos solo por la ruta X-PAYMENT de las pruebas unitarias.) La prueba de integración comprueba que una cabecera de pago bloqueada nunca sale del proceso.
MIT. Hecho por @withgrokbot. El servicio 402xAgent y el rastreo viven en withgrokbot/verified-catalog.
Auto-pago de la comprobación (opt-in, modo servicio)
Cuando la comprobación gratuita se agota, autoPayCheck paga la tarifa de 402xAgent con el mismo cliente x402, antes de pagar al vendedor:
const pay = wrapFetchWithPayment(spotCheckFetch(fetch, {
mode: "service",
autoPayCheck: { wrapFetch: (f) => wrapFetchWithPayment(f, client), maxPerCheck: 0.05, dailyCap: 1 },
}), client);
Solo paga cuando se cumplen todas estas condiciones: la tarifa es como máximo maxPerCheck; la tarifa más el gasto de hoy (UTC, por instancia) es como máximo dailyCap; la tarifa es como máximo el 25% del precio del objetivo (maxFraction puede establecer un límite más bajo, no uno más alto); la tarifa es exactamente 1/10 del precio USDC del objetivo ($0.01 a $0.25); y el 402 solicita x402 v2 exact USDC en Base a la dirección pay_to documentada de 402xAgent. La tarifa siempre se paga en Base, incluso para objetivos de Solana, por lo que el cliente necesita un firmante EVM registrado. Tu envoltorio de fetch puede firmar solo ese pago, una vez. Para compartir el total diario entre reinicios, pasa spendStore: { get(day), add(day, atomic) }. Si alguna regla falla o algo da error, la verificación cuenta como no disponible, igual que sin ella. Con autoPayCheck configurado, payFetch no se usa para la tarifa. Sin autoPayCheck, nada cambia.