/labels/batch
Enrich a list of addresses in one call: entity, wallet type, risk flag, 30-day net flow, 30-day volume and 30-day transaction count, one row per input address in input order.
POST https://data.vike.io/v1/onchain/labels/batchEnrich a list of addresses in one call: entity, wallet type, risk flag, 30-day net flow, 30-day volume and 30-day transaction count, one row per input address in input order. This is the route for a CSV of addresses rather than a single wallet.
The rows come back in input order as documented, and each echoes its own wallet — so you can
verify the alignment rather than trusting the ordering. The echoed address is lower-cased, while the
first address was sent checksummed; compare case-insensitively.
A row for an address the label table knows carries found: true; one it does not know comes back
with found: false, null labels and zeros, still in its input position. A rejected batch — more
than 100 addresses, or none — is an HTTP 400 with a detail message, not a set of rows (see the
warning below). A batch whose every address is malformed is the odd one out: it answers 200 with
an empty array [], so check the length as well as the status.
Two field notes, on risk_flag and wallet_type, are on Wallet labels.
# enrich a list of addresses in one call (here two): entity, wallet type, risk flag and 30-day activity per row
curl -X POST -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/labels/batch?addresses=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045,0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb"
# one address is the same call with a one-element list
curl -X POST -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/labels/batch?addresses=0x28C6c06298d514Db089934071355E5743bf21d60"
# an empty list is rejected with a 400 and {"detail": "addresses (list) is required"}; more than 100 addresses is a 400 too, reading "batch capped at 100 addresses"
curl -i -X POST -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/labels/batch?addresses="
# list the inputs that came back unlabelled: found is false for an address with no label row (or one that is not a valid address) and the row keeps its input position, so with both addresses here labelled this prints []
curl -s -X POST -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/labels/batch?addresses=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045,0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb" \
| jq '[.[] | select(.found == false) | .wallet]'
# screen a list for flagged addresses: risk_flag is the empty string on a clean row
curl -s -X POST -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/labels/batch?addresses=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045,0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb" \
| jq '[.[] | select((.risk_flag // "") != "") | {wallet, risk_flag}]'
# a list longer than 100 is split before sending: BATCH_1 is the first 100 addresses joined with commas
curl -X POST -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/labels/batch?addresses=$BATCH_1"
# and BATCH_2 the next 100, in a second call
curl -X POST -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/labels/batch?addresses=$BATCH_2"addressesqueryrequiredchainqueryoptionalethereum | bsc | base): labels are always read from Ethereum, so chain=bsc returns Ethereum labels, not an error. Any other name is a 400Note the -X POST and the absent -d — as described earlier, this route is a POST with no body,
so curl must be told the method explicitly. The complete response covers two addresses,
captured 2026-09-03.
[
{
"entity": "vitalik buterin",
"wallet_type": "dex",
"confidence": "medium",
"risk_flag": "",
"net_30d_usd": -70023.25164,
"volume_30d_usd": 70046.74836,
"tx_30d": 454,
"tokens_30d_count": 157,
"wallet": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
"found": true
},
{
"entity": "morpho",
"wallet_type": "defi",
"confidence": "medium",
"risk_flag": "",
"net_30d_usd": -357800362.784802,
"volume_30d_usd": 2359366854024.6597,
"tx_30d": 409814,
"tokens_30d_count": 235,
"wallet": "0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb",
"found": true
}
]chain does nothing on this route
For the three valid names the value is accepted and then never applied — labels and
features are always read from Ethereum. So chain=bsc and chain=base return Ethereum labels
rather than an error. A name outside ethereum, bsc and base is still rejected with a 400. The wallet_batch_labels MCP tool advertises the same three-value enum and
behaves identically. This is the one dead chain in the namespace: /wallets/{address}/counterparties,
/tokens/{token_address}/holders and /tokens/screener each genuinely honour it.
POST, but the addresses go in the query string
This is the only non-GET route in the /v1 REST surface — the published OpenAPI spec declares 61
GET operations and this one POST. Despite the method it takes no request body: addresses is a
comma-separated query parameter, and the spec declares no requestBody. A JSON body is ignored.
Because the addresses ride in the URL, a long batch makes a long URL. Split large batches across several calls rather than assuming the 100-address cap is reachable in one.
A rejected batch is a 400 with a detail message
Send more than 100 addresses and the response is an HTTP 400 whose detail reads
batch capped at 100 addresses. An empty addresses value is a 400 too, with
addresses (list) is required. Nothing is billed for a rejected batch. Branch on the status code
before reading rows.