Look up any address or hash
Step by step: use search/query to find out what a pasted string is, then open the right endpoint.
# 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).