Screen a wallet against OFAC (free, anonymous)
POST /v1/trust-check/ofac returns an allow or
block verdict for any wallet address, screened against the
U.S. Treasury OFAC SDN list. Anonymous, free, rate-limited at 1 r/s +
burst 3, refreshed daily from the Treasury XML feed.
Live status: see
/health
for current version, list refresh timestamp, and recent error count.
Why this vs alternatives
- vs Chainalysis Sanctions Oracle: HTTP + JSON instead of an on-chain contract call. No RPC dependency, no chain-specific deploys, works from any backend or non-EVM context. Sub-second response latency.
-
vs rolling your own from the Treasury XML feed: save
the parse-refresh-cache infrastructure. The underlying source is public
at
treasury.gov/ofac/downloads/sdn.xmlif you ever want to migrate off this endpoint. -
vs paid-tier API services (~$200-500/mo): free at this
scope. Pay only when you need token-contract risk via
/v1/trust-check($0.001/call x402).
cURL
curl -X POST https://swap.paladinfi.com/v1/trust-check/ofac \
-H "content-type: application/json" \
-d '{"address":"0x0000000000000000000000000000000000000000"}'
Allow response (full live shape):
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 8453,
"trust": {
"recommendation": "allow",
"factors": [
{"source":"ofac","signal":"not_listed","weight":0,"details":"","real":true}
],
"version": "1.1",
"_real": true,
"_scope": "ofac-only (wallet-address screen; use /v1/trust-check for full composition: GoPlus + Etherscan + anomaly heuristics)",
"_ofac_list_updated_at": "2026-05-27T04:07:49Z",
"_ofac_sdn_count": 93
},
"_paid_endpoint_info": {
"url": "https://swap.paladinfi.com/v1/trust-check",
"method": "POST",
"auth": "x402 (USDC EIP-3009 transferWithAuthorization on Base)",
"price_usdc": "0.001",
"plugins": {
"elizaos": "https://www.npmjs.com/package/@paladinfi/eliza-plugin-trust",
"agentkit": "https://www.npmjs.com/package/@paladinfi/agentkit-actions"
},
"docs": "https://paladinfi.com/trust-check/"
}
}
Block response (sanctioned wallet — abbreviated):
{
"trust": {
"recommendation": "block",
"factors": [
{"source":"ofac","signal":"listed","weight":100,"details":"OFAC SDN listed","real":true}
],
"version": "1.1",
"_real": true
}
}
Branch on trust.recommendation — "allow" or
"block". The _real: true field is your
machine-verifiable signal that this is live screening (not a fixture).
The chainId: 8453 field is informational only — OFAC SDN
entries are EOA addresses screened identically across chains.
Drop-in React hook
import { useEffect, useState } from "react";
export function useOfacScreen(address?: `0x${string}`) {
const [verdict, setVerdict] = useState<"allow" | "block" | "idle" | "loading" | "error">(
address ? "loading" : "idle"
);
useEffect(() => {
if (!address) { setVerdict("idle"); return; }
setVerdict("loading");
const ctrl = new AbortController();
fetch("https://swap.paladinfi.com/v1/trust-check/ofac", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ address }),
signal: ctrl.signal,
})
.then(r => r.ok ? r.json() : Promise.reject(r.status))
.then(d => setVerdict(d.trust.recommendation === "block" ? "block" : "allow"))
.catch(() => { if (!ctrl.signal.aborted) setVerdict("error"); });
return () => ctrl.abort();
}, [address]);
return verdict;
}
Use in a wallet-gate (fail-closed default for compliance use):
const verdict = useOfacScreen(connectedAddress);
// Fail-closed: block on error or while loading. Required for compliance use.
if (verdict === "block" || verdict === "error" || verdict === "loading") {
return <SanctionsBlockedMessage />; // replace with your component
}
// Fail-open is appropriate only for non-compliance UX gates where false-blocks
// cost more than false-allows.
When you need more
For token-contract risk (proxy detection, holder concentration, mint
authority, transfer hooks, recently-deployed flag, multi-source
composition with fail-closed contract), use the paid
/v1/trust-check
endpoint:
- $0.001/call settled via x402 on Base
- Same response shape; richer factor list (OFAC + GoPlus + Etherscan + anomaly heuristics)
- Plugins below handle x402 settlement for you
Caching + rate limits
- 1 r/s + burst 3 per IP. Cache on your side or proxy through your backend.
- Treasury refreshes the SDN feed daily; PaladinFi refreshes ours approximately once per 24h.
- Low-stakes UX gates: 1-6h client cache is the safe default.
- High-stakes flows (transfers >$X, contract deploys, sensitive actions): re-screen per-action; don't rely on a long cache.
- Audit-grade compliance: query Treasury XML directly.
- Rate-limit response is HTTP 429. Treat as transient: retry with backoff, or surface to your backend proxy. The React hook above collapses 429 into the generic
"error"verdict; production code should branch onr.status === 429and retry rather than fail-close.
Scope of coverage
Scope is OFAC SDN cryptocurrency-tagged wallet addresses only (~93 entries as of 2026-05-27). Not the EU consolidated list, not UK OFSI, not UN sanctions, not token contracts, not entity names, not country-level sanctions. For broader coverage, layer additional providers.
This endpoint surfaces the signal. Your dApp decides policy.
Plugins + MCP
- If you're using ElizaOS:
npm i @paladinfi/eliza-plugin-trust - If you're using AgentKit:
npm i @paladinfi/agentkit-actions - If your client speaks MCP (Claude Code, Cursor, etc.):
claude mcp add --transport http --scope user paladin-swap https://swap.paladinfi.com/mcp(listing) - Full trust-check (paid, multi-source): paladinfi.com/trust-check/
Last Updated: 2026-05-27 · API version: 1.1 · Service version: 0.11.77