Transaction states
Every state a Scan to Pay transaction can be in, what it means, and what the integrator should do.
A Scan to Pay transaction progresses through a state machine. This page lists every state the system can return, grouped by what they mean for the integrator. Authoritative values are taken directly from TxState in the Scan to Pay platform source.
How to use this page
You will see transaction states in webhook payloads, in code/queryRef responses (merchants), in getTransactionState responses (wallet providers, on the Remote API), and in the Admin Portal.
Three things to remember:
SUCCESSis the only positive terminal state. If you see anything else, the transaction did not complete normally — even if the state name sounds OK.END_*states are terminal. Stop polling. Do not retry the same transaction; create a fresh one if the customer wants to try again.- States prefixed
START_*,PROCESS_*,OFF_TO_*,RECEIVED_*are transient. Keep polling or wait for the webhook.
Wallet naming noteSeveral enum values include
MASTERPASSin their literal name (OFF_TO_MASTERPASS,END_MASTERPASS_COMPLETE, etc.). These are preserved for wire compatibility — treat them as the canonical Scan to Pay wallet states. Production traffic returns the literal values shown below.
Terminal — Success
| State | Meaning |
|---|---|
SUCCESS | The transaction has been completed successfully. Funds are committed. |
END_3DS_PURCHASE | A 3D Secure transaction completed (terminal success of the 3DS flow). |
CODE_NOTIFY_SUCCESS | The merchant notification was delivered and acknowledged. Often paired with SUCCESS. |
CODE_NOTIFY_SUCCESS_NOACK | The merchant notification was delivered but no acknowledgement was received from the merchant. The payment still succeeded — but check the merchant's webhook handler. |
CODE_EXTERNAL_SUCCESS | External code flow completed successfully. |
Terminal — Customer didn't complete
The customer started the flow but didn't finish. Treat as "abandoned cart."
| State | Meaning |
|---|---|
END_CLIENT_CANCEL | The customer cancelled while trying to pay (network/USSD only). |
END_CLIENT_TIMEOUT | The customer timed out while trying to pay (network/USSD only). |
END_CLIENT_CANCELLED_RECURRING_PAYMENT | The customer cancelled a recurring payment series. |
Terminal — Declined by bank or issuer
The bank or card issuer rejected the transaction. The customer may be able to retry with a different card.
| State | Meaning |
|---|---|
END_BANK_NON_00 | The acquiring bank returned a non-00 ISO response code. Inspect the response code for the precise reason. |
END_BANK_DECLINE | The bank declined the transaction. |
END_INSUFFICIENT_FUNDS_OR_OVER_CREDIT_LIMIT | Blocked before reaching the bank because TPE rules (mandated by Visa/Mastercard) detected insufficient funds. |
END_ACCOUNT_CLOSED_OR_FRAUDULENT | The card account is closed or flagged as fraudulent. |
END_CARD_EXPIRY_NOT_ALLOWED | Card expiry date not permitted by the merchant or scheme. |
END_BIN_NOT_WHITELISTED | The card BIN is not in the merchant's allowed list. |
END_NOTALLOW_BIN_CLASSIFICATION | The merchant does not accept this BIN classification (e.g. international cards on a domestic-only merchant). |
ISSUER_NEVER_APPROVE | The issuer has declined and will never approve this transaction (do not retry — present a different funding source). |
ISSUER_NOT_APPROVE_NOW | The issuer declined for now (the customer may retry shortly). |
Terminal — Authentication / 3D Secure failures
| State | Meaning |
|---|---|
END_BRE_REJECTION | BankServ / ACS rejected the 3D Secure step. |
END_HASH_FAILED | A hash check failed (mismatched MSISDN / card number / cardholder data). |
Terminal — Bank communication issues
These usually indicate a transient infrastructure problem on the bank side, not a card problem.
| State | Meaning |
|---|---|
END_BANK_EXPIRED | The transaction expired waiting for a bank response. |
END_BANK_ERROR | An error occurred on the bank node. |
END_BANK_OFFLINE | The bank node was offline or unreachable. |
END_PIN_PUSH_ERROR | Error while pushing the PIN request to the customer. |
END_PIN_PUSH_OFFLINE | PIN push channel offline. |
Terminal — Scan to Pay platform errors
Our side. Investigate before retrying.
| State | Meaning |
|---|---|
END_SYSTEM_ERROR | Unexpected error in the Scan to Pay platform. |
END_SYSTEM_FAULT | Unhandled exception in the platform. |
END_TIME_OUT_IN_QUEUE | Transaction waited too long in an internal queue (typically RabbitMQ to a bank node). |
END_CODE_PURCHASE_ERROR | Error processing the code-based purchase. |
END_VOUCHER_ERROR | Error during a voucher purchase. |
Terminal — Validation failures
The request was rejected before reaching the bank.
| State | Meaning |
|---|---|
END_INVALID_AMOUNT | The amount on the purchase was rejected (zero, negative, exceeds maximum, or doesn't match the code amount). |
END_VALIDATION_FAILED | Generic validation error while processing the transaction. |
END_CODE_IN_USE | A use-once code was already used. |
Terminal — Risk / fraud / limit blocks
The platform blocked the transaction. Customer is not at fault; retry with caution.
| State | Meaning |
|---|---|
END_LIMIT_FAILED | The transaction failed a limit check (e.g. daily / monthly airtime limit). |
END_FRAUD_DETECTION | The transaction was flagged by fraud detection rules. |
END_BLACKLISTED | The card, MSISDN, or device is blacklisted. |
END_TX_RATE_BLOCKED | The customer exceeded the allowed transaction rate (velocity check). |
Terminal — Refunds and reversals
These appear on the original transaction when a refund or reversal is applied.
| State | Meaning |
|---|---|
END_REVERSED | The transaction has been reversed successfully. |
END_REVERSAL_FAILED | A reversal attempt failed (e.g. outside the reversal window). |
END_REFUNDED | The transaction has been refunded (full or partial). |
END_REFUND_FAILED | A refund attempt failed. |
MARKED_FOR_REVERSAL | The transaction is queued for reversal (transient — wait for END_REVERSED or END_REVERSAL_FAILED). |
Terminal — WIG / USSD timeout failures
Specific to feature-phone and Wallet Initiation Gateway flows. The customer didn't respond to a prompt in time.
| State | Meaning |
|---|---|
END_TIMEOUT_PURCHASE | Customer received the WIG push but did not select/add a card and authorise. |
END_TIMEOUT_PURCHASE_3DS | A 3DS transaction was initiated but not completed. |
END_TIMEOUT_BALANCE | Timed out waiting for the balance response. |
END_TIMEOUT_CARD_DETAILS | Customer entered card details but the transaction timed out before completion. |
END_TIMEOUT_ADD_CARD | Add-card request sent; no response from customer. |
END_TIMEOUT_RELINK_MSISDN | Timeout while relinking the MSISDN to a card. |
END_TIMEOUT_CARD_VALIDATION | Timeout on a card-validation call. |
END_TIMEOUT_LINK_CARD_FAILED | The card link failed because the customer didn't pass the bank's hash check. |
END_TIMEOUT_HASH_CHECK_FAILED | Hash check failed during card linking. |
END_TIMEOUT_CARD_NOT_SUPPORTED | Customer entered a BIN that isn't supported. |
END_TIMEOUT_REMOVE_CARD | Timeout removing a card. |
END_TIMEOUT_INVALID_PIN | Customer entered an invalid PIN format. |
END_TIMEOUT_INVALID_CVV | Customer entered an invalid CVV format. |
END_TIMEOUT_INVALID_CARD_NUMBER | Customer entered an invalid card number. |
END_TIMEOUT_INVALID_ACC_TYPE | Customer entered an invalid account type. |
END_TIMEOUT_INVALID_EXPIRY | Customer entered an invalid expiry date. |
END_TIMEOUT_INVALID_DOB | Customer entered an invalid date of birth. |
END_TIMEOUT_REQUEST_QOS | No quality-of-service feedback from WIG on the initial request. |
END_TIMEOUT_REQUEST_QOS_GET_CARD_READY | System failed to send a QOS message during get-card-ready. |
END_TIMEOUT_REQUEST_QOS_GET_CARD_READY_SENT | QOS message sent for get-card-ready; user didn't respond within the limit. |
END_TIMEOUT_REQUEST_QOS_SELECT_BANK | System failed to send a QOS message at the select-bank step. |
END_TIMEOUT_REQUEST_QOS_SELECT_BANK_SENT | QOS message sent for select-bank; user didn't respond within the limit. |
Terminal — Code lifecycle
For codes (QR codes) themselves, not for transactions.
| State | Meaning |
|---|---|
CODE_NOTIFY_FAIL | The merchant notification webhook failed to deliver. |
CODE_NOTIFY_FAIL_NOACK | Notification delivered but no acknowledgement received. |
CODE_EXTERNAL_FAILED | External code flow failed. |
Transient — Start / mid states
You generally only see these inside the platform or in admin tools, not in webhooks delivered to integrators. Listed for completeness.
| State | Stage | Meaning |
|---|---|---|
START_CODE_PURCHASE | Start | A code-based purchase has been initiated. |
START_NETWORK_PURCHASE | Start | A network (USSD/WIG) purchase has been initiated. |
START_NETWORK_BALANCE | Start | A network balance check has been initiated. |
START_MOBILE_PURCHASE | Start | A mobile-initiated purchase has been initiated. |
START_WIG_3DS_PURCHASE | Start | A WIG 3D Secure purchase has been initiated. |
START_3DS_PURCHASE | Start | A 3D Secure purchase flow has been initiated. |
START_3DS_PURCHASE_PENDING | Start | A 3DS purchase is pending the customer's auth step. |
START_VOUCHER_PURCHASE | Start | A voucher purchase has been initiated. |
START_STRIKE_PURCHASE | Start | A strike (chargeback-style) purchase has been initiated. |
START_CCPI_PURCHASE | Start | A card-on-file recurring purchase has been initiated. |
START_CODE_NOTIFY | Start | The merchant-notify flow has started for a completed code. |
PROCESS_CODE_NOTIFY | Mid | The merchant-notify HTTP call is in flight. |
PROCESS_VOUCHER_PURCHASE | Mid | A voucher purchase is being processed. |
OFF_TO_BANK | Mid | The transaction has been sent to the acquiring bank for authorisation. |
OFF_TO_MASTERPASS | Mid | The transaction has been sent to the Scan to Pay wallet, awaiting a reply. |
RECEIVED_MASTERPASS_WALLET_REPLY | Mid | A reply has been received from the Scan to Pay wallet. |
RECEIVED_PIN_RESPONSE | Mid | PIN entry response received from the customer's device. |
END_MASTERPASS_ERROR | Mid → terminal | Error returned from the Scan to Pay wallet (during the wallet leg, before bank). |
END_MASTERPASS_COMPLETE | Mid → terminal | The wallet leg completed successfully (typically followed by OFF_TO_BANK → SUCCESS). |
Notes for integrators
- Polling cadence. If you do not have a webhook configured, poll the transaction state at no faster than once every 5 seconds. Most transactions reach a terminal state within 30 seconds.
- Idempotency. Do not treat any transient state as success. Only
SUCCESSandEND_REFUNDED/END_REVERSED(for refund and reversal flows) are settle-positive. - Display to customers. Never show raw state names to end users. Map them to human-readable copy in your UI.
What's next
- Receive states via webhook → Webhooks
- Map bank decline reasons to customer messages → ISO response codes
- HTTP error codes you'll see before a state is reached → Errors
- Retry safely with the same reference → Idempotency
Updated about 20 hours ago
