Track a deposit until it confirms

Step by step: poll tx/status until a transaction reaches your confirmation threshold, then verify the amount with tx/get.

# Track a deposit until it confirms

You have a transaction hash, for example from a customer who says "I sent it", and you want to know when it is safe to credit. You will poll [Transaction status](https://docs.rarebl.com/api/tx/status) until the transaction reaches your confirmation threshold, then confirm the amount and the address with [Transaction](https://docs.rarebl.com/api/tx/get).

## Before you start

- The `chain` the payment was sent on (`btc`, `ltc`, `bch`, `dash`, `eth` or `tron`) and the transaction hash (`id`).
- A confirmation threshold per chain. The reorg depths in [Data freshness](https://docs.rarebl.com/data-freshness) are 6 for BTC, LTC, BCH and DASH, 64 for ETH and 20 for TRON.
- Prefer being told instead of polling? Use a `tx.confirmations` [webhook](https://docs.rarebl.com/guides/webhooks) and skip to step 3.

## Step 1 — Ask for the status

```bash cURL
curl "https://api.rarebl.com/open/tx/status?chain=btc&id=9dedeb8092d6f026d235e3beb24337ba5657635a38cc949f70c0f28ea15e30db"
```

```js JavaScript
const url = 'https://api.rarebl.com/open/tx/status?chain=btc&id=9dedeb8092d6f026d235e3beb24337ba5657635a38cc949f70c0f28ea15e30db';
const body = await (await fetch(url)).json();
console.log(body.data.status, body.data.confirmations);
```

```python Python
import rarebl

c = rarebl.Rarebl()
data = c.status("btc", "9dedeb8092d6f026d235e3beb24337ba5657635a38cc949f70c0f28ea15e30db")
```

```bash Shell
rarebl status --chain btc 9dedeb8092d6f026d235e3beb24337ba5657635a38cc949f70c0f28ea15e30db
```

**You should see** a small reply with the status and the confirmation count.

```json
{
  "status": 1, "code": "API200", "message": "success",
  "data": { "hash": "9dedeb8092d6f026d235e3beb24337ba5657635a38cc949f70c0f28ea15e30db", "status": "success", "block": 975851, "confirmations": 20, "time": "2026-11-14T22:18:52Z" },
  "go": null,
  "meta": { "requestid": "0123456789abcdef", "notices": [] }
}
```

`data.status` is one of:

| `status` | Meaning | What to do |
| --- | --- | --- |
| `pending` | Seen in the mempool, not in a block. `block` and `time` are `null`, `confirmations` is 0. | Keep polling. |
| `success` | In a block. `confirmations` counts the blocks on top, including its own. | Credit once `confirmations` reaches your threshold. |
| `failed` | Included in a block but reverted (ETH and TRON). | Do not credit. |

## Step 2 — Poll until it confirms

Poll every few seconds, back off on errors, and stop at your threshold. Heads refresh about every 2 seconds, so polling faster gains nothing.

```js JavaScript
const THRESHOLD = { btc: 6, ltc: 6, bch: 6, dash: 6, eth: 64, tron: 20 };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function waitForConfirmations(chain, id) {
  let delay = 4000;
  for (;;) {
    const res = await fetch(`https://api.rarebl.com/open/tx/status?chain=${chain}&id=${id}`);
    const body = await res.json();

    if (body.code === 'API200') {
      const { status, confirmations } = body.data;
      if (status === 'failed') return { ok: false, reason: 'reverted' };
      if (status === 'success' && confirmations >= THRESHOLD[chain]) return { ok: true, confirmations };
      delay = 4000;
    } else if (body.code === 'API429') {
      delay = Number(res.headers.get('Retry-After') ?? 1) * 1000;
    } else if (body.code === 'API404') {
      delay = 4000;                                   // not seen by our node yet: keep waiting
    } else if (body.code === 'API502' || body.code === 'API409') {
      delay = Math.min(delay * 2, 30000);             // node syncing or index pending: back off
    } else {
      throw new Error(`${body.code}: ${body.message}`);   // API400 and friends: fix the request
    }
    await sleep(delay);
  }
}
```

```python Python
import time

THRESHOLD = {"btc": 6, "ltc": 6, "bch": 6, "dash": 6, "eth": 64, "tron": 20}

def wait_for_confirmations(c, chain, txid):
    delay = 4
    while True:
        try:
            s = c.status(chain, txid)
            if s["status"] == "failed":
                return False
            if s["status"] == "success" and s["confirmations"] >= THRESHOLD[chain]:
                return True
            delay = 4
        except rarebl.ApiError as e:
            if e.code == "API400":
                raise                                   # fix the request
            delay = min(delay * 2, 30)                  # 404 not seen yet, 429, 502, 409: back off
        time.sleep(delay)
```

**You should see** the function return once the threshold is reached (or at once with a failure for a reverted transaction).

## Step 3 — Check the amount and the address

`status` only tells you the transaction is final enough. Before you credit, confirm it paid the right address and amount with [Transaction](https://docs.rarebl.com/api/tx/get).

```bash cURL
curl "https://api.rarebl.com/open/tx/get?chain=btc&id=9dedeb8092d6f026d235e3beb24337ba5657635a38cc949f70c0f28ea15e30db"
```

- **UTXO chains:** look in `data.tx.utxo.outputs[]` for an output whose `address` is yours and whose `value` matches.
- **ETH and TRON:** check `data.tx.account.to` and `data.tx.value`, or for a token payment the matching entry in `data.tx.account.tokenTransfers[]`.
- Compare amounts as decimal strings or with a big-number type, never as floats.

**You should see** your address and the expected amount among the outputs. Only then credit the customer.

## Common errors

| Reply | What it means | What to do |
| --- | --- | --- |
| `API404` | The hash is not found yet: not seen by our node, or wrong. | Treat it as "not seen yet" for a while, then give up after a time you choose. |
| `API400` | The chain or hash is malformed. | Fix the request. |
| `API409` `tx_index_pending` | ETH only: the node is still indexing old transactions. | Retry later: see [Coverage and limits](https://docs.rarebl.com/limits-today). |
| `API429` | Polling too fast. | Wait `Retry-After`; one poll per pending deposit every few seconds is plenty. |
| `API502` | A node is unavailable or syncing. | Back off and retry. |

## Next steps

- Be pushed the events instead: [Webhooks](https://docs.rarebl.com/guides/webhooks) (`tx.confirmations`, `tx.final`).
- Find a transaction from a pasted string: [Look up any address or hash](https://docs.rarebl.com/guides/look-up-anything).
- Move the funds you received: [Watch addresses, get UTXOs and balances](https://docs.rarebl.com/guides/watch-addresses).
- Rate limits and retries: [Errors and rate limits](https://docs.rarebl.com/guides/handle-errors).

Back to the Rarebl AI documentation index