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 case | Associated values | Description |
|---|---|---|
.paid(transId:) | String | Payment was completed and confirmed. |
.authorized(transId:) | String | Payment was authorized by the bank (preauthorization). |
.pending(transId:) | String | Payment is still being processed (intermediate state). |
.cancelled(errorReason:transId:) | String?, String | Payment was cancelled or rejected by the server. |
.failed(ComgateError) | ComgateError | Library-side error during the payment process. |
Paid
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):
errorReason | Meaning |
|---|---|
CUSTOMER_CLICK | Cancelled by the payer. |
FRAUD_SUSPECTED | Suspected fraud. |
ESHOP_CANCELLED | Cancelled by the merchant. |
PROVIDER_REPORT | Cancelled by the provider. |
PROVIDER_TIMEOUT | Provider timeout. |
CUSTOMER_TIMEOUT | Payment timed out. |
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 funds. |
REJECTED_BY_BANK | Rejected by the bank. |
3DS_AUTH_FAIL | Authentication failed. |
NOT_SPECIFIED | Not specified. |
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 identifiermessage: String— human-readable description in English
Initialization
| Case | Code | Description |
|---|---|---|
.deviceRooted | DEVICE_ROOTED | Device appears to be jailbroken or otherwise tampered with. Initialization is blocked to protect card data. The check is skipped in devMode. |
.initNetworkError | INIT_NETWORK_ERROR | Session initialization failed due to a network error. |
.initUnauthorized | INIT_UNAUTHORIZED | Server returned HTTP 401 during initialization — invalid or expired authorization. |
.initFailed | INIT_FAILED | Session initialization failed (non-network reason). |
.applicationNotAllowed | APPLICATION_NOT_ALLOWED | App is not allowed to use the SDK (Bundle ID is not on the allow-list). |
Payment processing
| Case | Code | Description |
|---|---|---|
.sessionNotInitialized | SESSION_NOT_INITIALIZED | Session has not been initialized. Call initialize() first. |
.invalidCardData | INVALID_CARD_DATA | Card data is not valid. |
.missingCardholderName | MISSING_CARDHOLDER_NAME | Cardholder name was not provided. |
.paymentFailed | PAYMENT_FAILED | Payment failed (non-network reason). |
.paymentNetworkError | PAYMENT_NETWORK_ERROR | Payment request failed due to a network error. |
.paymentCreateFailed | PAYMENT_CREATE_FAILED | Payment creation failed. |
.pollingTimeout | POLLING_TIMEOUT | Payment-status polling timed out. |
.pollingNetworkError | POLLING_NETWORK_ERROR | Payment-status polling failed due to a network error. |
.threeDSChallengeCancelled | THREE_DS_CHALLENGE_CANCELLED | 3D Secure challenge was cancelled. |
.threeDSChallengeTimeout | THREE_DS_CHALLENGE_TIMEOUT | 3D Secure challenge timed out. |
.threeDSFailed | THREE_DS_FAILED | 3D Secure authentication failed. |
Apple Pay
| Case | Code | Description |
|---|---|---|
.applePayNotConfigured | APPLE_PAY_NOT_CONFIGURED | Apple Pay is not configured. |
.applePayCancelled | APPLE_PAY_CANCELLED | Apple Pay was cancelled by the user. |
.applePayFailed | APPLE_PAY_FAILED | Apple Pay payment failed. |
Field validation
| Case | Code | Description |
|---|---|---|
.invalidPan | INVALID_PAN | Invalid card number. |
.invalidExpiryMonth | INVALID_EXPIRY_MONTH | Invalid expiry month. |
.cardExpired | CARD_EXPIRED | Card has expired. |
.invalidCvv | INVALID_CVV | Invalid CVV. |
.conflictingPaymentOptions | CONFLICTING_PAYMENT_OPTIONS | initRecurring and preauth cannot both be true. |
.invalidPrice | INVALID_PRICE | price 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 / Method | Type | Description |
|---|---|---|
visible | Bool | true if the view should be shown (read-only, @Published). |
text | String | Current text (read-only, @Published). |
translation | Translation | Translations 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)
PaymentResult | Behavior |
|---|---|
.paid | Shows the localized message from Translation.statusPaid in green (success). |
.authorized | Shows the localized message from Translation.statusAuthorized in green (success). |
.pending | Shows the localized message from Translation.statusPending in orange (processing). |
.cancelled | Shows errorReason in red (error). |
.failed | Shows 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)
}
}
}
}