verdix-ai-sdk gives an AI SDK agent a tool,
checkAddressRisk, to screen an EVM address on Base before it sends funds there,
plus a cheaper checkAddressRiskLite ($0.01, never answers safe).
No API key: each check is paid via x402 in USDC from the agent's own wallet, under caps you set.
Current version: 0.3.0.
npm install verdix-ai-sdk ai viem
The agent's wallet needs a little USDC on Base mainnet. No ETH is needed: x402 payments are signatures, and the facilitator pays the gas. Payments are real USDC on Base mainnet; there is no testnet mode.
import { generateText, isStepCount } from 'ai';
import { privateKeyToAccount } from 'viem/accounts';
import { verdixTools } from 'verdix-ai-sdk';
const { text } = await generateText({
model: 'openai/gpt-5-mini',
tools: verdixTools({
account: privateKeyToAccount(process.env.AGENT_PRIVATE_KEY as `0x${string}`),
maxPricePerCallUsd: 0.1, // never pay more than $0.10 for one check
maxTotalSpendUsd: 1, // and at most $1 in total
}),
stopWhen: isStepCount(3),
prompt: 'Send 250 USDC on Base to 0x000000000000000000000000000000000000dEaD.',
});
The 'openai/gpt-5-mini' model string goes through the Vercel AI Gateway (set AI_GATEWAY_API_KEY); any AI SDK provider model works too.
The model calls checkAddressRisk({ address, tier? }) and gets back, for example:
{
"verdict": "danger",
"riskScore": 90,
"reasons": ["burn_address"],
"checked": ["ofac", "scam_lists", "poisoning_watch", "onchain_age",
"contract_code", "burn_list", "provenance"],
"advice": "Do not send funds to this address. Show the reasons to the user.",
"tier": "quick",
"priceUsd": 0.02,
"complete": true,
"charged": true,
"payment": { "transaction": "0x29d6…6fa4", "network": "eip155:8453" }
}
Without a model, use the client directly:
import { createVerdixClient } from 'verdix-ai-sdk';
const verdix = createVerdixClient({ account, maxPricePerCallUsd: 0.1 });
const result = await verdix.checkAddress({ address: '0x…', tier: 'quick' });
if (result.verdict !== 'safe') {
// stop, or ask the user
}
safecheckAddressRiskLite({ address }) (since 0.3.0) is the cheapest screen. It calls /risk/address/lite: OFAC sanctions, scam and phishing lists, address-poisoning lookalikes, burn addresses, phishing tokens and flagged deployers. It skips address age and the caution-only contract checks.
Its verdict is no_known_risk, caution or danger, never safe. no_known_risk only means the address is on none of those lists; it is not a safety verdict. When you need safe (say, before a large transfer), use checkAddressRisk with the quick tier ($0.02).
It is not part of verdixTools; add it yourself, with one client so both tools share one budget:
import { checkAddressRisk, checkAddressRiskLite, createVerdixClient } from 'verdix-ai-sdk';
const options = { account, maxPricePerCallUsd: 0.1, maxTotalSpendUsd: 1 };
const verdix = createVerdixClient(options);
const tools = {
checkAddressRisk: checkAddressRisk(options, verdix),
checkAddressRiskLite: checkAddressRiskLite(options, verdix),
};
The same lite tool is check_address_risk_lite in
verdix-mcp 0.3.0 and
langchain-verdix 0.2.0.
If your agent has its own send or transfer tool, use verdixNeedsApproval (since 0.2.0) as its
needsApproval.
Before the tool runs, it checks the destination address. A safe answer runs the tool directly. A caution or danger answer pauses it for the user's approval.
import { tool } from 'ai';
import { z } from 'zod';
import { verdixNeedsApproval } from 'verdix-ai-sdk';
const sendUsdc = tool({
description: 'Send USDC on Base',
inputSchema: z.object({ to: z.string(), amount: z.number() }),
needsApproval: verdixNeedsApproval({ account, maxPricePerCallUsd: 0.02 }), // quick tier
execute: async ({ to, amount }) => send(to, amount),
});
to, recipient or address in the tool input, or the field you name with address.onResult(result, input) receives each answer, for example to show the reasons in your approval prompt.safe means| Verdict | Meaning | What the agent should do |
|---|---|---|
safe | None of the checks listed in checked found a risk signal. It is not a guarantee that the address is trustworthy. | Still confirm the full address and amount with the user. |
caution | Risk signals were found, or a data source could not be reached (complete: false). | Show the reasons; send only if the user explicitly confirms. |
danger | Strong risk signals: sanctioned, known scam, poisoning lookalike, burn address… | Do not send. |
The tool's description tells the model the same thing, and every result carries an advice string.
The model picks a tier by what is at stake, and can only pick tiers that fit under your maxPricePerCallUsd. Each tier has its own URL (/risk/address/{tier}) with a single price, so the tier asked for is exactly the tier paid for.
| Tier | Price | When |
|---|---|---|
quick | $0.02 | Small, routine transfers (under ~$100) to an address used before. |
standard (default) | $0.10 | ~$100–$1,000, or any address that came from a message, a transaction history or a copy-paste. Adds deeper on-chain behaviour analysis. |
deep | $0.50 | Over ~$1,000, first-time counterparties, contract interactions. Runs the same checks as standard today; new counterparty checks land here first. |
maxPricePerCallUsd (required): a check whose live price is above it is refused before anything is signed. For example, standard with a $0.05 cap throws Refusing to pay: the standard tier costs $0.10, above the $0.05 per-call cap.maxTotalSpendUsd (optional): a total budget for the tool. Each payment is reserved before signing, so parallel tool calls cannot overspend, and released when the API reports no charge.caution with complete: false, never safe.verdixTools({
account, // required: a viem account (or any x402 ClientEvmSigner)
maxPricePerCallUsd, // required
maxTotalSpendUsd, // optional
allowedTiers, // optional, e.g. ['quick', 'standard']
defaultTier, // optional, default 'standard'
apiUrl, // optional, default https://api.verdixapi.com
fetch, // optional custom fetch
});
verdix-guard needs no model or tool.
It screens the recipient of every payment before it is signed and blocks danger.
It works as an onBeforePaymentCreation hook on the official x402 client, and as a wrapper around a viem account that covers transfers, approvals and EIP-3009 signatures.
npm install verdix-guard @x402/fetch @x402/evm viem
const guard = createVerdixGuard({ account }); // account = privateKeyToAccount(key)
guardX402Client(client, guard); // x402: your x402Client
const guardedAccount = guardAccount(account, guard); // viem: use it in your walletClient
lite tier ($0.01): danger is blocked, and no_known_risk is let through.caution is blocked by default. Set onCaution to 'allow' or 'ask' to change that.minAmountUsd), and spending is capped at $1 a day (dailyBudgetUsd).failMode (default block) applies when Verdix is unreachable or gives no complete answer.Source and full options on GitHub →
The private key only signs the x402 payment locally and is never sent anywhere. For the raw HTTP API see the OpenAPI spec; for MCP clients see verdix-mcp. Results are automated checks, not financial or legal advice — see Terms.