PAYMENT GUARD

Before your AI agent sends money, ask one question.

Agents are starting to move real funds over x402 endpoints and crypto rails. The obvious way that goes wrong is paying a sanctioned or scam address by mistake, and on-chain that is irreversible. Payment Guard is the one call an agent makes before a transfer.

FreeDeterministic — no LLMOFAC + scam lists + on-chain + ENSHTTP + MCP

Screen a recipient

verdict appears here…

Try a sanctioned/scam address and it returns block.

The tools

EndpointWhat it does
/api/screen-addressThe guard. Address or ENS name → OFAC-sanctioned? scam/abuse-listed? on-chain risk (brand-new/unused, contract)? → a verdict
/api/screen-paymentVet an x402/payment endpoint or merchant URL (punycode host, a known brand name outside the registrable domain, new domain, the final URL after redirects)
/api/check-sanctionedFast OFAC sanctions check for an address / ENS name. The response states its own coverage
/api/resolve-nameResolve an ENS name → address, then screen that address against the sanctions and scam lists. Catches names that do not resolve
/api/screen-tokenHoneypot / sell-tax / blocklist check on a token contract. The buy+sell simulation is api.honeypot.is, Ethereum and Base only

What the sanctions check covers

OFAC publishes sanctioned addresses by currency, not by chain. I ingest every upstream list that is in EVM (0x) format — ETH, ARB, BSC, ETC, USDC, USDT — and match against the union, so one result applies to every EVM chain.

Not checked: Bitcoin, Tron, Solana, Monero and the other non-EVM sanctioned addresses. This API only accepts EVM addresses, so it could never match them. A sanctioned: false means the address is absent from the EVM lists above and nothing more. Every response carries a coverage object that says this in machine-readable form.

If the list fails to load, you get verdict: "unknown" and a sanctions-check-unavailable flag. Never safe. An unanswered question is not a clean result.

An earlier version read only the ETH list. That missed 4 addresses OFAC publishes under ARB, BSC, USDC and USDT, and called them clear. The test suite now pins those four.

What the ENS check covers

lib/ens.js does one thing: namehash the name, call resolver(node) on the mainnet ENS registry, then call addr(bytes32) on that resolver. Whatever address comes back is screened against the sanctions and scam lists. That is the whole check.

It does not detect lookalike or homoglyph names. There is no confusable check and no ENSIP-15 normalization. A name with a Cyrillic character in it is just another name to me — I resolve it and screen whatever address it points to.

Mainnet registry and a direct addr() call only. No ENSIP-10 wildcard resolution, no CCIP-Read, so offchain and L2 names — Basenames, .cb.id, gasless subnames — come back as not resolving here even though a wallet resolves them. Read "did not resolve" as "not via the mainnet registry with a direct addr() call", not as "does not exist".

What the honeypot and URL checks cover

The buy+sell simulation is api.honeypot.is. It answers for Ethereum and Base, and returns 400 Invalid chain for Polygon, Arbitrum and Optimism, so the honeypot and taxes fields are not populated on those three. When no simulation ran the verdict is never safe: you get caution (or block, if the scam blocklist already hit), a honeypot-check-unavailable flag, and a honeypot_coverage object naming the chains it supports.

The URL lookalike rule matches 14 brand names as a substring of the host and flags them when the brand is not the registrable domain, so paypal.com.secure-pay.xyz is caught. There is no edit distance and no homoglyph mapping, so paypa1.com is not caught by that rule. On redirects I compare the final URL only, not each hop.

Use it from an agent (MCP)

{ "mcpServers": { "payment-guard": { "command": "npx", "args": ["-y", "payment-guard-mcp"] } } }

Why it exists

I wanted a "should I pay this?" check my agent could make as one free HTTP call in its own loop, before the transfer, so I wrote one. Sanctions screening exists for enterprises; this is the small version an agent can call on every recipient. Data is public and read-only: OFAC SDN, ethereum-lists + ScamSniffer, public RPC, ENS. Same input → same output.