Your own node or someone else's RPC? What a crypto payment watcher should trust

Every crypto checkout has a part nobody screenshots: the process that watches the chain and decides an invoice is paid. It's the least glamorous piece of the stack and the one that decides whether you ship goods for money you never received.
When I talk to people building their own checkout, the first shortcut they reach for is a hosted RPC endpoint. Sign up, paste an API key, poll eth_getLogs or a block explorer API, done. For a prototype that's fine. For the thing that flips orders to "paid", it's worth slowing down and asking what you are actually trusting.
What the watcher really decides
Strip it down and the watcher answers three questions for every invoice:
- Did a transfer of the right asset arrive at the right address?
- Is it big enough to cover the invoice (or is it partial, or over)?
- Is it buried deep enough that it won't disappear in a reorg?
All three answers come from whatever node you are asking. If that node is wrong, slow, rate-limited, or lying, your order state is wrong. Your code can be perfect and still credit a payment that isn't there.
The failure modes of borrowed data
None of these are exotic. I've seen each of them in someone's support inbox:
- Lag. A hosted endpoint behind a load balancer can serve you a block height a few blocks behind the tip from one backend and ahead from another. Your confirmation counter goes up, then down.
- Rate limits at the worst moment. Busy market, lots of checkouts, and your free tier starts returning 429s. The watcher either stalls (customers stare at a spinner) or, worse, a badly written retry treats "no data" as "no payment" and expires the invoice.
- Different views of the same chain. Two providers can disagree briefly about the head during a reorg. If you mix them, you get both versions.
- Someone else's outage is now your outage. Your checkout is up, your database is up, and nobody can pay because a third party is having a bad afternoon.
- Privacy. Every address you query tells the provider which addresses belong to your shop and when orders come in.
None of this means hosted RPC is evil. It means it's an input you should treat as a hint, not as the ledger.
A sensible split: settle on what you verify
The approach I like, and the one Coldtill takes, is simple to say: you run nodes for the networks you settle on, and the order is credited only when your own nodes see the funds arrive with full confirmations.
That sentence has a consequence people miss. You don't need a node for every coin you accept. Coldtill takes Ethereum, Base, Polygon, BNB, Tron, Solana and Bitcoin directly, and with auto-convert switched on it can accept 200+ more tokens on 35+ chains through NEAR Intents, which swaps the payment and delivers USDC or USDT to your cold wallet. For those swapped payments, the swap provider's progress reports are treated as hints. The order is only credited once your own node sees the stablecoin land in your cold wallet. You run a node for the chain you get paid on, not for every chain a customer might pay from.
That's the general rule I'd apply to any design, with or without Coldtill: the chain you settle on is the chain you verify yourself. Everything upstream of it is a status bar.

The payments list. An entry only moves to paid when the watcher on your own server has seen enough confirmations.
What "enough confirmations" means in practice
Once you own the data, you still have to decide when to believe it. A few rules that hold up:
- Count from your own head, every time. Confirmations are
your_tip - tx_block + 1, recomputed on each new block, never cached as a number that only goes up. - Expect the count to go backwards. A reorg can drop a transaction out of the canonical chain. Your state machine needs a path from "confirming" back to "waiting", and nothing downstream (fulfilment emails, licence keys) should fire before "confirmed".
- Pick thresholds per network. A fast chain with frequent short reorgs and Bitcoin with ten-minute blocks shouldn't share one number.
- Separate "seen" from "paid" in the UI. Customers calm down a lot when the checkout says "we see your payment, 2 of N confirmations" instead of nothing. Coldtill's hosted checkout shows live confirmation progress for exactly this reason.

The customer side: exact amount, QR code, and confirmation progress once the transfer is seen.
Then tell your shop, once
The watcher's last job is telling the shop. Coldtill sends a signed webhook with replay protection when a payment fills, partially fills or is cancelled. On your side that means:
- verify the signature and timestamp before reading the body,
- make the handler idempotent (the same payment arriving twice must not ship twice),
- and if you can, re-check status when the customer lands on your return page, because the browser sometimes beats the webhook.
I wrote more about the ordering problem in an earlier post on confirmations, reorgs and out-of-order webhooks, so I won't repeat it here.
The cost side, honestly
Running your own node is real work. You need disk, you need to watch sync status, and you need an alert when it falls behind. For a single small shop that might feel like overkill compared to a free API key.
My answer is that it's the same trade you make with your database. You could rent a shared one where you can't see the logs, or you can run a boring Postgres you understand. For the component that decides whether money arrived, I want the boring thing I can inspect.
If you'd like to see how the watcher fits next to the other processes (API, sweeper, payouts) in a Docker install, the Coldtill gateway source on GitHub is the place to start. The free edition installs with one command:
curl -fsSL https://coldtill.com/install.sh | sudo bash -s -- --edition free Whatever you build on, decide early which data you verify and which you merely accept. It's much easier to design that in than to bolt it on after the first "but the explorer said it was paid" ticket.