← Verdix

Verdix for the AI SDK

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.

Install

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.

Example

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
}

Lite: $0.01, never safe

checkAddressRiskLite({ 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.

Ask the user only when Verdix finds a risk

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),
});

What safe means

VerdictMeaningWhat the agent should do
safeNone 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.
cautionRisk signals were found, or a data source could not be reached (complete: false).Show the reasons; send only if the user explicitly confirms.
dangerStrong 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.

Tiers

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.

TierPriceWhen
quick$0.02Small, 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.50Over ~$1,000, first-time counterparties, contract interactions. Runs the same checks as standard today; new counterparty checks land here first.

What each tier checks →

Price caps

Options

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
});

Any agent: verdix-guard

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

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.