Skip to content
API AccessScanner API reference

Token scans

Detect an address type, scan a token's holders or traders for bundles, compare several tokens, and read cached token scans, on Solana and Robinhood Chain.

A token scan looks at a token's holders (or, on Solana, its early traders), groups wallets that were funded together or bought together into bundles, and follows proxy wallets and profit collectors. It is the same scan as the token scan in the dashboard.

13 routes: 7 under /contracts for Solana and 6 under /rh/contracts for Robinhood Chain. Every path below is served under https://api.scanner.net, and every request carries the key header, so those two are not repeated per route. Shared errors, limits and streaming are in Requests and errors.

A token scan costs 1 scan. A cached result is free, and so is joining a scan of the same token that is already running. A scan that fails is refunded. The detect, history, cached and rebuild routes are free.

Solana token detect

GET /contracts/{address}/detect

Says whether an address is a token, a program or a wallet. Free. For several addresses or either chain, use /detect.

ParameterInTypeRequiredNotes
addresspathstringyesSolana address.
curl "https://api.scanner.net/contracts/MINT_ADDRESS/detect" \
  -H "x-api-key: $SCANNER_API_KEY"

Response: { isToken, isContract, isWallet } booleans, plus chain, family, address, exists, and owner, executable and balance when known. An address that can't be detected, including an invalid one, returns all three flags false.

StatusCodeWhen
502SCAN_FAILEDThe lookup failed upstream.

Solana token scan

POST /contracts/{mint}/scan

Scans a Solana token's holders and returns the result when it finishes. No body.

ParameterInTypeRequiredNotes
mintpathstringyesToken mint address.
forcequerystringnotrue skips the cache and scans again. Read from the query string only.
curl -X POST "https://api.scanner.net/contracts/MINT_ADDRESS/scan" \
  -H "x-api-key: $SCANNER_API_KEY"

Response: a ContractScanResult, with no wrapper. Key fields:

  • mint and tokenProfile: the token and its metadata.
  • holders: the holders scanned, with their bundle and funding flags.
  • bundleGroups and totalBundles: groups of wallets that act together.
  • transferLinks, fundingSources, profitCollectors: how the holders are connected.
  • proxyChains and staggeredScoring, when found.
  • bundleSnapshotId: pass it to Rebuild bundles.
  • scanComplete: false when the result is partial.

Cost: a cached scan less than an hour old is returned free. Otherwise 1 scan.

StatusCodeWhen
400INVALID_MINTNot a valid Solana address.
402INSUFFICIENT_CREDITSNot enough scans left.
503INTERNAL_ERRORToken data is temporarily unavailable. The scan is refunded.
504TIMEOUTThe scan ran out of time. The scan is refunded.

Solana token scan stream

GET /contracts/{mint}/scan/stream

A Solana token scan as server-sent events. Unlike the JSON route, it can scan traders as well as holders.

ParameterInTypeRequiredNotes
mintpathstringyesToken mint address.
modequerystringnoholders (default) or traders.
forcequerystringnotrue skips the cache and scans again.
curl -N "https://api.scanner.net/contracts/MINT_ADDRESS/scan/stream?mode=traders" \
  -H "x-api-key: $SCANNER_API_KEY"

Events: on a cache hit, cache_hit (scannedAt, isStale, history) and then complete. On a live scan, status, token_metadata, holders, entry_analysis, transfer_analysis, funding_analysis, staggered_analysis, proxy_detection, bundle_detection, bundle_groups, proxy_chains, staggered_scoring, heartbeat every 15 seconds, then complete with the ContractScanResult. A failure sends error with code TIMEOUT or INTERNAL_ERROR.

Cost: any cached scan is returned free, even one over an hour old (isStale: true). Pass force=true for a new scan at 1 scan. A failed scan is refunded, unless the connection was closed after results had already arrived.

StatusCodeWhen
400INVALID_MINTNot a valid Solana address.
402INSUFFICIENT_CREDITSNot enough scans left.

Solana token scan history

GET /contracts/{mint}/scan/history

Up to 3 recent cached scans of a token. Free.

ParameterInTypeRequiredNotes
mintpathstringyesToken mint address.
modequerystringnoholders (default) or traders.
curl "https://api.scanner.net/contracts/MINT_ADDRESS/scan/history?mode=holders" \
  -H "x-api-key: $SCANNER_API_KEY"

Response: { "history": [{ "id", "scannedAt", "isStale" }] }. Pass an id to Cached token scan. An empty list means there is nothing cached, or the lookup failed; this route doesn't return errors.

Solana cached token scan

GET /contracts/scan/cache/{id}

One cached token scan by its history id. Free.

ParameterInTypeRequiredNotes
idpathstringyesAn id from scan history.
curl "https://api.scanner.net/contracts/scan/cache/CACHE_ID" \
  -H "x-api-key: $SCANNER_API_KEY"

Response: { scanResult, scannedAt, isStale }, where scanResult is a ContractScanResult.

StatusWhen
404No cached scan with this id. The body is { "error": "Cached scan not found" }, without a code.

Solana rebuild bundles

POST /contracts/{mint}/bundles/rebuild

Regroups the bundles of an earlier scan with some wallets hidden, for example a known exchange or a wallet you've already cleared. Free. It doesn't rescan.

ParameterInTypeRequiredNotes
mintpathstringyesToken mint address.
modebodystringyesholders or traders, matching the scan.
snapshotIdbodystringyesbundleSnapshotId from the scan result.
hiddenbodystring[]yesSolana addresses to leave out, at most 100. Can be empty.
curl -X POST "https://api.scanner.net/contracts/MINT_ADDRESS/bundles/rebuild" \
  -H "x-api-key: $SCANNER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode":"holders","snapshotId":"SNAPSHOT_ID","hidden":["WALLET_ADDRESS"]}'

Response: { "scanResult": { ... } }, the ContractScanResult with bundles regrouped.

StatusCodeWhen
400INVALID_MINTNot a valid Solana address.
400INVALID_INPUTBad mode, snapshotId or hidden, or the snapshot belongs to another token or mode.
410BUNDLE_SNAPSHOT_MISSINGThe snapshot has expired. Run the scan again.
503BUNDLE_REBUILD_UNAVAILABLERebuilding is briefly unavailable.

Multi-token scan

POST /contracts/multi/scan/stream

Scans 2 to 5 Solana tokens, holders and traders for each, and compares them: wallets they share, bundles that repeat, shared funding sources and profit collectors, and transfers between them. Answers with server-sent events.

ParameterInTypeRequiredNotes
mintsbodystring[]yes2 to 5 different token mint addresses.
forcebodybooleannotrue scans every token again instead of using cached results.
curl -N -X POST "https://api.scanner.net/contracts/multi/scan/stream" \
  -H "x-api-key: $SCANNER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mints":["MINT_ADDRESS_1","MINT_ADDRESS_2"]}'

Events: preflight, multi_start (mints, creditsRequired), then per token target_start, mode_start, mode_cache_hit or mode_progress, mode_complete and target_complete, then cross_analysis. complete holds a MultiContractScanResult: mints, targets, commonWallets, repeatedBundles, sharedFundingSources, sharedProfitCollectors, crossTransfers and a summary with creditsRequired, creditsCharged and a verdict (high, medium, low or none).

Cost: 1 scan for each token that has no cached result, charged after the stream opens. Any failure refunds the whole charge.

StatusCodeWhen
400INVALID_INPUTFewer than 2 or more than 5 tokens.
400INVALID_MINTAn address isn't valid.

After the stream opens, problems arrive as an error event: INVALID_MINT when an address isn't a token, INSUFFICIENT_CREDITS (with credits and required) when there aren't enough scans, and INTERNAL_ERROR. A lack of scans is reported this way, not as an HTTP 402.

Robinhood Chain token detect

GET /rh/contracts/{address}/detect

Says whether a Robinhood Chain address is a token, a contract or a wallet. Free.

ParameterInTypeRequiredNotes
addresspathstringyes0x address.
curl "https://api.scanner.net/rh/contracts/0xTOKEN_ADDRESS/detect" \
  -H "x-api-key: $SCANNER_API_KEY"

Response: { isToken, isContract, isWallet }, plus contractName and supply when known.

StatusCodeWhen
400INVALID_INPUTNot a 0x address.
502SCAN_FAILEDThe lookup failed upstream.

Robinhood Chain token scan

POST /rh/contracts/{address}/scan

Scans a Robinhood Chain token's holders and returns the result when it finishes.

ParameterInTypeRequiredNotes
addresspathstringyesToken 0x address.
forcequery or bodybooleannotrue (query force=true or body {"force":true}) skips the cache.
curl -X POST "https://api.scanner.net/rh/contracts/0xTOKEN_ADDRESS/scan" \
  -H "x-api-key: $SCANNER_API_KEY"

Response: a RobinhoodContractScanResult, with no wrapper. Key fields: address, tokenProfile, holders, bundleGroups, totalBundles, transferLinks, fundingSources, profitCollectors, scanComplete, and degraded when some data was missing.

Cost: a cached scan is returned free unless force is true. Otherwise 1 scan.

StatusCodeWhen
400INVALID_MINTNot a 0x address.
402INSUFFICIENT_CREDITSNot enough scans left.
503INTERNAL_ERRORToken data is temporarily unavailable. The scan is refunded.
504TIMEOUTThe scan ran out of time. The scan is refunded.

Robinhood Chain token scan stream

GET /rh/contracts/{address}/scan/stream

A Robinhood Chain token scan as server-sent events. Holders only.

ParameterInTypeRequiredNotes
addresspathstringyesToken 0x address.
forcequerystringnotrue skips the cache.
reusequerystringnotrue also replays a cached result that was degraded or made by an older version of the scan.
curl -N "https://api.scanner.net/rh/contracts/0xTOKEN_ADDRESS/scan/stream" \
  -H "x-api-key: $SCANNER_API_KEY"

Events: the same pattern as the Solana stream: cache_hit then complete for a cached result, otherwise progress events, heartbeat, and complete with the RobinhoodContractScanResult.

Cost: a complete cached scan is free, even when stale. Otherwise 1 scan, refunded on failure.

StatusCodeWhen
400INVALID_MINTNot a 0x address.
402INSUFFICIENT_CREDITSNot enough scans left.

Robinhood Chain token scan history

GET /rh/contracts/{address}/scan/history

Recent cached holder scans of a token. Free. The response has the same shape as the Solana history, and an empty list on any problem.

curl "https://api.scanner.net/rh/contracts/0xTOKEN_ADDRESS/scan/history" \
  -H "x-api-key: $SCANNER_API_KEY"

Robinhood Chain cached token scan

GET /rh/contracts/scan/cache/{id}

One cached Robinhood Chain token scan by its history id. Free. Returns { scanResult, scannedAt, isStale }, or 404 without a code when there is no such scan.

curl "https://api.scanner.net/rh/contracts/scan/cache/CACHE_ID" \
  -H "x-api-key: $SCANNER_API_KEY"

Robinhood Chain multi-token scan

POST /rh/contracts/multi/scan/stream

Compares 2 to 5 Robinhood Chain tokens, like the Solana multi-token scan. Answers with server-sent events.

ParameterInTypeRequiredNotes
addressesbodystring[]yes2 to 5 token 0x addresses. The field is addresses, not mints.
forcebodybooleannotrue scans every token again.
curl -N -X POST "https://api.scanner.net/rh/contracts/multi/scan/stream" \
  -H "x-api-key: $SCANNER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"addresses":["0xTOKEN_1","0xTOKEN_2"]}'

Events: multi_start, then per token target_start, target_cache_hit or target_progress, and target_complete, then cross_analysis, heartbeat, and complete with addresses, targets and a summary.

Cost: 1 scan for each token without a cached result, charged before the stream opens and refunded in full on failure.

StatusCodeWhen
400INVALID_INPUTFewer than 2 or more than 5 addresses.
400INVALID_MINTAn address isn't valid.
402INSUFFICIENT_CREDITSNot enough scans left. Unlike Solana, this is an HTTP 402.

View this page as Markdown