← Ulvane

API reference

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.

Try it

The same free, rate-limited demo from the homepage — no wallet needed.

Real USDC on Base: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913

Payment

Making a paid request

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.03 per call).

Endpoints

GET/api/token/{address}/risk$0.01

Is this token a scam clone of a known name? Checks against a hand-verified allowlist and flags symbol impersonation.

Request

curl https://ulvane.xyz/api/token/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913/risk

Response

{  "address": "0x8335...02913",  "symbol": "USDC",  "name": "USD Coin",  "status": "verified",  "note": "This exact address has been manually vetted by Ulvane.",  "impersonatedSymbol": null,  "asOf": "2026-09-18T17:55:00.476Z",  "signature": "0x22629f79...ee922761c",  "signerAddress": "0xdCac2E5680797cd6d7483764A76278cE5f91ECe8"}
GET/api/pnl/{wallet}$0.02

A wallet's realized/unrealized PnL, computed with a running-average cost basis — not just current balance × price.

Request

curl https://ulvane.xyz/api/pnl/0xYourWalletAddress

Response

{  "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"}
GET/api/token/{address}/top-traders$0.03

Who's actually trading this token, ranked by volume moved — not just top balances.

Request

curl https://ulvane.xyz/api/token/0xTokenAddress/top-traders

Response

{  "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"}
GET/api/wallet/{wallet}/risk$0.02

Should 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/risk

Response

{  "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"}

Verifiable responses

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

This is the sample response above (signed with a throwaway demo key, not Ulvane's real one) so you can see it work immediately. Paste a real response from any paid endpoint to verify it for real — everything runs in your browser, nothing is sent to Ulvane.

Use from an AI agent (MCP)

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 built in. The leaderboard tool is free and needs 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, base_leaderboard. The package is ulvane-mcp on npm; source is on GitHub.

Notes

Build on