A transaction hash is evidence that something was submitted. It is not, by itself, evidence that a payment is safe to settle.
That distinction became one of the product questions I kept returning to while working on a multi-chain payment gateway. The interface wants to show progress quickly. The backend needs stronger evidence before it credits a ledger, releases an item, or tells a merchant that the payment is complete.
The states are part of the product
A payment needs more than a green tick or a red cross. At minimum, the system has to distinguish between a request that is waiting to be submitted, a transaction that has been broadcast, a transaction that is still being checked, a confirmed payment, and a failure that needs action.
These states affect different people in different ways.
- The user wants to know whether they should wait or try again.
- The merchant wants to know whether an order can be released.
- The backend needs to know whether it can update the ledger.
- The delivery team needs acceptance criteria for every transition.
When these states are vague, the UI, webhook handler, and support process all start making different assumptions.
The useful boundary
Client-side detection can make the experience feel responsive. It can tell the user that funds have been noticed or that a wallet has submitted a transaction.
Settlement needs a server-side signal that has been verified. The backend should check the network, token, recipient, amount, transaction status, and duplicate-processing rules before moving the payment into a final state.
That boundary is a product decision as much as a technical one. It decides when the business is willing to treat an on-chain event as money received.
What I would put in the backlog
For a payment lifecycle, I would turn the following into explicit stories and acceptance criteria.
- A payment request has a unique reference and an expiry.
- The selected token and network are checked before signing.
- A submitted transaction records its hash without becoming settled.
- Delayed, failed, and duplicated transactions have different outcomes.
- A webhook is verified before it can trigger a ledger update.
- Retrying a write does not credit the same payment twice.
This is not glamorous product work. It is the part that stops a payment demo from becoming a support problem later.
The full cross-chain flow is documented in my Web3 payment transaction lifecycle note.
This is a generalised case study. Product-specific business details, implementation details, and performance results remain confidential.