Refunds and reversals — business rules

The constraints, eligibility rules, and error semantics for processing refunds and reversals.

These rules govern every refund and reversal you process through Scan to Pay. They're enforced by the platform, the acquiring bank, or scheme rules — depending on the specific rule. Read these once before you build your refund flow.

For the API and worked examples, see Refunds and reversals.


Eligibility at a glance

ReversalFull refundPartial refund
Debit card✗ (PASA rules)✗ (PASA rules)
Credit card
Cheque card
Multiple per transaction?One onlyOne onlyYes, until original is fully refunded
After settlement?No — same-day onlyYes — within issuer windowYes — within issuer window
After original is reversed?n/a
After original is refunded (full or partial)?✗ if fully refunded✓ until original fully refunded

General rules

These apply to both reversals and refunds.

RuleDetail
AuthenticationBoth operations require the same Basic Auth or JWT Bearer credentials as the create-code flow. See Authentication.
Audit trailEvery reversal and refund is recorded on the Scan to Pay Portal as a transaction in its own right, linked to the original.
Timeframe enforced by issuerScan to Pay submits whatever you request to the bank. The bank decides whether it's still within their reversal/refund window. If they reject, the response surfaces on the webhook with the bank's ISO code.
MSISDN linkingA refund or reversal can be processed regardless of whether the original card is still linked to a customer wallet at the time of the refund.
Bad credentialsIf you attempt either operation with incorrect API credentials, you get 513 SECURITY_VIOLATION rather than 401. The transaction is not modified.
Mutual exclusivityA reversed transaction cannot be refunded. A refunded transaction (full or partial) cannot be reversed. Pick one path per transaction.

Reversal-specific rules

RuleDetail
Full amount onlyYou cannot reverse part of a transaction. The reversal undoes the entire original. If the customer wants a partial credit, use a refund.
One per transactionOnly one successful reversal is allowed per transactionId. Subsequent attempts return 514 UNABLE_TO_REVERSE.
All card typesDebit, credit, cheque — all supported for reversal. This is one of the main reasons to reverse rather than refund when both options apply.
Issuer windowIf the bank has already cleared (settled) the transaction, the reversal is rejected at the bank with an ISO response code. The transaction state becomes END_REVERSAL_FAILED.
Same-day ruleIn practice, reversals work for transactions made on the same business day. Anything older usually needs to be a refund.

Refund-specific rules

RuleDetail
Credit and cheque cards onlyDebit cards cannot be refunded — this is a PASA scheme rule, not a Scan to Pay limitation. Attempts return 445 INVALID_CLIENT_CARD.
Full or partialRefunds can be processed for any amount up to the original transaction value.
Multiple partials allowedYou can refund multiple times against the same transactionId until the cumulative refunded amount equals the original. After that, further refund attempts return 515 UNABLE_TO_REFUND.
Acquirer windowRefunds are subject to the acquiring bank's refund window (typically 6 months for credit, varies for cheque). Outside the window, the bank rejects.

Card-type detection

The original transaction's webhook includes cardInfo.accountType, which is one of:

accountTypeRefund eligible?
CREDIT
CHEQUE
DEBIT✗ — use a reversal instead, or alternative payout (EFT, cash)
NONE (defaulted)The platform treats NONE as CREDIT for eligibility

Build your refund UI to check accountType before showing the "Refund" button — disable it for debit cards and route to an alternative refund process (EFT, manual payout).


Errors and what they mean

CodeOperationCause
432 INVALID_AMOUNTRefundThe amount is zero, negative, or exceeds the remaining refundable balance
436 INVALID_TRANSACTION_REFBothThe transactionId doesn't match a known transaction
444 NOTHING_TO_REVERSEReversalThe transaction is already reversed, already refunded, or out of window
445 INVALID_CLIENT_CARDRefundAttempted on a debit card
513 SECURITY_VIOLATIONBothBad credentials
514 UNABLE_TO_REVERSEReversalThe bank rejected the reversal (cleared, outside window, etc.)
515 UNABLE_TO_REFUNDRefundThe bank rejected the refund (outside window, already refunded, etc.)

Full error reference: Errors. Map raw error codes to customer-friendly copy before showing them in your back-office UI.


The reversal-on-webhook-failure safety net

When your handler fails to acknowledge a successful webhook within 45 seconds, the platform automatically reverses the transaction. This counts as a reversal under all the rules above — meaning:

  • The transaction transitions to END_REVERSED
  • You cannot subsequently refund it (it's already been reversed)
  • You receive a webhook with status: REVERSED

This is enforced by the same Quartz reversal scheduler that handles manual reversals. See Webhooks — How it works.

📘

If you're debugging a "why was this transaction reversed?" question and you didn't trigger a reversal yourself, check whether your webhook handler returned non-200 or timed out on the original payment. It's the most common cause.


Card-on-file and recurring payment refunds

If the original transaction was a card-on-file (CCPI) or a recurring payment, the same rules apply. Card-type eligibility for refund is determined by the underlying accountType of the stored card, not by the fact that it's recurring.


What's next