A transaction is a state machine, not one HTTP call

A banking transaction moves through distinct states: captured intent, validation, authorization, posting, external processing when applicable, reconciliation, and final customer-visible outcome. Compressing these into a boolean success flag hides uncertainty and makes retries, approvals, reversals, and incident handling unsafe.

Separate channel status from financial posting status

  • Use explicit states with allowed transitions and a reason/code for rejection.
  • Authorization is different from posting; approval can succeed before a downstream financial action finishes.
  • Pending must describe what the system is waiting for, not act as a catch-all.
  • Reversal is a new controlled transaction linked to the original, not deletion of history.
  • Every externally visible state change should have audit and correlation evidence.

Lifecycle from intent to finality

The transaction advances only through allowed state transitions; ambiguous external outcomes pause for reconciliation rather than inventing success or failure.

Diagram

Financial transaction lifecycle

The transaction advances only through allowed state transitions; ambiguous external outcomes pause for reconciliation rather than inventing success or failure.

What “pending” should mean

Lifecycle bugs that confuse customers and operations

Transaction-state checklist

  • Draw the state machine and allowed transitions.
  • Name the owner of each state transition.
  • Separate approval, posting, and settlement states where required.
  • Define unknown/reconciliation behavior.
  • Keep original, reversal, and return references linked immutably.