# Detection, identities, holdings and wallet finder

Source: https://www.scanner.net/docs/api/reference/lookups

> Detect what an address is, look up names and labels in bulk, read wallet holdings and trades, and find full addresses from truncated ones.

Quick lookups that don't run a scan. Every route on this page is free.

9 routes. 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 and limits are in [Requests and errors](/docs/api/reference/conventions). Some routes here have a [per-IP limit](/docs/api/reference/conventions#per-ip-limits).

Detect address [#detect-address]

```http
GET /detect/{address}
```

Says what an address is, on Solana or Robinhood Chain. The chain is worked out from the address.

| Parameter  | In    | Type   | Required | Notes                                                                  |
| ---------- | ----- | ------ | -------- | ---------------------------------------------------------------------- |
| `address`  | path  | string | yes      | A Solana or `0x` address.                                              |
| `chain`    | query | string | no       | `solana` or `robinhood`, to force one chain.                           |
| `metadata` | query | string | no       | `true` adds `contractName` and `supply` for Robinhood Chain contracts. |

```bash
curl "https://api.scanner.net/detect/WALLET_ADDRESS" \
  -H "x-api-key: $SCANNER_API_KEY"
```

**Response:** the detection, with no wrapper: `chain`, `family` (`svm` or `evm`), `address`, `isToken`, `isContract`, `isWallet` and `exists`. Solana adds `owner` and `executable`. `balance` (smallest unit) appears when the answer wasn't cached.

| Status | Code          | When                                                                                     |
| ------ | ------------- | ---------------------------------------------------------------------------------------- |
| 404    | `NOT_FOUND`   | Not an address on any chain, nothing exists at it, or `chain` doesn't match the address. |
| 502    | `SCAN_FAILED` | The lookup failed upstream.                                                              |

Detect addresses in bulk [#detect-addresses-in-bulk]

```http
POST /detect
```

The same detection for up to 100 addresses.

| Parameter   | In   | Type      | Required | Notes                                                 |
| ----------- | ---- | --------- | -------- | ----------------------------------------------------- |
| `addresses` | body | string\[] | yes      | At most 100. Entries that aren't strings are dropped. |
| `chain`     | body | string    | no       | `solana` or `robinhood`.                              |
| `metadata`  | body | boolean   | no       | `true` adds `contractName` and `supply`.              |

```bash
curl -X POST "https://api.scanner.net/detect" \
  -H "x-api-key: $SCANNER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"addresses":["WALLET_ADDRESS","0xADDRESS"]}'
```

**Response:** `{ "detections": { "<address>": { ... } } }`, keyed by each address exactly as sent. Addresses that don't exist or couldn't be detected are left out.

| Status | Code            | When                        |
| ------ | --------------- | --------------------------- |
| 400    | `MISSING_FIELD` | `addresses` isn't an array. |
| 400    | `INVALID_INPUT` | More than 100 addresses.    |
| 502    | `SCAN_FAILED`   | The lookup failed upstream. |

Identities [#identities]

```http
POST /identities/batch
```

Names and labels for many addresses: KOL names and handles, and entity labels such as exchanges and protocols. Limited to 60 requests per minute per IP.

| Parameter   | In   | Type      | Required | Notes                                                                                                                                                   |
| ----------- | ---- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `addresses` | body | string\[] | yes      | Not empty. On Solana, invalid addresses and duplicates are dropped and the first 300 are used. On Robinhood Chain, at most 5, all valid `0x` addresses. |
| `chain`     | body | string    | no       | `sol` (default) or `rh`.                                                                                                                                |

```bash
curl -X POST "https://api.scanner.net/identities/batch" \
  -H "x-api-key: $SCANNER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"addresses":["WALLET_ADDRESS"],"chain":"sol"}'
```

**Response:** `{ "success": true, "identities": { "<address>": { "kol", "entity" } } }`.

* `kol`: `{ name, twitter_handle, profile_picture_url }`, Solana only.
* `entity`: `{ name, type, category, tags }`.
* On Solana, addresses with no name are left out. On Robinhood Chain every address is present, as `{}` when unnamed.

| Status | Code            | When                                                                                                  |
| ------ | --------------- | ----------------------------------------------------------------------------------------------------- |
| 400    | `INVALID_INPUT` | `addresses` is missing or empty, `chain` isn't `sol` or `rh`, or the Robinhood Chain list is invalid. |
| 429    | `RATE_LIMITED`  | The per-IP limit was reached. The body includes `retryAfterSeconds`.                                  |

Solana holdings [#solana-holdings]

```http
GET /holdings/{address}
```

A Solana wallet's SOL and token balances with USD values.

| Parameter | In   | Type   | Required | Notes           |
| --------- | ---- | ------ | -------- | --------------- |
| `address` | path | string | yes      | Solana address. |

```bash
curl "https://api.scanner.net/holdings/WALLET_ADDRESS" \
  -H "x-api-key: $SCANNER_API_KEY"
```

**Response:** `{ "success": true, "data": { ... } }`. `data` has `address`, `solBalance`, `solUsdPrice`, `solUsdValue`, `tokens`, `totalUsdValue`, `fetchedAt`, `truncated`, and `stale: true` when a slightly older copy was served because the live read timed out. Each token has `mint`, `symbol`, `name`, `logoUri`, `balance`, `decimals`, `usdPrice`, `usdValue` and `liquidityUsd`. Results are cached for 30 seconds.

| Status | Code              | When                             |
| ------ | ----------------- | -------------------------------- |
| 400    | `INVALID_ADDRESS` | Not a Solana address.            |
| 504    | `TIMEOUT`         | The holdings provider timed out. |

Solana liquid balance [#solana-liquid-balance]

```http
GET /holdings/{address}/liquid-balance
```

A Solana wallet's holdings, counting only tokens with enough liquidity to sell.

| Parameter         | In    | Type   | Required | Notes                                                              |
| ----------------- | ----- | ------ | -------- | ------------------------------------------------------------------ |
| `address`         | path  | string | yes      | Solana address.                                                    |
| `minLiquidityUsd` | query | number | no       | Smallest pool liquidity in USD for a token to count. Default 5000. |

```bash
curl "https://api.scanner.net/holdings/WALLET_ADDRESS/liquid-balance?minLiquidityUsd=10000" \
  -H "x-api-key: $SCANNER_API_KEY"
```

**Response:** the same shape as [Solana holdings](#solana-holdings), with `minLiquidityUsd` set. Cached for an hour per address and threshold.

| Status | Code              | When                             |
| ------ | ----------------- | -------------------------------- |
| 400    | `INVALID_ADDRESS` | Not a Solana address.            |
| 504    | `TIMEOUT`         | The holdings provider timed out. |

Solana wallet trades [#solana-wallet-trades]

```http
GET /holdings/{address}/trades
```

Profit and loss per token for a Solana wallet: up to 20 tokens, highest realized profit first.

| Parameter | In   | Type   | Required | Notes           |
| --------- | ---- | ------ | -------- | --------------- |
| `address` | path | string | yes      | Solana address. |

```bash
curl "https://api.scanner.net/holdings/WALLET_ADDRESS/trades" \
  -H "x-api-key: $SCANNER_API_KEY"
```

**Response:** `{ "success": true, "data": [...] }`. Each entry has `mint`, `symbol`, `name`, `realized`, `unrealized`, `totalInvested`, `totalSold`, `buyTransactions`, `sellTransactions`, `holding`, `currentValue` and `lastTradeTime`. Cached for 5 minutes.

| Status | Code              | When                           |
| ------ | ----------------- | ------------------------------ |
| 400    | `INVALID_ADDRESS` | Not a Solana address.          |
| 504    | `TIMEOUT`         | The trades provider timed out. |

EVM holdings [#evm-holdings]

```http
GET /holdings/evm/{address}
```

An EVM wallet's balances across chains, including Robinhood Chain. Limited to 20 requests per minute per IP.

| Parameter | In   | Type   | Required | Notes         |
| --------- | ---- | ------ | -------- | ------------- |
| `address` | path | string | yes      | `0x` address. |

```bash
curl "https://api.scanner.net/holdings/evm/0xADDRESS" \
  -H "x-api-key: $SCANNER_API_KEY"
```

**Response:** `{ "success": true, "data": { ... } }`. `data` has `address`, `totalUsd`, `complete` (`false` when a chain couldn't be read), `fetchedAt` and `chains`. Each chain has `chain` (a CAIP-2 id), `chainName`, `totalUsd`, `unpricedCount` and `tokens`. Each token has `tokenAddress` (`null` for the native coin), `symbol`, `name`, `decimals`, `amount` (a decimal string), `priceUsd` and `valueUsd`.

| Status | Code              | When                             |
| ------ | ----------------- | -------------------------------- |
| 400    | `INVALID_ADDRESS` | Not a `0x` address.              |
| 429    | `RATE_LIMITED`    | The per-IP limit was reached.    |
| 504    | `TIMEOUT`         | The holdings provider timed out. |

Wallet finder [#wallet-finder]

```http
GET /wallet-finder/search
GET /rh/wallet-finder/search
```

Finds full addresses that match a truncated one, such as `5ZkP...cikb` copied from a screenshot. The first path searches Solana, the second Robinhood Chain. See [Wallet finder](/docs/finder) for how matching works. Limited to 30 requests per minute per IP on each chain.

| Parameter | In    | Type   | Required | Notes                                                                                                                           |
| --------- | ----- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `q`       | query | string | yes      | 1 to 100 characters. A prefix, a suffix, both with a gap between them (`…`, 2 to 4 dots, `*` or a space), or a middle fragment. |

The known parts must be long enough:

| Chain                                | Prefix alone | Suffix alone | Middle | Each side of prefix…suffix |
| ------------------------------------ | ------------ | ------------ | ------ | -------------------------- |
| Solana (base58)                      | 3            | 4            | 4      | 3                          |
| Robinhood Chain (hex, `0x` optional) | 4            | 4            | 6      | 4                          |

```bash
curl "https://api.scanner.net/wallet-finder/search?q=5ZkP...cikb" \
  -H "x-api-key: $SCANNER_API_KEY"
```

**Response:** `{ "success": true, "data": { "pattern", "matches", "truncated" } }`. `pattern` is `exact`, `prefix`, `suffix`, `affix` or `middle`. `matches` holds up to 20 `{ address, firstSeen, lastSeen }`, most recently seen first; the times are when Scanner's index saw the address. `truncated` is `true` when there were more matches. A full address returns itself.

| Status | Code            | When                                                                      |
| ------ | --------------- | ------------------------------------------------------------------------- |
| 400    | `INVALID_INPUT` | `q` is missing, too long, or too short to search. The message says which. |
| 429    | `RATE_LIMITED`  | The per-IP limit was reached.                                             |
