# Look up any address or hash

Someone pastes a string: a block height, a hash, an address, a token name, even a link from another explorer. You do not know which chain it is on, or what kind of thing it is. You will call [Search](https://docs.rarebl.com/api/search/query), read the ranked matches, and open the right endpoint.

## Before you start

- The string to look up. Nothing else is needed: no chain, no key. Send it as it was pasted: whitespace, quotes, `0x`, a `bitcoin:` payment link or an explorer link are handled.
- Search asks the nodes of the candidate chains in parallel, with a 4 second budget in total. A slow node shows up in `unavailable`, not as an error.

## Step 1 — Search

```bash cURL
curl "https://api.rarebl.com/open/search/query?q=800000"
```

```js JavaScript
const search = await (await fetch(`https://api.rarebl.com/open/search/query?q=${encodeURIComponent(q.trim())}`)).json();
if (search.code !== 'API200') throw new Error(search.message);
```

```python Python
import json, urllib.parse, urllib.request

url = "https://api.rarebl.com/open/search/query?q=" + urllib.parse.quote(q.strip())
results = json.load(urllib.request.urlopen(url))["data"]["results"]
```

**You should see** one result per match, best first. A height exists on several chains, so there are several results and `ambiguous` is `true`. Each result has a `label` ready to display, a `confidence`, and a `reason`.

```json
{
  "status": 1, "code": "API200", "message": "success",
  "data": {
    "results": [
      { "chain": "btc",  "type": "block", "id": "800000", "label": "Block 800000 · Bitcoin",      "confidence": 0.7, "reason": "Block 800000 exists on Bitcoin",      "verified": true, "path": "/btc/block/800000",  "rank": 1 },
      { "chain": "ltc",  "type": "block", "id": "800000", "label": "Block 800000 · Litecoin",     "confidence": 0.7, "reason": "Block 800000 exists on Litecoin",     "verified": true, "path": "/ltc/block/800000",  "rank": 2 },
      { "chain": "bch",  "type": "block", "id": "800000", "label": "Block 800000 · Bitcoin Cash", "confidence": 0.7, "reason": "Block 800000 exists on Bitcoin Cash", "verified": true, "path": "/bch/block/800000",  "rank": 3 },
      { "chain": "dash", "type": "block", "id": "800000", "label": "Block 800000 · Dash",         "confidence": 0.7, "reason": "Block 800000 exists on Dash",         "verified": true, "path": "/dash/block/800000", "rank": 4 }
    ],
    "best": { "chain": "btc", "type": "block", "id": "800000", "...": "the first result" },
    "ambiguous": true,
    "query": { "input": "800000", "normalized": "800000", "kind": "height", "source": "plain", "chain": null, "type": null, "payment": null },
    "suggestions": [], "unavailable": [], "mode": "full"
  },
  "go": null,
  "meta": { "requestid": "0123456789abcdef", "notices": [] }
}
```

(Shortened: `best` repeats `results[0]`.)

## Step 2 — Read what matched

| You search for | Result |
| --- | --- |
| Digits (also `#975,838`, `block 975838`) | A block height on every chain where that height exists. |
| 64 hex characters, with or without `0x` | A transaction or block hash. With `0x`, Ethereum first; without, every chain at once. |
| `0x` + 40 hex | An ETH address (a mixed-case one must pass its EIP-55 checksum): `address`, `contract` or `token`. |
| `T` + 33 base58, or 41-prefixed hex | A TRON address, or a TRC-20 contract (`token`). |
| Bech32 (`bc1…`, `ltc1…`), bech32m taproot (`bc1p…`), base58 (`1`, `3`, `L`, `M`, `X`, `7`) or CashAddr (`q…`, `p…`, `bitcoincash:`) | The matching UTXO chain or chains. |
| `USDT`, `tether`, `bitcoin`, `0xdac17f` | Known tokens and chains by name, symbol or contract prefix; a typo is tolerated. |
| An explorer link or a `bitcoin:` / `ethereum:` payment link | The identifier inside it. |

**Read `best` and `ambiguous`.** When `ambiguous` is `false` and `best` is set, open `best`. A legacy `1…` address is valid on Bitcoin and on Bitcoin Cash, but Bitcoin ranks far higher (0.92 against 0.45), so it is not ambiguous. When it is `true`, let the user pick, using `reason` and `confidence`. **No match is an empty `results` array with `API200`**, not an error: show `suggestions[].message`.

## Step 3 — Open the right endpoint

Use `type` to choose the endpoint and pass `chain` and `id` along.

| `type` | Call |
| --- | --- |
| `block` | [Block](https://docs.rarebl.com/api/block/get): `chain`, `id` |
| `tx` | [Transaction](https://docs.rarebl.com/api/tx/get): `chain`, `id` |
| `address` | [Address](https://docs.rarebl.com/api/address/balance): `chain`, `address` |
| `contract` | [Address](https://docs.rarebl.com/api/address/balance): `chain`, `address` (an address with code) |
| `token` | [Token](https://docs.rarebl.com/api/token/info): `chain`, `contract` |
| `chain` | The query named a chain (`bitcoin`): [Chains](https://docs.rarebl.com/api/stats/chains) |

```js JavaScript
const BASE = 'https://api.rarebl.com/open';

async function lookUp(q) {
  const search = await (await fetch(`${BASE}/search/query?q=${encodeURIComponent(q.trim())}`)).json();
  if (search.code !== 'API200') throw new Error(search.message);

  const { best, ambiguous, results, suggestions } = search.data;
  // One clear winner: open it. Several close ones: open them all and let the user pick.
  const wanted = best && !ambiguous ? [best] : results;
  const opened = await Promise.all(wanted.filter((r) => r.type !== 'chain').map(async (r) => {
    const call = {
      block:    `block/get?chain=${r.chain}&id=${r.id}&limit=1`,
      tx:       `tx/get?chain=${r.chain}&id=${r.id}`,
      address:  `address/balance?chain=${r.chain}&address=${r.id}`,
      contract: `address/balance?chain=${r.chain}&address=${r.id}`,
      token:    `token/info?chain=${r.chain}&contract=${r.id}`,
    }[r.type];
    return { ...r, reply: await (await fetch(`${BASE}/${call}`)).json() };
  }));
  return { opened, suggestions };
}
```

**You should see** each opened result with the reply of the matching endpoint. ETH block and transaction ids in results carry `0x`; BCH address ids are CashAddr without the prefix. On BTC, LTC and BCH an address lookup returns `balance: null` until the address is watched: see [Watch addresses](https://docs.rarebl.com/guides/watch-addresses).

## Step 4 — Handle a miss

Search tells you why nothing matched. Branch on `suggestions[].kind`, not on the text.

```json
{ "status": 1, "code": "API200", "message": "success",
  "data": { "results": [], "best": null, "ambiguous": false,
    "query": { "input": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNx", "normalized": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNx", "kind": "none", "source": "plain", "chain": null, "type": null, "payment": null },
    "suggestions": [ { "kind": "invalid_checksum", "chain": "btc", "message": "Looks like a Bitcoin address, but the checksum is wrong (a typo, or a missing or extra character). It could also be a Bitcoin Cash legacy address." } ],
    "unavailable": [], "mode": "full" },
  "go": null, "meta": { "requestid": "0123456789abcdef", "notices": [] } }
```

**You should see** an empty `results` and one suggestion. `unavailable` lists chains whose node did not answer in time: tell the user the answer may be incomplete and retry.

## Instant suggestions while typing

Send `mode=fast` with each keystroke (after a pause): it makes no node call, answers addresses, token names and contract prefixes at once, and returns heights and hashes with `verified: false`. Send the full lookup (the default mode) when the user presses Enter, or when the input is a complete number, hash or address. [Rarebl Explorer](https://docs.rarebl.com/explorer) does exactly this.

## Common errors

| Reply | What it means | What to do |
| --- | --- | --- |
| `API400` with `data.param: "q"` | `q` is missing or longer than 256 characters. | Trim the input and send at most 256 characters. |
| `API400` with `data.param: "mode"` or `"chain"` | The value is not one of the listed options. | Use `full` or `fast`; use a chain id such as `btc`. |
| Empty `results`, a `suggestion` of kind `invalid_checksum`, `wrong_length` or `testnet` | The input looks like an address but is not valid. | Show the suggestion message; ask the user to re-copy it. |
| Empty `results`, a `secret` suggestion | The input is a private or extended key. | Warn the user; the key was not searched or stored. |
| Non-empty `unavailable` | A node did not answer in time. | Show what you have and retry in a moment. |
| `API429` | Over 5 reads per second. | Wait `Retry-After`. |

## Next steps

- Ready-made pages: [Rarebl Explorer](https://docs.rarebl.com/explorer) links straight to blocks, transactions and addresses.
- Follow a transaction: [Track a deposit until it confirms](https://docs.rarebl.com/guides/track-a-deposit).
- The shared response shapes: [Data types](https://docs.rarebl.com/data-types).
