Skip to main content

Payment results

The payment result is represented by the PaymentResult enum. The async methods processPayment(...) and processApplePayPayment(...) return PaymentResult directly; the onResult callback in SecurePayButton and SecureApplePayButton is always invoked on the main thread.

PaymentResult

In practice, distinguish these result types:

PaymentResult caseAssociated valuesDescription
.paid(transId:)StringPayment was completed and confirmed.
.authorized(transId:)StringPayment was authorized by the bank (preauthorization).
.pending(transId:)StringPayment is still being processed (intermediate state).
.cancelled(errorReason:transId:)String?, StringPayment was cancelled or rejected by the server.
.failed(ComgateError)ComgateErrorLibrary-side error during the payment process.

The payment was successfully completed.

case .paid(let transId):
// Payment completed
print("Paid: \(transId)")

Authorized

The payment was authorized (preauthorized) by the bank. This is a final state. Capture (settlement) is performed by the merchant separately via the standard /capturePreauth or /cancelPreauth endpoints.

case .authorized(let transId):
// Authorized — awaiting capture
print("Authorized: \(transId)")

Pending

The payment is not yet final; the backend is still processing it. The final state will be .paid, .authorized, or .cancelled.

case .pending(let transId):
// Awaiting final state
print("Pending: \(transId)")

Cancelled

The payment was cancelled or rejected by the server. It includes a transaction identifier and an optional reason.

case .cancelled(let errorReason, let transId):
// Payment finished without being charged
print("Cancelled: \(errorReason ?? "-") (\(transId))")

Possible errorReason values

errorReason is the raw value of the ErrorReason enum (it may be nil if the server didn't supply it):

errorReasonMeaning
CUSTOMER_CLICKCancelled by the payer.
FRAUD_SUSPECTEDSuspected fraud.
ESHOP_CANCELLEDCancelled by the merchant.
PROVIDER_REPORTCancelled by the provider.
PROVIDER_TIMEOUTProvider timeout.
CUSTOMER_TIMEOUTPayment timed out.
ACS_TIMEOUTVerification timeout.
INVALID_CARDNO_EXPIRYInvalid card number or expiry date.
INVALID_CVCInvalid CVC / CVV code.
LIMIT_EXCEEDEDCard limit exceeded.
NO_FUNDSInsufficient funds.
REJECTED_BY_BANKRejected by the bank.
3DS_AUTH_FAILAuthentication failed.
NOT_SPECIFIEDNot specified.
Testing error scenarios

In dev mode (devMode = true) you can simulate these values via the errorReason parameter in PaymentParams. See Simulating an error reason.

Failed

A library-side error during the payment process. Unlike .cancelled (where the server actively rejected the payment), .failed indicates the payment did not complete at all — e.g. network error, uninitialized session, etc.

The associated value is a ComgateError with a machine-readable code (code) and a human-readable message (message).

case .failed(let error):
let errorCode = error.code // e.g. "PAYMENT_NETWORK_ERROR"
let errorMessage = error.message // e.g. "Network error during payment."
// Show the error to the user

ComgateError

All errors are defined as cases of the ComgateError enum. Every case exposes:

  • code: String — machine-readable error identifier
  • message: String — human-readable description in English
Initialization
CaseCodeDescription
.deviceRootedDEVICE_ROOTEDDevice appears to be jailbroken or otherwise tampered with. Initialization is blocked to protect card data. The check is skipped in devMode.
.initNetworkErrorINIT_NETWORK_ERRORSession initialization failed due to a network error.
.initUnauthorizedINIT_UNAUTHORIZEDServer returned HTTP 401 during initialization — invalid or expired authorization.
.initFailedINIT_FAILEDSession initialization failed (non-network reason).
.applicationNotAllowedAPPLICATION_NOT_ALLOWEDApp is not allowed to use the SDK (Bundle ID is not on the allow-list).
Payment processing
CaseCodeDescription
.sessionNotInitializedSESSION_NOT_INITIALIZEDSession has not been initialized. Call initialize() first.
.invalidCardDataINVALID_CARD_DATACard data is not valid.
.missingCardholderNameMISSING_CARDHOLDER_NAMECardholder name was not provided.
.paymentFailedPAYMENT_FAILEDPayment failed (non-network reason).
.paymentNetworkErrorPAYMENT_NETWORK_ERRORPayment request failed due to a network error.
.paymentCreateFailedPAYMENT_CREATE_FAILEDPayment creation failed.
.pollingTimeoutPOLLING_TIMEOUTPayment-status polling timed out.
.pollingNetworkErrorPOLLING_NETWORK_ERRORPayment-status polling failed due to a network error.
.threeDSChallengeCancelledTHREE_DS_CHALLENGE_CANCELLED3D Secure challenge was cancelled.
.threeDSChallengeTimeoutTHREE_DS_CHALLENGE_TIMEOUT3D Secure challenge timed out.
.threeDSFailedTHREE_DS_FAILED3D Secure authentication failed.
Apple Pay
CaseCodeDescription
.applePayNotConfiguredAPPLE_PAY_NOT_CONFIGUREDApple Pay is not configured.
.applePayCancelledAPPLE_PAY_CANCELLEDApple Pay was cancelled by the user.
.applePayFailedAPPLE_PAY_FAILEDApple Pay payment failed.
Field validation
CaseCodeDescription
.invalidPanINVALID_PANInvalid card number.
.invalidExpiryMonthINVALID_EXPIRY_MONTHInvalid expiry month.
.cardExpiredCARD_EXPIREDCard has expired.
.invalidCvvINVALID_CVVInvalid CVV.
.conflictingPaymentOptionsCONFLICTING_PAYMENT_OPTIONSinitRecurring and preauth cannot both be true.
.invalidPriceINVALID_PRICEprice must be a positive integer in the smallest currency unit.

SecurePaymentStatusView

The SecurePaymentStatusView component shows payment status messages (success, processing, error). It works with a PaymentStatusState object that holds the current displayed message.

PaymentStatusState

Property / MethodTypeDescription
visibleBooltrue if the view should be shown (read-only, @Published).
textStringCurrent text (read-only, @Published).
translationTranslationTranslations used for automatic messages. Set this to session.translation.
show(result:)func show(result: PaymentResult)Automatically picks and displays the localized message for the result.
showError(_:)func showError(_ message: String)Shows a custom error message.
hide()func hide()Hides the view (text remains).
clear()func clear()Hides the view and clears the text.

Showing the state from PaymentResult

@StateObject private var statusState = PaymentStatusState()

statusState.translation = session.translation
statusState.show(result: paymentResult)

// In SwiftUI:
SecurePaymentStatusView(state: statusState)
PaymentResultBehavior
.paidShows the localized message from Translation.statusPaid in green (success).
.authorizedShows the localized message from Translation.statusAuthorized in green (success).
.pendingShows the localized message from Translation.statusPending in orange (processing).
.cancelledShows errorReason in red (error).
.failedShows error.message in red (error).

Hiding the view

statusState.clear()  // hides the view and clears the text
statusState.hide() // hides only, text remains

Styling

For details on styling SecurePaymentStatusView via the PaymentStatusStyle struct, see Component styling.

Complete result-handling example

struct PaymentResultHandler: View {
@ObservedObject var session: ComgateSecureSession
@StateObject private var statusState = PaymentStatusState()
@State private var resultText = ""
@State private var resultVisible = false

func handle(_ result: PaymentResult) {
statusState.translation = session.translation

switch result {
case .paid(let t):
statusState.show(result: result)
resultVisible = true
resultText = "Payment completed\nTransId: \(t)"
case .authorized(let t):
statusState.show(result: result)
resultVisible = true
resultText = "Payment authorized\nTransId: \(t)"
case .pending(let t):
statusState.show(result: result)
resultVisible = true
resultText = "Payment pending\nTransId: \(t)"
case .cancelled:
statusState.show(result: result)
resultVisible = false
case .failed(let err):
statusState.show(result: result)
resultVisible = false
print("Failed: \(err.code)\(err.message)")
}
}

var body: some View {
VStack {
// ... (card fields, button — see Card data)

SecurePaymentStatusView(state: statusState)

if resultVisible {
Text(resultText)
.padding(.top, 8)
}
}
}
}