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.