vike
API EndpointsOn-chain

On-chain REST

Endpoints for EVM wallets, tokens, transfers, labels and PnL — the one namespace where every REST route runs the same code as its MCP tool.

/v1/onchain/ answers questions about EVM addresses and ERC-20 tokens: what a wallet holds, who it trades with, where its money went, who is accumulating a token, and which labelled institution sits behind an address. 15 endpoints, all on https://data.vike.io, all behind the API key and the shared hourly budget.

The chain is a filter, not a namespace — ?chain=ethereum|bsc|base on most routes, because the data behind this namespace is multi-chain by design.

One route accepts chain and then ignores it

POST /labels/batch is Ethereum-only whatever you send.

Every call carries the credential in a header — X-API-Key: vk_... or Authorization: Bearer vk_oat_..., either alone is enough (Authentication) — and spends one unit of the shared hourly counter (Rate limits):

cURL
# the 20 counterparties this wallet moved the most USD with over the past 7 days
curl -H "X-API-Key: $VIKE_API_KEY" \
  "https://data.vike.io/v1/onchain/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/counterparties?window=7d&limit=20"

Each endpoint has its own page, carrying its full request line in a fence at the top; the page titles are written as the path, without the method.

Start here

TaskEndpoint
Size up an address before spending calls on it: volume, inflow, outflow and activity across five windows/wallets/{address}
See who a wallet deals with most over the past week or month/wallets/{address}/counterparties
Follow an exchange wallet's money outward, hop by hop/wallets/{address}/trace
Check whether two wallets are related by the counterparties and tokens they share/wallets/compare
Read what a wallet holds right now, priced where a price exists/wallets/{address}/balances
Rank the most active wallets, or the biggest net buyers, of the week/wallets/discover
Find the tokens with the biggest net inflow over 24h, or only among smart money/tokens/screener
See who is selling or buying a token in the last hour or day/tokens/{token_address}/transfers
Label a CSV of up to 100 addresses in one call/labels/batch
Find out which source says an address is an exchange/labels/{address}/provenance

What it looks like in use

A first session
# find: the wallets with the biggest net inflow over 7 days
curl -s "https://data.vike.io/v1/onchain/wallets/discover?window=7d&sort=net_flow&order=desc&size=5" \
  -H "X-API-Key: $VIKE_API_KEY"

# size one up: WALLET is an address from that board; five windows of activity in one call
curl -s "https://data.vike.io/v1/onchain/wallets/$WALLET" \
  -H "X-API-Key: $VIKE_API_KEY"

# who it deals with: its ten biggest counterparties over 30 days
curl -s "https://data.vike.io/v1/onchain/wallets/$WALLET/counterparties?window=30d&limit=10" \
  -H "X-API-Key: $VIKE_API_KEY"

# where the money went from there: two hops, five counterparties per hop
curl -s "https://data.vike.io/v1/onchain/wallets/$WALLET/trace?depth=2&width=5&window=30d" \
  -H "X-API-Key: $VIKE_API_KEY"

# who those counterparties are: CPS is their addresses joined with commas
curl -s -X POST "https://data.vike.io/v1/onchain/labels/batch?addresses=$CPS" \
  -H "X-API-Key: $VIKE_API_KEY"

Full MCP parity — the REST and MCP answers cannot drift

Every endpoint on this namespace maps one-to-one onto one of the tools the MCP server at vike.io/mcp advertises, and each pair is answered by the same query — there is no second implementation to drift.

So a REST call and the matching MCP tool call return the same payload. What they do not share is the HTTP contract on top: parameter names, defaults, ceilings and billing differ, and the three sections below are about exactly those differences.

Conventions on this namespace

Omitting a parameter is not the same as passing zero

A numeric parameter sent as 0 — or as an empty string — is treated exactly like one you did not send at all: the endpoint falls back to its own default, and that default is not always zero.

ParameterPassing 0, or omitting it, resolves to
min_usd on /trace10,000 USD
min_usd on /balances (omitting only; an explicit 0 is honoured)1.0 USD
min_usd on /transactions0 (no floor)
days on /pnl and /transactions30
depth / width on /trace2 / 5

You cannot ask /trace for a floor of exactly zero

On /trace, min_usd=0 selects the default floor instead of removing it. Pass a small positive number (min_usd=0.01) if you want everything.

Two ceilings, and the lower one is silent

The limit a route accepts and the limit it applies are two different numbers. The request validator enforces the higher one; the query underneath then quietly caps at the lower one. Nothing rejects an over-cap value and nothing reports the cap — a request for 1,000 rows returns 50 and looks exactly like a wallet with only 50 counterparties.

EndpointParameterHTTP acceptsActually applied
/wallets/comparelimit≤ 1000 (route default 100)≤ 50
/wallets/{address}/transactionslimit≤ 1000 (route default 100)≤ 500
/wallets/{address}/counterpartieslimit≤ 1000 (route default 100)≤ 50
/wallets/{address}/pnldaysany integer1–365
/wallets/{address}/tracedepth / widthany integer1–5 / 1–10
/tokens/screenerlimit≤ 500 (route default 50)≤ 100
/tokens/{token_address}/holderslimit≤ 500 (route default 50)≤ 50

REST and MCP produce different default row counts from the same query

A REST route always applies its own limit default, even when you send none, so /wallets/{address}/counterparties defaults to 100 and caps at 50 rows, while the wallet_counterparties MCP tool defaults to 10. Same data, different page size. Set limit explicitly if you care.

Credits are counted differently from MCP

Every on-chain REST call logs one credit, whatever it cost to serve — no route on this namespace charges more. Over MCP the same work is priced by tool instead, from 0 (token_search) to 4 (wallet_trace, the heaviest graph traversal). The hourly request budget is separate again and charges one unit per request on every surface, this namespace included.

Errors

Status codes and the error envelope are namespace-wide and documented under Errors. The mapping: a rejected input becomes 400 carrying the reason, and any other failure becomes 503.

A rejected batch on POST /labels/batch — more than 100 addresses, or none — is a 400 like any other rejected input. A malformed address on /balances and /ens is a 400 too, with a message reading Bad EVM address: …; the check there is strict: a 0x prefix and exactly 42 characters.

An unrecognised chain name is a 400 (chain 'x' not supported (use ethereum, bsc, or base)) on /wallets/{address}/counterparties, /pnl, /transactions, /trace, /wallets/compare, /tokens/screener, /tokens/{token_address}/holders and /labels/batch. The one exception is /tokens/{token_address}/transfers, which maps an unknown chain to ethereum and answers 200.

A batch of malformed addresses is a 200 with an empty array

POST /labels/batch skips an address that is not valid hex, so a batch in which every address is malformed answers 200 with []. Check the length of the array as well as the status.

Wallets

Nine endpoints. /wallets/compare and /wallets/discover are literal paths rather than addresses — they take no {address} segment.

EndpointWhat it answers
GET /wallets/{address}Aggregate metrics for one wallet across the 24h / 7d / 30d / 90d / all windows in a single response
GET /wallets/{address}/transactionsThe raw transfer list for a wallet: individual transfers, not aggregates
GET /wallets/{address}/counterpartiesThe addresses this wallet transacted with most, by combined transfer volume over a window
GET /wallets/{address}/pnlA daily net-flow series for the wallet — net inflow USD, cumulative, gross volume, transaction count
GET /wallets/{address}/balancesCurrent ERC-20 balances across the major EVM chains, with a USD value and price per holding
GET /wallets/{address}/traceFollow the money outward — top counterparties per hop, up to depth hops
GET /wallets/{address}/ensReverse ENS lookup — turn an address into vitalik.eth
GET /wallets/compareAre these two wallets related? Shared counterparties and shared tokens within a window
GET /wallets/discoverThe leaderboard: most active wallets over a window, ranked by the metric you pick

Tokens

EndpointWhat it answers
GET /tokens/searchResolve a symbol or name to the tokens we know about
GET /tokens/screenerFind tokens by activity within a window — volume, net inflow, holder count or smart-money inflow
GET /tokens/{token_address}/transfersWho bought and who sold a token over a period — the top buyers or the top sellers
GET /tokens/{token_address}/holdersThe holder leaderboard for a token, ranked by cumulative net inflow USD

Labels

EndpointWhat it answers
POST /labels/batchEnrich a list of addresses in one call — entity, wallet type, risk flag and 30-day activity
GET /labels/{address}/provenanceThe full label cascade for one address, with per-source attribution

On this page