Guides
How to Verify a Crypto Payment Before Releasing an Order
The five checks that make a crypto transfer a real, settled payment — expected amount, sender, network, uniqueness and chain state — and how to automate them with a signed webhook instead of building the logic yourself.
By Forypay Engineering · Last updated September 6, 2026
The short answer
Verifying a crypto payment means proving four things before you release an order: money arrived at the address you published, in the exact amount you asked for, on the network you asked for, and in a state the chain has actually accepted (a confirmed block, not a pending or reorged one). Do these four checks and you release real revenue; skip any one of them and you transition from "processing a payment" to "absorbing a loss".
Why "the money arrived" is not enough
A transfer into your address is a fact about the chain, but it is not automatically a fact about your order. Between "a transfer exists" and "I fulfil the order" sits every failure that has ever cost a crypto merchant money: someone sent to the wrong wallet and now expects goods from you; a customer underpaid and still wants the product; the same run of your scan job counted one transfer twice; or a block the network will later discard included the payment and your checkout already shipped it.
Verification is the translation layer between the raw chain and the business decision to release. It has to resolve those ambiguities, and it has to do it the same way every time — the order release logic may be yours, but the proof under it should not be re-invented per merchant.
The checks that actually decide "verified"
- The amount matches exactly. The transfer value must equal the expected raw amount for the open order. This is the check that catches underpayments and overpayments: only an exact match settles, and any surplus is held for manual handling rather than credited to the order or silently pocketed.
- The sender is a third party. A transfer you sent out of your own wallet must never count as incoming revenue. Incoming-only scanning filters this out at the source.
- The network and token match the request. BSC USDT and TRON USDT are different ledgers. A transfer must be evaluated on the network and token the order specified — never "any transfer anywhere".
- The transfer is unique. The same transfer re-read in a later scan must not be counted twice. The natural key is network + transaction hash + log index; that combination is what makes a transfer "one payment, once".
- The chain state is final enough. The transfer must be found in a confirmed chain block. Detecting in unconfirmed blocks hands a reorg the power to undo what you already released (next section).
Confirmations: when you must wait, and when you don't
A "confirmation" is a statement about distance and finality: how many blocks sit on top of the one that included the transfer. The more blocks pile up, the harder it is for the chain to rearrange itself and drop the payment. On networks with slow blocks (like Bitcoin's ten minutes), merchants wait several confirmations because the risk of a reorg in the first minutes is real.
On BSC and TRON the trade-off is different: a new block arrives roughly every three seconds, and the memory-pool-to-confirmed hop is seconds, not minutes. The practical decision is not "wait for 12 confirmations" but "never act on an unconfirmed or pending transfer in the first place". A confirmed chain log on these networks is already accepted by the network — that is the boundary a payment verifier uses, settling the moment such a transfer is detected. There is no confirmation-counting step to wire up because the product never exposes unconfirmed state as payable in the first place.
Reorgs: the case for tying release to confirmed state
A chain reorganization ("reorg") happens when the network briefly included a block and then replaced it with a competing block that excludes the transfer. Reorgs are rare on BSC and TRON, but they exist — and their blast radius is the merchant who approved an order against a transfer that the chain later deleted.
The mitigation is not clever detection; it is never acting on unconfirmed state. If fulfilment only ever happens after a confirmed chain log is read, a reorg simply produces "a transfer that now is not there" — which, if it was already counted, is caught by the uniqueness check and expires the payment. That is the entire reorg strategy, and it is why verifiers treat confirmed-vs-pending as a hard filter rather than a preference.
Overpayments and underpayments, decided once
Both edge cases turn on a single decision made at payment creation: the amount is an exact equality test.
- Underpayment: the incoming transfer is below the expected amount, so it does not match any open order and the payment stays open until expiry. It is recorded and available to audit, but it never auto-releases.
- Overpayment: the transfer covers the expected amount, so the order settles. The surplus travels with the transfer record, so the merchant sees the overage and can refund it with an ordinary outgoing transfer.
- Neither is guessed at settle time. The equality is evaluated once, against the created payment — a merchant never re-decides "close enough?" under the pressure of a waiting customer.
How to verify with a payment API, step by step
- Create a payment (POST /api/v1/payments) with the receiving address, the expected raw amount plus the token's decimals, the network, and the offer's expiry.
- Show the customer the address and the exact amount on checkout. The expected amounts are locked at creation time — this is what makes the later equality check trustworthy.
- Wait. Nothing to build: a worker scans both chains for a matching incoming transfer to that address and that token.
- Receive the decision. On detection in a confirmed chain log the payment settles and your webhook is called (payment.detected, then payment.confirmed; payment.expired fires if time runs out). Every delivery is HMAC-signed.
- Verify the signature, then release the order against the confirmed state — not against something your checkout UI guessed.
Why the webhook is the release gate, not a nicety
Verification ends at a decision point, not a database row. A webhook is that decision point made explicit: your server receives payment.confirmed with the transfer data, checks the HMAC signature, and runs fulfilment. Because deliveries retry with exponential backoff until your endpoint returns 2xx, the decision is eventual — a temporarily down server does not lose the payment, it just receives it a moment later. Automating release this way is also what makes the amount/network/uniqueness checks a single code path instead of a pile of per-language reimplementations.
Frequently asked questions
- How do I verify that a crypto payment is real?
- Match the incoming transfer against four things: exact expected amount, third-party sender, the requested network and token, and confirmed chain state (never pending). A transfer in a confirmed block on BSC or TRON is already accepted by the network.
- How many confirmations should I wait for USDT on BSC or TRON?
- None above confirmed-log detection. These chains produce a block about every 3 seconds, so the hazard is acting on unconfirmed state, not waiting for depth. A verifier that only reads confirmed chain logs can settle immediately on detection.
- What is a blockchain reorg and why does it delay verification?
- A reorg is the network briefly including a block, then replacing it with a competing one that drops the transfer. It is rare on BSC/TRON. The safe response is to never release against an unconfirmed transfer, so a reorg can only produce a payment that simply does not exist yet — not one you already fulfilled.
- Can overpaid or underpaid transfers be auto-released?
- No. Neither underpaid nor overpaid transfers are ever auto-released. Only a transfer that matches the expected amount exactly settles the order; a shortfall keeps the payment open until expiry, and a surplus is recorded for manual handling. The exact amount is fixed at payment creation, not re-decided at settlement.
- Do I need my own node to verify payments?
- No. A verification API reads confirmed chain logs for you and delivers signed webhooks with the decision. Self-hosting means running a node plus an indexer plus reorg and dedupe handling — subsystems that each take real attention.
- Is verification free?
- With Forypay, verification is the only metered operation: creating a payment or a one-off check is one verification. The free plan includes 10 a month; reads and status polling are free. Paid plans meter the same way ($9 for 500, $29 for 2,500, or $0.05 per-verification).