Unknown state needs lookup, not a guess
Aliases: payment pending · unknown capture · query payment result
What it is
When the rail has not answered and the merchant will not mark success or failure, the UI is unknown. The right move is “look up this payment”: order id, asking the rail, how you will be told—not guessing failure and inviting another pay, or guessing success and shipping. This is the interaction principle for unknown. Timeout-is-not-failure and a brief rail/order mismatch labeled “processing” are the next split of that unknown.
Why it happens
People cannot sit with an unlabeled wait; they encode silence as failure, especially when money may already have moved. If the UI follows that encoding with “Failed, retry,” it stacks a new intent on an unknown. If it writes “Success,” it may ship an empty order. Lookup keeps judgment with the system: a read-only ask of the rail, UI held at “not yet known.” People need a sense of progress and an exit: refresh the result, open order detail, take the id to the bank—not a forced choice of which sentence to believe.
Studying it
Drop the async notify so the client times out. Compare label-as-fail, label-as-success, stay processing with lookup.
Independent variables: label after timeout, auto re-query, whether a pay button remains. Dependent variables: duplicate pay, empty-order ship, whether people can say “still not sure.”
Lab participants wait as instructed and will not open a bank app. Allow leave and return. Final reconciliation accuracy alone is not the measure—a double capture already refunded still means lookup failed in process.
Where it stops holding
Lookup has a time bound; after it, escalate to a human ticket rather than spin forever. If the person already sees a bank capture while the UI says unknown, say “the bank record wins, we are reconciling.” Fully offline, offer later lookup by id rather than a fake live result. A known decline must not be dressed as unknown to stall.
Applying it
- On timeout or no answer, show “result not confirmed,” offer lookup and the order id, and hide “pay again” until lookup returns failure.
- Lookup is read-only; auto-poll has a cap and an exit of “we will notify you.”
- When the result lands, leave unknown for a success receipt or an actionable failure; do not remain processing.
- Verify by dropping the rail callback: the page offers lookup, not failure; a pay-again before lookup returns is blocked. Copy that says “payment failed” while the rail later succeeds is a guess.