Four onchain intelligence endpoints on Base, priced per call via the x402 protocol. No API keys, no accounts — request the endpoint, get an HTTP 402 with payment requirements, pay in USDC on Base mainnet, get your answer. Every route also has a free, rate-limited, no-payment /api/demo/* mirror with a smaller data window — that's what the homepage demo calls. Prefer a machine-readable schema? See the OpenAPI spec.
The same free, rate-limited demo from the homepage — no wallet needed.
Real USDC on Base: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
eip155:8453)A plain fetch/requests call gets you the 402 — an x402 client library handles signing the payment and retrying automatically. Client library APIs move fast; check coinbase/x402 for the current package names if these have drifted.
TypeScript
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";import { ExactEvmScheme } from "@x402/evm";import { privateKeyToAccount } from "viem/accounts";const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, { schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],});const res = await fetchWithPayment( "https://ulvane.xyz/api/token/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913/risk");const data = await res.json();Python
from eth_account import Accountfrom x402.clients.requests import x402_requestsaccount = Account.from_key("0xYOUR_PRIVATE_KEY")session = x402_requests(account)res = session.get( "https://ulvane.xyz/api/token/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913/risk")data = res.json()The wallet behind the private key needs a small amount of real USDC on Base mainnet — prices are cents-level ($0.01–$0.05 per call).
/api/token/{address}/risk$0.01Is this token a scam clone of a known name? Checks a hand-verified allowlist and flags symbol impersonation, and adds neutral facts read from the contract (ownership, upgradeable proxy, mint/pause/blacklist functions) and from published token lists.
Request
curl https://ulvane.xyz/api/token/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913/riskResponse
{ "address": "0x8335...02913", "symbol": "USDC", "name": "USD Coin", "status": "verified", "note": "This exact address has been manually vetted by Ulvane.", "impersonatedSymbol": null, "signals": [ { "id": "has_owner", "level": "caution", "text": "A privileged owner address exists (0x3ABd...). What it can do depends on the contract's code." }, { "id": "upgradeable_proxy", "level": "caution", "text": "Upgradeable proxy: the logic can be replaced by whoever controls the proxy admin." }, { "id": "listed", "level": "info", "text": "Listed on: Uniswap Labs Default, Superchain Token List, CoinGecko." } ], "onchain": { "isContract": true, "ownership": "owned", "upgradeable": true, "decimals": 6, "capabilities": { "mint": true, "pause": true, "blacklist": true } }, "listings": { "listedBy": ["Uniswap Labs Default", "Superchain Token List", "CoinGecko"], "lookalikes": [] }, "asOf": "2026-09-18T17:55:00.476Z", "signature": "0x22629f79...ee922761c", "signerAddress": "0xdCac2E5680797cd6d7483764A76278cE5f91ECe8"}/api/tokens/risk$0.05Token risk for up to 10 tokens in one call, at a flat price. A token that can't be read (e.g. an address with no contract code) fails on its own row without failing the call; if every token fails, nothing is charged.
Request
curl "https://ulvane.xyz/api/tokens/risk?addresses=0xTokenA,0xTokenB,0xTokenC"Response
{ "count": 3, "summary": { "verified": 1, "impersonator": 0, "unverified": 1, "withCautionSignals": 2, "errors": 1 }, "results": [ { "ok": true, "address": "0x...", "symbol": "USDC", "status": "verified", "signals": [], "onchain": {}, "listings": {} }, { "ok": true, "address": "0x...", "symbol": "PEPE", "status": "unverified", "signals": [{ "id": "lookalike_symbol", "level": "caution", "text": "..." }] }, { "ok": false, "address": "0x...", "error": "This address has no contract code on Base, so it is not a token." } ], "asOf": "2026-10-29T00:00:00Z", "signature": "0x22629f79...ee922761c", "signerAddress": "0xdCac2E5680797cd6d7483764A76278cE5f91ECe8"}/api/pnl/{wallet}$0.02A wallet's realized/unrealized PnL, computed with a running-average cost basis — not just current balance × price.
Request
curl https://ulvane.xyz/api/pnl/0xYourWalletAddressResponse
{ "wallet": "0x...", "realizedUsd": 1234.56, "unrealizedUsd": 342.10, "wins": 14, "losses": 6, "totalTrades": 20, "points": [{ "time": 1737000000, "realizedUsd": 0 }], "positions": [ { "tokenAddress": "0x...", "symbol": "TOKEN", "avgCostUsd": 0.012, "amountHeld": 50000, "unrealizedUsd": 60.0 } ], "windowNote": "Based on the most recent swaps...", "asOf": "2026-09-18T00:00:00Z", "signature": "0x22629f79...ee922761c", "signerAddress": "0xdCac2E5680797cd6d7483764A76278cE5f91ECe8"}/api/token/{address}/top-traders$0.03Who's actually trading this token, ranked by volume moved — not just top balances.
Request
curl https://ulvane.xyz/api/token/0xTokenAddress/top-tradersResponse
{ "tokenAddress": "0x...", "currentPriceUsd": 0.0123, "traders": [ { "trader": "0x...", "boughtUsd": 50000, "soldUsd": 42000, "totalPnlUsd": 3900, "tradeCount": 14 } ], "windowNote": "Based on the most recent swaps...", "asOf": "2026-09-18T00:00:00Z", "signature": "0x22629f79...ee922761c", "signerAddress": "0xdCac2E5680797cd6d7483764A76278cE5f91ECe8"}/api/wallet/{wallet}/risk$0.02Should an agent trust this counterparty? Flags a wallet if it's recently traded any token on Ulvane's impersonator list — the wallet-level counterpart to the token risk check.
Request
curl https://ulvane.xyz/api/wallet/0xYourWalletAddress/riskResponse
{ "wallet": "0x...", "tradesAnalyzed": 42, "distinctTokensTraded": 11, "flaggedTokens": [], "status": "clean", "note": "No flagged-token activity found in this wallet's recent trade window...", "windowNote": "Based on the most recent swaps...", "asOf": "2026-09-18T00:00:00Z", "signature": "0x22629f79...ee922761c", "signerAddress": "0xdCac2E5680797cd6d7483764A76278cE5f91ECe8"}/api/token/{address}/pre-trade-gate$0.05Token risk + top traders (+ an optional wallet risk check) combined into one clear/caution/avoid verdict. Cheaper than calling the three separately.
Request
curl "https://ulvane.xyz/api/token/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913/pre-trade-gate?wallet=0xYourAgentWallet"Response
{ "tokenAddress": "0x...", "tokenSymbol": "USDC", "tokenStatus": "verified", "tokenNote": "This exact address has been manually vetted by Ulvane.", "topTraders": [ { "trader": "0x...", "boughtUsd": 50000, "soldUsd": 42000, "totalPnlUsd": 3900, "tradeCount": 14 } ], "walletChecked": { "wallet": "0x...", "status": "clean", "note": "No flagged-token activity..." }, "verdict": "clear", "verdictNote": "The token is on Ulvane's verified allowlist...", "windowNote": "Top-trader and wallet-risk signals reflect a bounded recent-swap window...", "asOf": "2026-09-28T00:00:00Z", "signature": "0x22629f79...ee922761c", "signerAddress": "0xdCac2E5680797cd6d7483764A76278cE5f91ECe8"}Every paid response includes a signature and signerAddress. It's a standard EIP-191 signature over the exact JSON body (minus those two fields) — proof this data came from Ulvane at this exact time, checkable by anyone, without asking our server again.
import { verifyMessage } from "viem";const { signature, signerAddress, ...data } = response;const valid = await verifyMessage({ address: signerAddress, message: JSON.stringify(data), signature,});Try it
Ulvane ships an MCP server, so Claude Desktop, Cursor or any MCP client can call the endpoints as tools. The agent's own wallet pays each call over x402 — the key stays on your machine and is only used to sign payment authorizations. Use a dedicated wallet with a few dollars of USDC on Base. A per-call spend cap (ULVANE_MAX_PRICE_USD, default $0.05) is enforced against the amount the server actually asks for, and every paid result includes a _verification field reporting whether its signature checks out and came from Ulvane. The leaderboard and pricing tools are free and need no key.
// claude_desktop_config.json — no install step, runs via npx{ "mcpServers": { "ulvane": { "command": "npx", "args": ["-y", "ulvane-mcp"], "env": { "EVM_PRIVATE_KEY": "0x..." } } }}Tools: token_risk, wallet_pnl, wallet_risk, token_top_traders, pre_trade_gate, pricing, base_leaderboard. The package is ulvane-mcp on npm; source is on GitHub.
Building on Coinbase AgentKit? ulvane-agentkit adds the same actions as an AgentKit action provider, with the same spend cap (checked before anything is signed) and signature verification:
npm install ulvane-agentkit @coinbase/agentkitimport { ulvaneActionProvider } from "ulvane-agentkit";const agentKit = await AgentKit.from({ walletProvider, // EVM wallet on base-mainnet with a little USDC actionProviders: [ulvaneActionProvider()],});Note: a fresh install of @coinbase/agentkit 0.10.x can fail to load because of an upstream Solana dependency conflict (it reproduces without Ulvane). Installing graphql and adding "overrides": { "@solana/kit": "^8.0.0" } to your package.json fixes it.
Prices are also available as JSON at GET /api/pricing (free), so an agent can budget before it calls anything.
windowNote says exactly which sources it covered).windowNote).status: "unverified" on the risk endpoint means not on our hand-curated allowlist yet — not a signal that a token is unsafe.signals on a token-risk result are neutral facts, not a verdict: legitimate tokens are often upgradeable, owned or pausable (USDC is all three). Function checks look for selectors in the contract's bytecode, which shows a function exists, not who may call it. Token-list membership means a third party listed the token, not that we vetted it; a lookalike_symbol means a different address is listed under the same symbol on a curated list (Uniswap Labs Default, Superchain Token List).Build on