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 type | Description |
|---|---|
PaymentResult.Paid | Payment was completed and confirmed. |
PaymentResult.Authorized | Payment was authorized by the bank (pre-authorization). |
PaymentResult.Pending | Payment is still being processed (intermediate state). |
PaymentResult.Cancelled | Payment was canceled or rejected by server. |
PaymentResult.Failed | Library-side error occurred during payment process. |
Paid
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
errorReason | Meaning |
|---|---|
CUSTOMER_CLICK | Canceled by payer. |
FRAUD_SUSPECTED | Fraud suspected. |
ESHOP_CANCELLED | Canceled by merchant. |
PROVIDER_REPORT | Canceled by provider. |
PROVIDER_TIMEOUT | Provider timeout. |
CUSTOMER_TIMEOUT | Payment timeout. |
ACS_TIMEOUT | Verification timeout. |
INVALID_CARDNO_EXPIRY | Invalid card number or expiry date. |
INVALID_CVC | Invalid CVC / CVV code. |
LIMIT_EXCEEDED | Card limit exceeded. |
NO_FUNDS | Insufficient account balance. |
REJECTED_BY_BANK | Rejected by bank. |
3DS_AUTH_FAIL | Payment verification failed. |
NOT_SPECIFIED | Not specified. |
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 identifiermessage- human-readable description in English
Initialization
| Code | Description |
|---|---|
DEVICE_ROOTED | Device appears to be rooted or tampered with. Initialization is blocked to protect sensitive card data. Skipped in devMode. |
INIT_NETWORK_ERROR | Session initialization failed due to network error. |
INIT_UNAUTHORIZED | Server returned HTTP 401 during initialization — invalid or expired authorization. |
INIT_FAILED | Session initialization failed (non-network reason). |
APPLICATION_NOT_ALLOWED | Application is not allowed to use SDK (package name not on allow-list). |
Payment processing
| Code | Description |
|---|---|
SESSION_NOT_INITIALIZED | Session was not initialized. Call initialize() first. |
INVALID_CARD_DATA | Card data is invalid. |
MISSING_CARDHOLDER_NAME | Cardholder name was not provided. |
PAYMENT_FAILED | Payment failed (non-network reason). |
PAYMENT_NETWORK_ERROR | Payment request failed due to network error. |
PAYMENT_CREATE_FAILED | Payment creation failed. |
POLLING_TIMEOUT | Payment state polling timed out. |
POLLING_NETWORK_ERROR | Payment state polling failed due to network error. |
Google Pay
| Code | Description |
|---|---|
GOOGLE_PAY_NOT_CONFIGURED | Google Pay is not configured. |
GOOGLE_PAY_FAILED | Google Pay payment failed. |
Field validation
| Code | Description |
|---|---|
INVALID_PAN | Invalid card number. |
INVALID_EXPIRY_MONTH | Invalid expiry month. |
CARD_EXPIRED | Card is expired. |
INVALID_CVV | Invalid 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)
| PaymentResult | Behavior |
|---|---|
Paid | Shows localized "Paid" message with green success style. |
Authorized | Shows localized "Authorized" message with green success style. |
Pending | Shows localized "Processing" message with orange processing style. |
Cancelled | Shows errorReason with red error style. |
Failed | Shows 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)
)
}
}
}