This documentation is intended to be used in conjunction with the Netcetera-provided 3DS SDK. For more information on the Netcetera SDK, refer to their Developer Documentation.

To start using the Netcetera 3DS SDK, contact our support team.

danger

3D Secure is an authentication protocol that aims to reduce fraud, increase cardholder security, and reduce merchant liability for chargebacks. It introduced a step in the transaction process where the customer is shown a screen hosted by or on behalf of their card issuer and is prompted to authenticate themselves, often via a password or similar information that is only known to the customer.

3DS version 2 is designed with the mobile checkout experience in mind by introducing new checkout flows that better suit customers paying on mobile with new authentication methods, such as biometrics, or the option of a fully frictionless flow by using a more comprehensive data set provided by the merchant to authenticate the customer without the need for their intervention.

This guide assumes that you've already created an access token and a single-use token.

info

Step 1: Check 3DS2 enrollment

To begin the 3D Secure authentication process, first check the version that the card supports. We maintain an up-to-date database of BIN ranges and the versions of 3D Secure they support.

@WorkerThread
fun checkEnrollment(cardToken: String) {
        val result = Secure3dService
            .checkEnrollment(tokenizedCard)
            .withCurrency(Currency)
            .withAmount(amount)
            .withAuthenticationSource(AuthenticationSource.MobileSDK)
            .execute(Constants.DEFAULT_GPAPI_CONFIG)
        if (result.enrolledStatus == "ENROLLED") {
            //Open  netcetera
        }   }
func checkEnrollment(_ token: String, completion: @escaping ThreeDSecureCompletion){
        tokenizedCard = CreditCardData()
        tokenizedCard.token = token
        
        Secure3dService
            .checkEnrollment(paymentMethod: tokenizedCard)
            .withCurrency(currency)
            .withAmount(amount)
            .execute(completion: completion)
    }
curl --location --request POST 'https://apis.sandbox.globalpay.com/ucp/authentications' \
--header 'X-GP-Version: 2021-03-22' \
--header 'Authorization: Bearer Ekxp4eG90Cvjpq25dVusrTIUdvA8' \
--header 'Content-Type: application/json' \
--data-raw '{
   "account_name": "transaction_processing",
   "reference": "reference-123",
   "channel": "CNP",
   "amount":"1000",
   "currency": "EUR",
   "country": "IE",
   "payment_method": {
      "id":"PMT_8d9e8792-e299-4d9a-a8d0-881aa05f32f8"
   },
   "notifications": {
      "challenge_return_url": "https://example.com/challengenotification",
      "three_ds_method_return_url": "https://example.com/methodnotification"
   }
}'

Message version logic

The Netcetera 3DS Mobile SDK differs from our other SDKs in that you must specify the 3D Secure 2 message version in the createTransaction method.This means that business logic should be implemented by the merchant to ensure that the highest possible message version is used during the authentication. To do so, you will want to utilize the highest common 3D Secure 2 supported version across the Directory Server (DS) and Access Control Server (ACS).

As we saw previously, the range of versions of 3D Secure 2 that are supported are returned in the Check Version response. This allows us to determine the highest supported values across both. For example, the DS may support the range of 2.1.0 through 2.3.0 and the ACS may only support 2.1.0 through 2.2.0. In this case, the message version we should use for the authentication is 2.2.0—the highest common version across both. This will ensure that customers are able to avail of the most up-to-date version that the card issuer and card schemes support.

Step 2: Initiate 3DS2 authentication

After calling the getAuthenticationRequestParameters method of the Netcetera 3DS Mobile SDK (provided by our partner, Netcetera), your application can now begin 3D Secure 2 authentication. 

Here, we’ve provided the required and recommended data to be sent in the POST to the authentication endpoint. This includes the billing and shipping details of the customer, at least one phone number, and the transaction details (amount, currency, and so on). We’ve also included the encoded device data obtained from the Netcetera 3DS Mobile SDK in addition to other SDK information.

 /**
     * Create a transaction using NetceteraSDK
     */
    fun createNetceteraTransaction(secureEcom: ThreeDSecure) {
        val transaction = ThreeDS2Service.createTransaction(
            getDsRidValuesForCard(),
            secureEcom.messageVersion
        )
        
        authenticateTransaction(secureEcom, transaction.authenticationRequestParameters)
    }




 /**
     * Authenticate request using the response from checkEnrolment and params from Netcetera Transaction
     */
    @WorkerThread
    fun authenticateTransaction(
        secureEcom: ThreeDSecure,
        netceteraParams: AuthenticationRequestParameters
    ) {
        val response = Secure3dService
            .initiateAuthentication(tokenizedCard, secureEcom)
            .withAuthenticationSource(AuthenticationSource.MobileSDK)
            .withAmount(amount)
            .withCurrency(Currency)
            .withStoredCredential(storedCredential)
            .withOrderCreateDate(DateTime.now())
            .withMobileData(MobileData().apply {
                applicationReference = netceteraParams.sdkAppID
                sdkTransReference = netceteraParams.sdkTransactionID
                referenceNumber = netceteraParams.sdkReferenceNumber
                sdkInterface = SdkInterface.Both
                encodedData = netceteraParams.deviceData
                maximumTimeout = 15
                ephemeralPublicKey = JsonDoc.parse(netceteraParams.sdkEphemeralPublicKey)
                setSdkUiTypes(*SdkUiType.values())
            })
            .execute(Constants.DEFAULT_GPAPI_CONFIG)
    }
 private func createTransaction(secureEcom: ThreeDSecure) {
        do {
            //10. Create transaction
            transaction = try threeDS2Service.createTransaction(directoryServerId: getDsRidCard(), messageVersion: secureEcom.messageVersion
            )
            
            //11. Get authentication Params
            if let netceteraParams = try transaction?.getAuthenticationRequestParameters(){
                authenticateTransaction(secureEcom, netceteraParams: netceteraParams)
            }
        } catch {
            view?.requestError(error)
        }
    }


 – Authenticate request using the response from checkEnrollment and params from Netcetera Transaction

func authenticateTransaction(_ secureEcom: ThreeDSecure, netceteraParams: AuthenticationRequestParameters ) {
        let mobileData = MobileData()
        mobileData.applicationReference = netceteraParams.getSDKAppID()
        mobileData.sdkTransReference = netceteraParams.getSDKTransactionId()
        mobileData.referenceNumber = netceteraParams.getSDKReferenceNumber()
        mobileData.sdkInterface = .both
        mobileData.encodedData = netceteraParams.getDeviceData()
        mobileData.maximumTimeout = 10
        mobileData.ephemeralPublicKey = JsonDoc.parse(netceteraParams.getSDKEphemeralPublicKey())
        mobileData.sdkUiTypes = SdkUiType.allCases
        
        Secure3dService
            .initiateAuthentication(paymentMethod: tokenizedCard, secureEcom: secureEcom)
            .withAuthenticationSource(.mobileSDK)
            .withAmount(amount)
            .withCurrency(currency)
            .withOrderCreateDate(Date.now)
            .withMobileData(mobileData)
            .execute { [weak self] threeDSecure, error in
                guard let threeDSecure = threeDSecure else {
                    if let error = error{
                        self?.view?.requestError(error)
                    }
                    return
                }
                self?.startChallengeFlow(threeDSecure)
            }
    }
curl --location --request POST 'https://apis.sandbox.globalpay.com/ucp/authentications/AUT_7d64214e-2e58-4496-91fe-f3ffa7e65a25/initiate' \
--header 'X-GP-Version: 2021-03-22' \
--header 'Authorization: Bearer Ekxp4eG90Cvjpq25dVusrTIUdvA8' \
--header 'Content-Type: application/json' \
--data-raw '{
    "three_ds": {
        "source": "MOBILE_SDK",
        "preference": "NO_PREFERENCE"
    },
    "mobile_data": {
        "application_reference": "f283b3ec-27da-42a1-acea-f3f70e75bbdc",
        "sdk_interface": "BOTH",
        "sdk_ui_type": [
            "TEXT",
            "SINGLE_SELECT",
            "MULTI_SELECT",
            "OOB",
            "HTML_OTHER"
        ],
        "ephemeral_public_key": {
            "kty": "EC",
            "crv": "P-256",
            "x": "WWcpTjbOqiu_1aODllw5rYTq5oLXE_T0huCPjMIRbkI",
            "y": "Wz_7anIeadV8SJZUfr4drwjzuWoUbOsHp5GdRZBAAiw"
        },
        "maximum_timeout": "05",
        "reference_number": "3DS_LOA_SDK_PPFU_020100_00007",
        "sdk_trans_reference": "b2385523-a66c-4907-ac3c-91848e8c0067",
        "encoded_data": "ew0KCSJEViI6ICIxLjAiLA0KCSJERCI6IHsNCgkJIkMwMDEiOiAiQW5kcm9pZCIsDQoJCSJDMDAyIjogIkhUQyBPbmVfTTgiLA0KCQkiQzAwNCI6ICI1LjAuMSIsDQoJCSJDMDA1IjogImVuX1VTIiwNCgkJIkMwMDYiOiAiRWFzdGVybiBTdGFuZGFyZCBUaW1lIiwNCgkJIkMwMDciOiAiMDY3OTc5MDMtZmI2MS00MWVkLTk0YzItNGQyYjc0ZTI3ZDE4IiwNCgkJIkMwMDkiOiAiSm9obidzIEFuZHJvaWQgRGV2aWNlIg0KCX0sDQoJIkRQTkEiOiB7DQoJCSJDMDEwIjogIlJFMDEiLA0KCQkiQzAxMSI6ICJSRTAzIg0KCX0sDQoJIlNXIjogWyJTVzAxIiwgIlNXMDQiXQ0KfQ0K"
    },
    "message_category": "PAYMENT_AUTHENTICATION",
    "account_name": "transaction_processing",
    "channel": "CNP",
    "amount": "1000",
    "currency": "EUR",
    "country": "IE",
    "payment_method": {
        "id": "PMT_794692a5-1e90-4fad-99a7-ed73c8c445cf"
    },
    "order": {
        "time_created_reference": "2019-04-26T10:19:32.552327Z",
        "amount": "1000",
        "currency": "EUR",
        "reference": "3400dd37-101d-4940-be15-3c963b6109b3",
        "address_match_indicator": "false",
        "shipping_address": {
            "line1": "Apartment 852",
            "line2": "Complex 741",
            "line3": "House 963",
            "city": "Chicago",
            "postal_code": "50001",
            "state": "IL",
            "country": "840"
        }
    },
    "payer": {
        "mobile_phone": {
            "country_code": "44",
            "subscriber_number": "123456789"
        },
        "billing_address": {
            "line1": "Flat 456",
            "line2": "House 456",
            "line3": "Unit 4",
            "city": "Halifax",
            "postal_code": "W5 9HR",
            "country": "826"
        }
    },
    "merchant_contact_url": "https://example.com/about"
}'

Step 3: Receive authentication response

At this point, the Issuer will analyze the transaction. It will take into account factors such as the data your application has provided along with historical customer behavior and transaction analysis. The outcome of this process will determine whether the Issuer decides that the customer must further authenticate the transaction or not: a Challenge flow. 

Alternatively, the Issuer can be satisfied that it has enough data to make a decision on whether the transaction should proceed or not and that no further authentication is required:a Frictionless flow

Frictionless flow

In a frictionless flow, the Issuer can determine that no further authentication is required and that the transaction qualifies for Strong Customer Authentication (SCA). Or, based on the information that it has received so far, that the transaction should not proceed any further.

Successful authentication response

{
    "id": "AUT_5dad4214-78a9-4003-a5a0-737ffa38181c",
    "time_created": "2022-05-16T17:14:16.631Z",
    "time_last_updated": "2022-05-16T17:14:00.398Z",
    "transaction_type": "SALE",
    "status": "SUCCESS_AUTHENTICATED",
    "channel": "CNP",
    "amount": "1000",
    "currency": "EUR",
    "country": "IE",
    "source": "MOBILE_SDK",
    "three_ds": {
        "server_trans_ref": "5dad4214-78a9-4003-a5a0-737ffa38181c",
        "acs_trans_ref": "9d8923c0-d53b-41ec-8bf1-40fafa3f1a10",
        "acs_reference_number": "3DS_LOA_ACS_INTE_020200_00293",
        "ds_trans_ref": "6ca331b5-f2da-4e77-9e2a-5d4bf12d7947",
        "eci": "05",
        "liability_shift": "YES",
        "status": "AUTHENTICATION_SUCCESSFUL",
        "status_reason": "MEDIUM_CONFIDENCE",
        "authentication_source": "MOBILE_SDK",
        "message_version": "2.2.0",
        "authentication_value": "AJkBAFBklgAAAAPol4E2dAAAAAA=",
        "cardholder_response_info": "",
        "message_category": "PAYMENT_AUTHENTICATION",
        "redirect_url": "",
        "acs_challenge_request_url": "",
        "challenge_status": "",
        "challenge_model": "",
        "session_data_field_name": "threeDSSessionData",
        "message_type": "creq",
        "challenge_value": ""
    },
    "notifications": {
        "challenge_return_url": "https://example.com/challengenotification"
    },
    "action": {
        "id": "ACT_HH6l88hux634HMF7llUFlIbmmTfj4e",
        "type": "INITIATE",
        "time_created": "2022-05-16T17:14:16.631Z",
        "result_code": "SUCCESS",
        "app_id": "grf9Q3tGYqglXOmYXYGAeYfFvsmnXAGe",
        "app_name": "hosted_fields"
    }
}

Failed authentication response

{
    "id": "AUT_af597950-3fd4-44f4-a216-e3ba7d29cdf1",
    "time_created": "2022-05-16T17:15:38.969Z",
    "time_last_updated": "2022-05-16T17:15:31.021Z",
    "transaction_type": "SALE",
    "status": "NOT_AUTHENTICATED",
    "channel": "CNP",
    "amount": "1000",
    "currency": "EUR",
    "country": "IE",
    "source": "MOBILE_SDK",
    "three_ds": {
        "server_trans_ref": "af597950-3fd4-44f4-a216-e3ba7d29cdf1",
        "acs_trans_ref": "ce9daf30-d53b-41ec-8bf1-40fafa3f1a12",
        "acs_reference_number": "3DS_LOA_ACS_INTE_020200_00293",
        "ds_trans_ref": "7dd3118e-e011-429e-88c2-0bf9321be7a8",
        "eci": "07",
        "liability_shift": "NO",
        "status": "AUTHENTICATION_FAILED",
        "status_reason": "CARD_AUTHENTICATION_FAILED",
        "authentication_source": "MOBILE_SDK",
        "message_version": "2.2.0",
        "authentication_value": "",
        "cardholder_response_info": "",
        "message_category": "PAYMENT_AUTHENTICATION",
        "redirect_url": "",
        "acs_challenge_request_url": "",
        "challenge_status": "",
        "challenge_model": "",
        "session_data_field_name": "threeDSSessionData",
        "message_type": "creq",
        "challenge_value": ""
    },
    "notifications": {
        "challenge_return_url": "https://example.com/challengenotification"
    },
    "action": {
        "id": "ACT_C17dvwchLykizW18dPcnyqOgC0B5DT",
        "type": "INITIATE",
        "time_created": "2022-05-16T17:15:38.969Z",
        "result_code": "SUCCESS",
        "app_id": "grf9Q3tGYqglXOmYXYGAeYfFvsmnXAGe",
        "app_name": "hosted_fields"
    }
}


Depending on the outcome, your application can now either proceed to authorization or display a message to the customer telling them their transaction was unsuccessful and return them to the payment page.

Challenge flow

In the challenge flow, the Issuer determines that further authentication is required for the transaction to proceed. This may be due to various reasons, including a high value transaction, unusual payment behavior for this particular customer (time of day, type of merchant, and so on) or mismatching/insufficient data was submitted for them to make a determination.

In the response, we pass the required data for the Netcetera 3DS Mobile SDK to interact with the ACS to either present the challenge natively or display the relevant HTML.

Challenge response

{
   "id": "AUT_7d64214e-2e58-4496-91fe-f3ffa7e65a25",
   "time_created": "2022-05-16T16:58:17.190Z",
   "time_last_updated": "2022-05-16T15:12:19.671Z",
   "transaction_type": "SALE",
   "status": "CHALLENGE_REQUIRED",
   "channel": "CNP",
   "amount": "1000",
   "currency": "EUR",
   "country": "IE",
   "source": "MOBILE_SDK",
   "three_ds": {
      "server_trans_ref": "7d64214e-2e58-4496-91fe-f3ffa7e65a25",
      "acs_trans_ref": "61a5f100-d539-41ec-8bf1-40fafa3f19eb",
      "acs_reference_number": "3DS_LOA_ACS_INTE_020200_00293",
      "ds_trans_ref": "743a8197-1c73-4c5c-888d-7df369e01f50",
      "eci": "",
      "liability_shift": "",
      "status": "CHALLENGE_REQUIRED",
      "status_reason": "",
      "authentication_source": "MOBILE_SDK",
      "message_version": "2.2.0",
      "authentication_value": "",
      "cardholder_response_info": "",
      "message_category": "PAYMENT_AUTHENTICATION",
      "redirect_url": "https://apis.sandbox.globalpay.com/ucp/authentications/redirect/eyJpZCI6IkFVVF83ZDY0MjE0ZS0yZTU4LTQ0OTYtOTFmZS1mM2ZmYTdlNjVhMjUiLCJtZXJjaGFudF9tYW5hZ2VtZW50X2lkIjpudWxsLCJtZXJjaGFudF9pZCI6Ik1FUl83ZTNlMmM3ZGYzNGY0MjgxOWIzZWRlZTMxMDIyZWUzZiIsImFjY291bnRfaWQiOiJUUkFfYzk5NjdhZDdkOGVjNGI0NmI2ZGQ0NGE2MWNkZTlhOTEiLCJtZXJjaGFudF9uYW1lIjoiU2FuZGJveF9tZXJjaGFudF8zIiwiYWNjb3VudF9uYW1lIjoidHJhbnNhY3Rpb25fcHJvY2Vzc2luZyIsImFjc191cmwiOm51bGwsIm1lc3NhZ2VfdmVyc2lvbiI6IjIuMS4wIiwiYXBwX2lkIjoiZ3JmOVEzdEdZcWdsWE9tWVhZR0FlWWZGdnNtblhBR2UiLCJhcHBfbmFtZSI6Imhvc3RlZF9maWVsZHMiLCJhcHBfZGV2ZWxvcGVyIjoiamFzb24uYmFqYXJpYXNAZ2xvYmFscGF5LmNvbSJ9",
      "acs_challenge_request_url": "",
      "challenge_status": "MANDATED",
      "challenge_model": "OUT_OF_BAND_CHALLENGE",
      "session_data_field_name": "threeDSSessionData",
      "message_type": "creq",
      "challenge_value": "ewogICJtZXNzYWdlVHlwZSIgOiAiQ1JlcSIsCiAgIm1lc3NhZ2VWZXJzaW9uIiA6ICIyLjEuMCIsCiAgInRocmVlRFNTZXJ2ZXJUcmFuc0lEIiA6ICI3ZDY0MjE0ZS0yZTU4LTQ0OTYtOTFmZS1mM2ZmYTdlNjVhMjUiLAogICJhY3NUcmFuc0lEIiA6ICI2MWE1ZjEwMC1kNTM5LTQxZWMtOGJmMS00MGZhZmEzZjE5ZWIiLAogICJjaGFsbGVuZ2VXaW5kb3dTaXplIiA6ICIwNCIKfQ",
      "mobile_data": {
         "acs_signed_content": "eyJhbGciOiJQUzI1NiIsIng1YyI6WyJ…Truncated For Readability…DgjonzRLLwWjtxLksjnvwL6tw9qR-QndX9YgAefFog6auSqkm44IOAKYSQ",
         "acs_rendering_type": {
            "acs_interface": "NATIVE",
            "acs_ui_template": "OUT_OF_BAND"
         }
      }
   },
   "notifications": {
      "challenge_return_url": "https://example.com/challengenotification"
   },
   "action": {
      "id": "ACT_4aooc0Sz4vpUU2lApb4GhavmRJ6c81",
      "type": "INITIATE",
      "time_created": "2022-05-16T16:58:17.190Z",
      "result_code": "SUCCESS",
      "app_id": "grf9Q3tGYqglXOmYXYGAeYfFvsmnXAGe",
      "app_name": "hosted_fields"
   }
}

 

Response syntax (Netcetera 3DS Mobile SDK specific fields only)

Element/Field Format Description
acs_reference_number String Unique identifier assigned by the EMVCo for the particular ACS.
acs_signed_content String Encrypted string that contains the following data necessary to present the challenge to the customer:

ACS URL
ACS Ephemeral Public Key (QT)
SDK Ephemeral Public Key (QC)

acs_rendering_type Object Identifies the ACS UI Template that the ACS will first present to the customer.
acs_interface Enum The ACS interface that the challenge will present to the cardholder. Possible values:

NATIVE
HTML

acs_ui_template String Identifies the UI Template format that the ACS first presents to the customer. Possible values:

TEXT
SINGLE_SELECT
MULTI_SELECT
OOB
HTML_OTHER

Step 4: Present the challenge to the customer

The type of challenge displayed by the Netcetera 3DS Mobile SDK to the customer will be determined by the Issuer ACS and will align with at least two elements of Strong Customer Authentication:

  • Possession â€“ Something only the customer has; for example, their mobile device registered with their bank to which they will receive a code in a SMS
  • Inherence – Something only the customer is; for example, their fingerprint or other form of biometric data
  • Knowledge – Something only the customer knows; for example, a unique passphrase or answer to a personal question

Sample ACS

Sample ACS

With the customer on the ACS, the following outcomes may occur:

  • The authentication is successful
    (Transaction Status = Y & Challenge Completion Indicator = Y)
  • The authentication fails and the customer is not given another chance
    (Transaction Status = N & Challenge Completion Indicator = Y)
  • The authentication fails and the customer is given another chance

Step 5: Obtain the authentication data

If the transaction qualifies as authenticated (Transaction Status = Y), the final step before processing the authorization is to obtain the necessary authentication data from our 3DS solution. This is the data the ACS passed to us when the customer completed the challenge.

To do this, we call the Obtain Result endpoint with the relevant Authentication ID. For example: 

https://apis.sandbox.globalpay.com/ucp/authentications/{ID}/result

https://apis.sandbox.globalpay.com/ucp/authentications/AUT_5dad4214-78a9-4003-a5a0-737ffa38181c/result

If the customer canceled during the challenge or the authentication did not proceed for another reason, the summary endpoint will also provide you with the information available so you can update your application or website accordingly. The most important information we need for the authorization is the ECI and Authentication Value.

Sample successful authentication response

{
   "id": "AUT_5dad4214-78a9-4003-a5a0-737ffa38181c",
   "time_created": "2022-05-16T17:18:37.443",
   "status": "SUCCESS_AUTHENTICATED",
   "channel": "CNP",
   "amount": "1000",
   "currency": "EUR",
   "country": "IE",
   "source": "MOBILE_SDK",
   "three_ds": {
      "acs_trans_ref": "9d8923c0-d53b-41ec-8bf1-40fafa3f1a10",
      "ds_trans_ref": "6ca331b5-f2da-4e77-9e2a-5d4bf12d7947",
      "server_trans_ref": "5dad4214-78a9-4003-a5a0-737ffa38181c",
      "acs_reference_number": "",
      "liability_shift": "YES",
      "authentication_type": "",
      "authentication_value": "AJkBAFBklgAAAAPol4E2dAAAAAA=",
      "eci": "05",
      "status": "AUTHENTICATION_SUCCESSFUL",
      "status_reason": "MEDIUM_CONFIDENCE",
      "redirect_url": "",
      "acs_challenge_request_url": "",
      "authentication_source": "MOBILE_SDK",
      "challenge_value": "",
      "message_category": "PAYMENT_AUTHENTICATION",
      "message_version": "2.2.0",
      "challenge_status": "NOT_MANDATED",
      "authentication_request_type": "",
      "acs_decoupled_response_indicator": "",
      "whitelist_status": "",
      "message_extension": []
   },
   "action": {
      "id": "ACT_njv5YFcRRjQgIxzTF88L8qghIiPpEb",
      "type": "GET_CHALLENGE_RESULT",
      "time_created": "2022-05-16T17:18:37.443",
      "result_code": "SUCCESS",
      "app_id": "grf9Q3tGYqglXOmYXYGAeYfFvsmnXAGe",
      "app_name": "hosted_fields"
   }
}

Step 6: Process the authorization

Now that the 3D Secure process is complete, we can proceed to authorization and include the authentication data. The transaction will be processed as normal and may be successful or declined based on standard criteria: sufficient funds, correct security code entered, and so on.

@WorkerThread
    fun doAuth(serverTransactionId: String) {
        val response = Secure3dService
            .getAuthenticationData()
            .withServerTransactionId(serverTransactionId)
            .execute(Secure3dVersion.TWO, Constants.DEFAULT_GPAPI_CONFIG)

        tokenizedCard.threeDSecure = response
        chargeMoney()
    }

    @WorkerThread
    fun chargeMoney() {
        val response = tokenizedCard.charge(amount)
            .withCurrency(Currency)
            .execute(Constants.DEFAULT_GPAPI_CONFIG)
    }
  func doAuth(serverTransactionId: String) {
        Secure3dService
            .getAuthenticationData()
            .withServerTransactionId(serverTransactionId)
            .execute { [weak self] threeDSecure, error in
                guard let threeDSecure = threeDSecure else {
                    if let error = error{
                        self?.view?.requestError(error)
                    }
                    return
                }
                self?.tokenizedCard.threeDSecure = threeDSecure
                self?.chargeMoney()
            }
    }
    
    private func chargeMoney() {
        tokenizedCard.charge(amount: amount)
            .withCurrency(currency)
            .execute(completion: { [weak self] transaction, error in
                guard let _ = transaction else {
                    if let error = error {
                        self?.view?.requestError(error)
                    }
                    return
                }
                self?.view?.requestSuccess("Transaction Completed")
            })
    }
curl --location --request POST 'https://apis.sandbox.globalpay.com/ucp/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Ekxp4eG90Cvjpq25dVusrTIUdvA8' \
--header 'Accept: application/json' \
--header 'X-GP-Version: 2021-03-22' \
--data-raw '{
   "account_name": "transaction_processing",
   "channel": "CNP",
   "type": "SALE",
   "amount": "1000",
   "currency": "EUR",
   "reference": "Transaction_123",
   "country": "IE",
   "payment_method": {
      "name": "James Mason",
      "entry_mode": "ECOM",
      "id": "PMT_8d9e8792-e299-4d9a-a8d0-881aa05f32f8",
      "authentication": {
         "message_version": "2.2.0",
         "eci": "05",
         "value": "AJkBAFBklgAAAAPol4E2dAAAAAA=",
         "ds_trans_reference": "6ca331b5-f2da-4e77-9e2a-5d4bf12d7947",
         "server_trans_reference": "5dad4214-78a9-4003-a5a0-737ffa38181c"
      }
   }
}'
Internal Title
REST API
Show Content Nav
On
Tags
Subtitle
Authenticate customers within an app.