Skip to main content

Payment Results

Payment result is represented by sealed class PaymentResult. Callback onPaymentResult in both SecurePayButton.setup() and SecureGooglePayButton.setup() is always called on the main thread.

PaymentResult

In practice, distinguish these result types:

PaymentResult typeDescription
PaymentResult.PaidPayment was completed and confirmed.
PaymentResult.AuthorizedPayment was authorized by the bank (pre-authorization).
PaymentResult.PendingPayment is still being processed (intermediate state).
PaymentResult.CancelledPayment was canceled or rejected by server.
PaymentResult.FailedLibrary-side error occurred during payment process.

Payment completed successfully.

is PaymentResult.Paid -> {
val transId = result.transId
// Payment completed
}

Authorized

Payment was authorized (pre-authorized) by the bank. This is a final state. Capture (settlement) will be performed by the merchant separately using the standard /capturePreauth or /cancelPreauth endpoints.

is PaymentResult.Authorized -> {
val transId = result.transId
// Payment authorized, awaiting capture
}

Pending

Payment is not final yet, backend is still processing it. The final state will be Paid, Authorized or Cancelled.

is PaymentResult.Pending -> {
val transId = result.transId
// Waiting for final state
}

Cancelled

Payment was canceled or rejected by server. Contains transaction identifier and optional reason.

is PaymentResult.Cancelled -> {
val transId = result.transId
val reason = result.errorReason
// Payment ended without successful charge
}

If result is PaymentResult.Cancelled, response also includes errorReason. In SDK this reason is available as PaymentResult.Cancelled.errorReason.

Possible errorReason values

errorReasonMeaning
CUSTOMER_CLICKCanceled by payer.
FRAUD_SUSPECTEDFraud suspected.
ESHOP_CANCELLEDCanceled by merchant.
PROVIDER_REPORTCanceled by provider.
PROVIDER_TIMEOUTProvider timeout.
CUSTOMER_TIMEOUTPayment timeout.
ACS_TIMEOUTVerification timeout.
INVALID_CARDNO_EXPIRYInvalid card number or expiry date.
INVALID_CVCInvalid CVC / CVV code.
LIMIT_EXCEEDEDCard limit exceeded.
NO_FUNDSInsufficient account balance.
REJECTED_BY_BANKRejected by bank.
3DS_AUTH_FAILPayment verification failed.
NOT_SPECIFIEDNot specified.
Testing error scenarios

In dev mode (devMode = true), you can simulate these values using errorReason in PaymentParams. See Error reason simulation.

Failed

Library-side error that happened during payment process. Unlike Cancelled (where server actively rejects payment), Failed means payment could not be completed at all, for example network failure.

Result contains ComgateError with machine-readable code (code) and human-readable message (message).

is PaymentResult.Failed -> {
val errorCode = result.error.code // for example "PAYMENT_NETWORK_ERROR"
val errorMessage = result.error.message // for example "Payment request failed due to a network error"
// Show error to user
}

ComgateError

All errors are defined as subtypes of sealed class ComgateError. Each type contains:

  • code - machine-readable error identifier
  • message - human-readable description in English
Initialization
CodeDescription
DEVICE_ROOTEDDevice appears to be rooted or tampered with. Initialization is blocked to protect sensitive card data. Skipped in devMode.
INIT_NETWORK_ERRORSession initialization failed due to network error.
INIT_UNAUTHORIZEDServer returned HTTP 401 during initialization — invalid or expired authorization.
INIT_FAILEDSession initialization failed (non-network reason).
APPLICATION_NOT_ALLOWEDApplication is not allowed to use SDK (package name not on allow-list).
Payment processing
CodeDescription
SESSION_NOT_INITIALIZEDSession was not initialized. Call initialize() first.
INVALID_CARD_DATACard data is invalid.
MISSING_CARDHOLDER_NAMECardholder name was not provided.
PAYMENT_FAILEDPayment failed (non-network reason).
PAYMENT_NETWORK_ERRORPayment request failed due to network error.
PAYMENT_CREATE_FAILEDPayment creation failed.
POLLING_TIMEOUTPayment state polling timed out.
POLLING_NETWORK_ERRORPayment state polling failed due to network error.
Google Pay
CodeDescription
GOOGLE_PAY_NOT_CONFIGUREDGoogle Pay is not configured.
GOOGLE_PAY_FAILEDGoogle Pay payment failed.
Field validation
CodeDescription
INVALID_PANInvalid card number.
INVALID_EXPIRY_MONTHInvalid expiry month.
CARD_EXPIREDCard is expired.
INVALID_CVVInvalid CVV code.

SecurePaymentStatusView

SecurePaymentStatusView displays payment status messages (success, processing, error). It starts hidden (GONE) and becomes visible after calling showStatus().

Showing status from PaymentResult

showStatus(PaymentResult) automatically detects result type and displays matching style:

val statusState = rememberPaymentStatusState()

// Automatic mapping from PaymentResult to status message
statusState.showStatus(paymentResult)

// In Composable:
SecurePaymentStatusView(state = statusState)
PaymentResultBehavior
PaidShows localized "Paid" message with green success style.
AuthorizedShows localized "Authorized" message with green success style.
PendingShows localized "Processing" message with orange processing style.
CancelledShows errorReason with red error style.
FailedShows error.message with red error style.

Hiding the view

statusState.clear()

Styling

Details on styling SecurePaymentStatusView via update block, setter methods, and XML attributes are in Component Styling.

Complete result handling example

@Composable
private fun PaymentResultHandler(session: ComgateSecureSession) {
val statusState = rememberPaymentStatusState()
var resultText by remember { mutableStateOf("") }
var resultVisible by remember { mutableStateOf(false) }

// ... (card fields, collector, button - see Card Data section)

// Payment result handling:
fun handlePaymentResult(result: PaymentResult) {
when (result) {
is PaymentResult.Paid -> {
statusState.showStatus(result)
resultVisible = true
resultText = "Payment completed\nTransId: ${result.transId ?: "-"}"
}

is PaymentResult.Authorized -> {
statusState.showStatus(result)
resultVisible = true
resultText = "Payment authorized\nTransId: ${result.transId}"
}

is PaymentResult.Pending -> {
statusState.showStatus(result)
resultVisible = true
resultText = "Payment is processing\nTransId: ${result.transId ?: "-"}"
}

is PaymentResult.Cancelled -> {
resultVisible = false
statusState.showStatus(result)
// Optional: Toast.makeText(context, "Payment canceled: ${result.errorReason ?: "no detail"}", Toast.LENGTH_LONG).show()
}

is PaymentResult.Failed -> {
resultVisible = false
statusState.showStatus(result)
Log.w("PaymentResult", "Failed: ${result.error.code} - ${result.error.message}")
// Optional: Toast.makeText(context, "Error: ${result.error.message}", Toast.LENGTH_LONG).show()
}
}
}

Column(modifier = Modifier.fillMaxWidth()) {
SecurePaymentStatusView(
state = statusState,
modifier = Modifier.fillMaxWidth()
)

if (resultVisible) {
Text(
text = resultText,
modifier = Modifier.padding(top = 8.dp)
)
}
}
}