vike
API EndpointsOn-chain

/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/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. 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.

cURL
# 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"
addressesqueryrequired
Comma-separated addresses. Capped at 100
chainqueryoptional
Accepted and ignored for the three valid names (ethereum | bsc | base): labels are always read from Ethereum, so chain=bsc returns Ethereum labels, not an error. Any other name is a 400

Note 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.

Example response
[
  {
    "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.

cURL
# enrich a list of addresses in one call (here two): entity, wallet type, risk flag and 30-day activity per rowcurl -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 listcurl -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 rowcurl -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 commascurl -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 callcurl -X POST -H "X-API-Key: $VIKE_API_KEY" \  "https://data.vike.io/v1/onchain/labels/batch?addresses=$BATCH_2"
Example response
[  {    "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  }]