Skip to content

Error Reference

Tokenization and 3D Secure failures are reported through CompletePaymentSheet's onFailure callback. Each failure carries a FinixErrorCode describing the exact failure mode.

Deprecated signature

The deprecated signature had no failure callback — errors were surfaced via a toast inside the sheet. If you're still using the deprecated signature, tokenization errors won't reach your code. Migrate to the new CompletePaymentSheet signature.

FinixErrorCode

A sealed interface — pattern-match on the specific type in when to branch per failure mode. Every variant carries a human-readable message suitable for surfacing to the buyer.

FinixErrorCode shape

sealed interface FinixErrorCode {
    val message: String

    data object NetworkError : FinixErrorCode {
        override val message = "Network error. Please check your connection."
    }

    data object Timeout : FinixErrorCode {
        override val message = "Request timed out. Please try again."
    }

    data object PaymentFailed : FinixErrorCode {
        override val message = "Payment failed. Please try again."
    }

    data class MissingConfiguration(val field: String) : FinixErrorCode {
        override val message = "3DS is enabled but required field '$field' is missing."
    }

    data class ThreeDSFailed(val failureCode: ThreeDSFailureCode?) : FinixErrorCode {
        override val message =
            failureCode?.failureMessage ?: "3DS authentication failed. Please try again."
    }

    data class Unknown(val detail: String = "") : FinixErrorCode {
        override val message = detail.ifEmpty { "An unexpected error occurred." }
    }
}
VariantMeaning
NetworkErrorThe device could not reach Finix (no connectivity, DNS failure, TLS error).
TimeoutA Finix API call did not return within the SDK's timeout window.
PaymentFailedTokenization reached Finix but did not succeed. Typically an invalid or declined card.
MissingConfiguration(field)3DS was enabled but a required field is missing from PaymentSheetConfiguration — the field property names which one (e.g. "merchantId", "apiUsername").
ThreeDSFailed(failureCode)3D Secure authentication failed. The nested ThreeDSFailureCode describes the specific reason. No liability shift — do not charge.
Unknown(detail)An unexpected error. detail carries any available context from the SDK.

ThreeDSFailureCode

Nested inside FinixErrorCode.ThreeDSFailed and populated on ThreeDSResponse.failureCode. Each case carries a failureMessage string explaining the failure.

ThreeDSFailureCode cases

enum class ThreeDSFailureCode(val failureMessage: String) {
    ACCESS_CONTROL_SERVER_UNAVAILABLE,
    AUTHENTICATION_FAILED,
    AUTHENTICATION_TIMED_OUT,
    CARD_NOT_ENROLLED,
    CHALLENGE_REQUIRED,
    DIRECTORY_SERVER_UNAVAILABLE,
    INVALID_ACQUIRER,
    INVALID_CARD,
    PROTOCOL_ERROR,
    REQUIRED_DATA_ELEMENT_MISSING,
    SUSPECTED_FRAUD,
    TRANSACTION_CANCELLED_BY_CARDHOLDER,
    TRANSACTION_NOT_PERMITTED,
    TRANSIENT_SYSTEM_FAILURE,
    UNSUPPORTED_3D_SECURE_VERSION,
}
CaseMeaning
ACCESS_CONTROL_SERVER_UNAVAILABLEThe card issuer's authentication server was unavailable. Retry later.
AUTHENTICATION_FAILEDThe cardholder failed to provide the correct authentication details. Treat as potentially fraudulent.
AUTHENTICATION_TIMED_OUTAuthentication timed out, likely because the cardholder abandoned the transaction.
CARD_NOT_ENROLLEDThe card is not enrolled in 3DS and cannot be authenticated.
CHALLENGE_REQUIREDA challenge was required but the integration is configured to fail on challenge.
DIRECTORY_SERVER_UNAVAILABLEThe card network's directory server was unavailable. Retry later.
INVALID_ACQUIRERThe acquirer details provided are invalid.
INVALID_CARDThe card details are invalid.
PROTOCOL_ERRORA protocol error occurred during authentication.
REQUIRED_DATA_ELEMENT_MISSINGA required data element is missing from the authentication request.
SUSPECTED_FRAUDThe transaction was flagged as suspected fraud by the issuer.
TRANSACTION_CANCELLED_BY_CARDHOLDERThe cardholder explicitly cancelled the authentication challenge.
TRANSACTION_NOT_PERMITTEDThe transaction type is not permitted for this card.
TRANSIENT_SYSTEM_FAILUREA transient system failure occurred. Retry later.
UNSUPPORTED_3D_SECURE_VERSIONThe 3D Secure version required by the issuer is not supported.

Handling onFailure

Pattern-match on the error code to branch per failure mode. message is safe to surface directly to the buyer.

onFailure = { code ->
    when (code) {
        FinixErrorCode.NetworkError,
        FinixErrorCode.Timeout -> showError(code.message)
        FinixErrorCode.PaymentFailed -> showError(code.message)
        is FinixErrorCode.MissingConfiguration ->
            // Bug in the integration — missing field named by code.field
            logConfigurationError(code.field)
        is FinixErrorCode.ThreeDSFailed ->
            // No liability shift — do not charge
            showError(code.message)
        is FinixErrorCode.Unknown -> showError(code.message)
    }
}
sealed interface FinixErrorCode {
    val message: String

    data object NetworkError : FinixErrorCode {
        override val message = "Network error. Please check your connection."
    }

    data object Timeout : FinixErrorCode {
        override val message = "Request timed out. Please try again."
    }

    data object PaymentFailed : FinixErrorCode {
        override val message = "Payment failed. Please try again."
    }

    data class MissingConfiguration(val field: String) : FinixErrorCode {
        override val message = "3DS is enabled but required field '$field' is missing."
    }

    data class ThreeDSFailed(val failureCode: ThreeDSFailureCode?) : FinixErrorCode {
        override val message =
            failureCode?.failureMessage ?: "3DS authentication failed. Please try again."
    }

    data class Unknown(val detail: String = "") : FinixErrorCode {
        override val message = detail.ifEmpty { "An unexpected error occurred." }
    }
}

enum class ThreeDSFailureCode(val failureMessage: String) {
    ACCESS_CONTROL_SERVER_UNAVAILABLE(
        "The card issuer's authentication server was unavailable. Retry later."
    ),
    AUTHENTICATION_FAILED(
        "The cardholder failed to provide the correct authentication details. " +
            "This transaction should be considered potentially fraudulent."
    ),
    AUTHENTICATION_TIMED_OUT(
        "The authentication timed out, likely because the cardholder abandoned the transaction."
    ),
    CARD_NOT_ENROLLED(
        "The card is not enrolled in 3DS and cannot be authenticated."
    ),
    CHALLENGE_REQUIRED(
        "A challenge was required but the integration is configured to fail on challenge."
    ),
    DIRECTORY_SERVER_UNAVAILABLE(
        "The card network's directory server was unavailable. Retry later."
    ),
    INVALID_ACQUIRER(
        "The acquirer details provided are invalid."
    ),
    INVALID_CARD(
        "The card details are invalid."
    ),
    PROTOCOL_ERROR(
        "A protocol error occurred during the authentication process."
    ),
    REQUIRED_DATA_ELEMENT_MISSING(
        "A required data element is missing from the authentication request."
    ),
    SUSPECTED_FRAUD(
        "The transaction was flagged as suspected fraud by the issuer."
    ),
    TRANSACTION_CANCELLED_BY_CARDHOLDER(
        "The cardholder explicitly cancelled the authentication challenge."
    ),
    TRANSACTION_NOT_PERMITTED(
        "The transaction type is not permitted for this card."
    ),
    TRANSIENT_SYSTEM_FAILURE(
        "A transient system failure occurred. Retry later."
    ),
    UNSUPPORTED_3D_SECURE_VERSION(
        "The 3D Secure version required by the issuer is not supported."
    ),
}

onFailure = { code ->
    when (code) {
        FinixErrorCode.NetworkError,
        FinixErrorCode.Timeout -> showError(code.message)
        FinixErrorCode.PaymentFailed -> showError(code.message)
        is FinixErrorCode.MissingConfiguration ->
            // Bug in the integration — missing field named by code.field
            logConfigurationError(code.field)
        is FinixErrorCode.ThreeDSFailed ->
            // No liability shift — do not charge
            showError(code.message)
        is FinixErrorCode.Unknown -> showError(code.message)
    }
}