@agentradar/x402-trust
v0.2.0
Published
Pre-pay trust gate for x402 agent payments. Score the payee with AgentRadar before settling an HTTP 402 — block or warn on scam/low-trust wallets. The 'Stripe Radar' for agent payments.
Maintainers
Readme
@agentradar/x402-trust
A pre-pay trust gate for x402 agent payments. Before your agent settles an HTTP 402, score the payee wallet with AgentRadar and block or warn when the recipient is a known scam or low-trust wallet.
Think of it as the "Stripe Radar" for agent payments — a fraud check at the one universal chokepoint every paying agent passes through.
- Library-agnostic. Works with any x402 client (
@x402/fetch,x402-axios, custom). It keys off the x402 protocol's402response (accepts[].payTo), not a specific client's internals. - Zero runtime dependencies. Uses the global
fetch(Node 20+). - Fail-open or fail-closed.
"block"mode throws on a bad payee;"warn"mode logs and proceeds.
Powered by AgentRadar's on-chain trust scoring (ERC-8004 reputation + static analysis + scam-DB). Verdicts:
TRUSTED · VERIFIED · CAUTION · RISKY · BLOCKED.
Install
npm install @agentradar/x402-trustQuick start — native x402 lifecycle hook (recommended, v0.2.0+)
x402 clients expose an official lifecycle-hooks API. createTrustHook plugs straight into x402Client.onBeforePaymentCreation, so the trust check runs on every transport (HTTP, MCP) right before the payment payload is created — and blocks via the protocol's own { abort, reason } mechanism:
import { x402Client } from "@x402/core";
import { createTrustHook } from "@agentradar/x402-trust";
const client = new x402Client();
client.onBeforePaymentCreation(
createTrustHook({
policy: { mode: "block", minScore: 40 }, // block scams + anything under 40/100
onDecision: (d) =>
console.log(`[x402-trust] ${d.result.address} → ${d.result.verdict} (${d.result.score})`),
}),
);Failure semantics: if the AgentRadar API is unreachable, "block" mode aborts the payment (fail-closed) and "warn" mode proceeds (fail-open).
Alternative — wrap your paying fetch
For clients that don't use @x402/core (or pre-v2 setups), the original fetch wrapper still works:
import { wrapFetchWithPayment } from "@x402/fetch";
import { wrapFetchWithTrust } from "@agentradar/x402-trust";
// 1. Your normal x402 paying fetch
const payFetch = wrapFetchWithPayment(fetch, walletClient);
// 2. Gate it: AgentRadar scores the payee before any USDC moves
const trustedFetch = wrapFetchWithTrust(payFetch, {
policy: { mode: "block", minScore: 40 }, // block scams + anything under 40/100
onDecision: (d) =>
console.log(`[x402-trust] ${d.result.address} → ${d.result.verdict} (${d.result.score})`),
});
// 3. Use it exactly like fetch. Blocked payees throw TrustBlockedError before payment.
const res = await trustedFetch("https://some-x402-service.example/api");Standalone checks
import { checkTrust, decide } from "@agentradar/x402-trust";
const result = await checkTrust("0xPayeeAddress");
// { address, score, verdict, riskFlags }
const decision = decide(result, { minScore: 50 });
if (!decision.allowed) throw new Error(decision.reason);Gate inside your own 402 handler (e.g. axios)
If you handle the 402 yourself, pass the response body to assertPayeesTrusted:
import { assertPayeesTrusted } from "@agentradar/x402-trust";
// `body` is the parsed 402 response ({ accepts: [{ payTo, ... }] })
await assertPayeesTrusted(body, { policy: { mode: "block" } }); // throws on a bad payee
// ...then run x402-axios' payment retryAPI
| Export | Description |
|---|---|
| createTrustHook(opts?) | v0.2.0 — Returns a native onBeforePaymentCreation lifecycle hook for x402Client (@x402/core). Scores the selected payee and aborts via { abort, reason } per policy. |
| wrapFetchWithTrust(payFetch, opts?) | Returns a fetch that probes for 402, scores each payee, enforces policy, then delegates to payFetch. |
| checkTrust(address, opts?) | Calls GET {baseUrl}/verify?target=…; returns { address, score, verdict, riskFlags }. Cached in-memory (TTL configurable). |
| decide(result, policy?) | Applies a TrustPolicy → { allowed, reason, result }. |
| assertPayeesTrusted(payload, opts?) | Extracts accepts[].payTo from a 402 body and enforces policy (throws in block mode). |
| extractPayTo(payload) | Pulls unique, lower-cased payee addresses from a 402 body. |
| createTrustGate(opts) | Factory binding one option set to all helpers. |
| TrustBlockedError | Thrown in block mode; carries .decision. |
TrustGateOptions
| Field | Default | Notes |
|---|---|---|
| baseUrl | https://api.vvpro.ai | AgentRadar API base. |
| apiKey | — | Sent as x-api-key (raises rate limits). |
| policy.mode | "block" | "block" throws on a bad payee; "warn" continues. |
| policy.blockVerdicts | ["BLOCKED"] | Verdicts that fail the gate. |
| policy.minScore | — | Block below this composite score (0–100). |
| cacheTtlMs | 60000 | In-memory cache for /verify. 0 disables. |
| fetchImpl | global fetch | Override for tests / older runtimes. |
| onDecision | — | Callback per payee decision (telemetry/logging). |
How it works
agent ──probe──▶ x402 service (no payment)
◀─402── { accepts:[{ payTo }] }
agent ──verify─▶ AgentRadar /verify (score each payTo)
◀────── { score, verdict }
block? ──yes──▶ throw TrustBlockedError (no funds move)
──no───▶ payFetch() settles the 402 normallyDevelop
npm install
npm test # vitest
npm run build # tsc → dist/MIT © AgentRadar
