How to Monitor a Bitcoin Address for Incoming Payments

How Bitcoin payments differ from other chains, how many confirmations to wait for, and how to get a webhook when BTC arrives, without running a node.

· 5 min read

Watching a Bitcoin address sounds like the simplest job in crypto, and it is the one with the most surprises. A Bitcoin transaction is not "A sends 0.1 BTC to B". This guide explains what it is instead, how long to wait before you trust a payment, and how to be notified without running a Bitcoin node.

Why Bitcoin is different

  • A transaction has many inputs and many outputs. One transaction can pay your address twice, pay ten other people as well, and send change back to the sender.
  • There is no single sender. The inputs can come from several addresses, so "who paid me" often has no one answer.
  • An address can appear on both sides. When you spend from an address, part of the money usually returns to you as change.

So the useful question is not "which transfers touched my address" but "how much did this transaction change my address's balance". That is the number to credit.

How many confirmations to wait for

A transaction you can see is not yet a payment you can rely on. Until it is in a block it can be replaced, and the latest block can still be reorganised. Each further block makes that much less likely. Three confirmations, around half an hour, is a common threshold for everyday amounts, and six is the traditional one for large ones.

Getting a webhook when BTC arrives

The LirChain Wallet Tracker reads every Bitcoin block and reports what each transaction changed for the addresses you track. Create a free account, open the Wallet Tracker project in the dashboard, copy its API key and add your address:

curl https://api.lirchain.com/merchant/wallet-tracker/create \
  -H "x-api-key: YOUR_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "network": "bitcoin",
    "address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
    "external_id": "invoice-204"
  }'

Legacy (1…), script (3…) and SegWit and Taproot (bc1…) addresses are all accepted, written exactly as Bitcoin writes them. Use your own address in place of the example.

Open the project in the dashboard, paste the HTTPS address of your endpoint into its webhook field and save. A payment then arrives like this, three blocks after it is mined:

Webhook for an incoming Bitcoin payment
{
  "type": "wallet-tracker",
  "event": {
    "id": "95e04e32-5c98-4f68-8c62-f487bda0ed5c",
    "tracker_id": "67153a22-af19-4352-ab8e-041006c76c7b",
    "external_id": "invoice-204",
    "project_id": "ea54aa6c-21d7-46a4-b1fe-c0703f74a2af",
    "created_ms": 1791504120904
  },
  "transfer": {
    "network": "bitcoin",
    "block_number": 971350,
    "tx_hash": "4e3a…9f21",
    "log_index": null,
    "from_address": "",
    "to_address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
    "asset": "0x0000000000000000000000000000000000000000",
    "amount": "250000",
    "symbol": "BTC",
    "amount_units": "0.0025"
  }
}

Reading the event

  • to_address is your address and from_address is empty: the transaction added to your balance. The other way round means it took from it.
  • amount is the net change in satoshi and amount_units the same in BTC. If a transaction pays you twice, you get one event with the total. If you spend and receive change, you get one event with what actually left.
  • asset is all zeros for a network's own coin, and log_index is empty because Bitcoin has no logs.
Webhook handler (Node.js, Express)
import express from "express";

const app = express();
app.use(express.json());

// Use a table in your database instead of memory in production
const handled = new Set();

app.post("/webhooks/lirchain", (req, res) => {
    const id = req.get("x-webhook-id");

    if (handled.has(id)) {
        return res.sendStatus(200);
    }
    handled.add(id);

    const { type, event, transfer } = req.body;

    if (type === "wallet-tracker" && transfer.network === "bitcoin" && transfer.to_address) {
        console.log(`${event.external_id} received ${transfer.amount_units} BTC in ${transfer.tx_hash}`);
    }

    res.sendStatus(200);
});

app.listen(3000);

Answer with a 2xx status within 10 seconds. If your server does not, the same webhook is sent again every minute, up to 20 times, each time with the same x-webhook-id header, so keep the ids you handled and skip repeats.

Webhooks are not signed. Before you release goods or credit money because of one, read the event back from the API with your key and act on what the API says.

Good practice for Bitcoin payments

  • Use a fresh address for every invoice or customer. It tells you who paid and keeps your payments private from each other.
  • Price in your own currency and fix the BTC amount for a short time only, because the rate moves.
  • Decide in advance what happens with underpayments and late payments, and say so on the invoice.
  • The Free plan tracks 50 addresses and reports 250 events per 30 days, with no fee per event.

Questions and answers

Can I monitor a Bitcoin address without running a node?
Yes. A wallet tracker reads the blocks for you and sends a webhook for every confirmed change to the address. You only need the public address.
Why is the sender empty in a Bitcoin event?
A Bitcoin transaction can be funded from many addresses at once, so there is often no single sender. The event reports what the transaction changed for your address instead.
Are unconfirmed transactions reported?
No. A transaction is reported once it is three blocks deep, so everything you receive is already confirmed.

Try it on the Free plan

Every product is included, and no card is needed to sign up.

Create a free account

Keep reading