--- title: "iOS 3D Secure 2 SDK" description: "Support 3D Secure 2 authentication on your iOS app." url: "https://docs.adyen.com/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/ios-sdk-integration" source_url: "https://docs.adyen.com/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/ios-sdk-integration.md" canonical: "https://docs.adyen.com/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/ios-sdk-integration" last_modified: "2023-07-14T14:34:00+02:00" language: "en" --- # iOS 3D Secure 2 SDK Support 3D Secure 2 authentication on your iOS app. [View source](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/ios-sdk-integration.md) **Adyen is no longer developing the Classic API integration** This page is for the Classic API (`/authorise`) integration, which we no longer accept new integrations with. We strongly recommend migrating to the newer [Native 3D Secure 2 for iOS](/online-payments/3d-secure/native-3ds2/ios) integration. To use this newer integration, you must also [migrate to the Checkout API](/online-payments/upgrade-your-integration/migrate-to-checkout-api). ##### PSD2 compliance If you are implementing 3D Secure to comply with PSD2 SCA, learn more from our [comprehensive guide](/online-payments/psd2-sca-compliance-and-implementation-guide). The [Adyen 3DS2 iOS SDK](https://github.com/Adyen/adyen-3ds2-ios) gets the device fingerprint and presents the challenge to your shopper. From your server, you need to send a payment request, the encrypted device fingerprint, and the challenge result to Adyen. In a full 3D Secure 2 implementation, a payment can go through either a [frictionless](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2#frictionless-flow) or a [challenge](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2#challenge-flow) authentication flow before it can be authorised. If you only want to perform a 3D Secure 2 authentication and then authorise the payment later, refer to the [Authentication-only](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/authentication-only-integration) documentation. ### How it works Here's how a 3D Secure 2 challenge authentication flow works: [![](/user/pages/docs/02.online-payments/60.classic-integrations/01.classic-api-integration/03.3d-secure-authentication/09.native-3ds2/02.ios-sdk-integration/3ds2-ios.png)](/user/pages/docs/02.online-payments/60.classic-integrations/01.classic-api-integration/03.3d-secure-authentication/09.native-3ds2/02.ios-sdk-integration/3ds2-ios.png) 1. [Submit a payment request](#submit-a-payment-request) with the required 3D Secure 2 objects to start the authentication process. Build your implementation depending on the `resultCode` returned in the response. If the transaction is exempted from 3D Secure, you might get an **Authorised** result code. 2. If you receive an **IdentifyShopper** `resultCode`, [get the 3D Secure 2 device fingerprint](#get-the-3d-secure-2-device-fingerprint) and send the encrypted device fingerprint information to Adyen. After you send the device fingerprint, it is possible that you receive an **Authorised**`resultCode` in the response. This means that the 3D Secure 2 authentication was frictionless, and the payment was authorised. 3. If you receive **ChallengeShopper**`resultCode`, this means that the issuer requires further shopper interaction and you need to [present a challenge to the shopper](#present-a-challenge). The payment might also be [routed to 3D Secure 1](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2#3d-secure-1-fallback), based on issuer performance. This is indicated by a **RedirectShopper** `resultCode`. If you do not want to automatically fall back to 3D Secure 1, contact our [Support Team](https://ca-test.adyen.com/ca/ca/contactUs/support.shtml?form=other). To test your integration, see [Testing 3D Secure 2](#testing-3d-secure-2). ## Before you begin ##### Adyen 3DS2 iOS Subscribe to our [GitHub repository](https://github.com/Adyen/adyen-3ds2-ios) to get the latest updates and versions. Before you begin to integrate, make sure you have followed the [Get started with Adyen guide](/get-started-with-adyen) to: * Get an overview of the steps needed to accept live payments. * Create your test account. After you have created your test account: 1. [Get your API Key](/development-resources/api-credentials#generate-api-key). Save a copy, because you'll need it for API calls you make to the Adyen payments platform. 2. Install one of our [Libraries](/development-resources/libraries) to connect with the Adyen APIs. 3. Install the [Adyen 3DS2 iOS SDK latest version](https://github.com/Adyen/adyen-3ds2-ios). You must use version 2.3.0 or later to trigger the 3D Secure 2 native flow. You can install the SDK through CocoaPods, Carthage, or by manually installing the SDK as a dynamic or static framework. ### Tab: CocoaPods 1. Add pod `'Adyen3DS2'` to your Podfile. 2. Run `pod install`. ### Tab: Carthage 1. Add `github "adyen/adyen-3ds2-ios"` to your `Cartfile`. 2. Run `carthage update`. 3. Link the framework with your target as described in [Carthage Readme](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application). ### Tab: Dynamic or static framework **Install manually as a dynamic framework** 1. In Xcode, drag the dynamic XCFramework/Dynamic/Adyen3DS2.xcframework to the **Frameworks, Libraries, and Embedded Content** section in your General Target settings. Select **Copy items if needed** when asked. **Install manually as a static framework** 1. In Xcode, select **File** > **Add Files to...**. 2. Select the static `Adyen3DS2.framework` and check **Copy items if needed**, then select **Add**. 3. In Xcode, select **File** > **Add Files to...**. 4. Select **Adyen3DS2.bundle** inside **Adyen3DS2.framework** and check **Copy items if needed**, then select **Add**. ### Tab: Swift Package Manager Use Xcode 12.0 or later when adding Adyen 3D Secure 2 using Swift Package Manager. 1. Follow [Apple's instructions](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app) to add a Swift Package dependency. 2. Use `https://github.com/Adyen/adyen-3ds2-ios` as the repository URL. 3. Specify version **2.2.1.** or later. ## Step 1: Submit a payment request Collect your shopper's card details then make a payment with a POST [/authorise](https://docs.adyen.com/api-explorer/#/Payment/authorise) request, and include the following: | Parameter name | Required | Description | | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [card](https://docs.adyen.com/api-explorer/#/Payment/latest/post/authorise__reqParam_card) | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | Object that contains the shopper's card details. | | [threeDS2RequestData.deviceChannel](https://docs.adyen.com/api-explorer/Payment/latest/post/authorise#request-threeDS2RequestData-deviceChannel) | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | Set to **app**. | | [browserInfo](https://docs.adyen.com/api-explorer/#/Payment/latest/post/authorise__reqParam_browserInfo) | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | Object that contains the `userAgent` and `acceptHeader` fields. Indicates that your integration can handle [3D Secure 1 redirect authentication](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/3d-secure-1) in case the transaction is [routed to 3D Secure 1](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2#3d-secure-1-fallback). If your integration is unable to generate this information, you can send the same data as in the request below. | | [sdkVersion](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/ios-sdk-integration#get-the-sdk-version) | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | We recommend you use the `ADY3DS2SDKVersion()` function to determine your 3DS2 sdkVersion. You can also get the sdkVersion from [Github](https://github.com/Adyen/adyen-3ds2-ios) | You can send [additional parameters](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/api-reference-3d-secure-2#3d-secure-2-additional-parameters) for better authorization rates, and to increase the chance of a frictionless flow. You do not have to send all the additional parameters. Send parameters that you know you can provide accurately, or that are mandatory in specific scenarios. Here is an example of how to make a request for a **EUR 150** purchase: #### curl ```bash curl https://pal-test.adyen.com/pal/servlet/Payment/v68/authorise \ -H 'x-api-key: ADYEN_API_KEY' \ -H 'content-type: application/json' \ -d '{ "amount":{ "currency":"EUR", "value":15000 }, "merchantAccount":"YOUR_MERCHANT_ACCOUNT", "reference":"YOUR_ORDER_NUMBER", "threeDS2RequestData":{ "deviceChannel":"app", "{hint:Required to trigger native. Get your sdkVersion and send it here. Do not hard code your sdkVersion.}sdkVersion{/hint}": "STATE_DATA" }, "card":{ "cvc":"737", "expiryMonth":"03", "expiryYear":"2030", "holderName":"Simon Hopper", "number":"4917610000000000" }, "{hint:Required for 3D Secure 1}browserInfo{/hint}": { "userAgent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1", "acceptHeader":"text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8" } }' ``` #### Java ```java // Adyen Java API Library v26.3.0 import com.adyen.Client; import com.adyen.enums.Environment; import com.adyen.model.payment.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.service.*; Client client = new Client("ADYEN_API_KEY", Environment.TEST); // Create the request object(s) Amount amount = new Amount() .currency("EUR") .value(15000L); ThreeDS2RequestData threeDS2RequestData = new ThreeDS2RequestData() .sdkVersion("STATE_DATA") .deviceChannel("app"); Card card = new Card() .cvc("737") .number("4917610000000000") .holderName("Simon Hopper") .expiryMonth("03") .expiryYear("2030"); BrowserInfo browserInfo = new BrowserInfo() .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8") .userAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1"); PaymentRequest paymentRequest = new PaymentRequest() .reference("YOUR_ORDER_NUMBER") .amount(amount) .merchantAccount("YOUR_MERCHANT_ACCOUNT") .threeDS2RequestData(threeDS2RequestData) .card(card) .browserInfo(browserInfo); // Send the request paymentApi service = new paymentApi(client); PaymentResult response = service.authorise(paymentRequest, null); ``` #### PHP ```php // Adyen PHP API Library v18.2.1 use Adyen\Client; use Adyen\Environment; use Adyen\Model\Payments\Amount; use Adyen\Model\Payments\ThreeDS2RequestData; use Adyen\Model\Payments\Card; use Adyen\Model\Payments\BrowserInfo; use Adyen\Model\Payments\PaymentRequest; use Adyen\Service\Payments\PaymentsApi; $client = new Client(); $client->setXApiKey("ADYEN_API_KEY"); $client->setEnvironment(Environment::TEST); // Create the request object(s) $amount = new Amount(); $amount ->setCurrency("EUR") ->setValue(15000); $threeDS2RequestData = new ThreeDS2RequestData(); $threeDS2RequestData ->setSdkVersion("STATE_DATA") ->setDeviceChannel("app"); $card = new Card(); $card ->setCvc("737") ->setNumber("4917610000000000") ->setHolderName("Simon Hopper") ->setExpiryMonth("03") ->setExpiryYear("2030"); $browserInfo = new BrowserInfo(); $browserInfo ->setAcceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8") ->setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1"); $paymentRequest = new PaymentRequest(); $paymentRequest ->setReference("YOUR_ORDER_NUMBER") ->setAmount($amount) ->setMerchantAccount("YOUR_MERCHANT_ACCOUNT") ->setThreeDS2RequestData($threeDS2RequestData) ->setCard($card) ->setBrowserInfo($browserInfo); // Send the request $service = new PaymentsApi($client); $response = $service->authorise($paymentRequest); ``` #### C\# ```cs // Adyen .net API Library v17.0.0 using Adyen; using Environment = Adyen.Model.Environment; using Adyen.Model; using Adyen.Model.Payment; using Adyen.Service; var config = new Config() { XApiKey = "ADYEN_API_KEY", Environment = Environment.Test }; var client = new Client(config); // Create the request object(s) Amount amount = new Amount { Currency = "EUR", Value = 15000 }; ThreeDS2RequestData threeDS2RequestData = new ThreeDS2RequestData { SdkVersion = "STATE_DATA", DeviceChannel = "app" }; Card card = new Card { Cvc = "737", Number = "4917610000000000", HolderName = "Simon Hopper", ExpiryMonth = "03", ExpiryYear = "2030" }; BrowserInfo browserInfo = new BrowserInfo { AcceptHeader = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1" }; PaymentRequest paymentRequest = new PaymentRequest { Reference = "YOUR_ORDER_NUMBER", Amount = amount, MerchantAccount = "YOUR_MERCHANT_ACCOUNT", ThreeDS2RequestData = threeDS2RequestData, Card = card, BrowserInfo = browserInfo }; // Send the request var service = new PaymentService(client); var response = service.Authorise(paymentRequest); ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v17.3.0 // Require the parts of the module you want to use const { Client, PaymentAPI } = require('@adyen/api-library'); // Initialize the client object const client = new Client({apiKey: "ADYEN_API_KEY", environment: "TEST"}); // Create the request object(s) const paymentRequest = { amount: { currency: "EUR", value: 15000 }, merchantAccount: "YOUR_MERCHANT_ACCOUNT", reference: "YOUR_ORDER_NUMBER", threeDS2RequestData: { deviceChannel: "app", sdkVersion: "STATE_DATA" }, card: { cvc: "737", expiryMonth: "03", expiryYear: "2030", holderName: "Simon Hopper", number: "4917610000000000" }, browserInfo: { userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1", acceptHeader: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" } } // Send the request const paymentAPI = new PaymentAPI(client); const response = paymentAPI.authorise(paymentRequest); ``` #### Go ```go // Adyen Go API Library v10.4.0 import ( "context" "github.com/adyen/adyen-go-api-library/v9/src/common" "github.com/adyen/adyen-go-api-library/v9/src/adyen" "github.com/adyen/adyen-go-api-library/v9/src/payments" ) client := adyen.NewClient(&common.Config{ ApiKey: "ADYEN_API_KEY", Environment: common.TestEnv, }) // Create the request object(s) amount := payments.Amount{ Currency: "EUR", Value: 15000, } threeDS2RequestData := payments.ThreeDS2RequestData{ SdkVersion: common.PtrString("STATE_DATA"), DeviceChannel: "app", } card := payments.Card{ Cvc: common.PtrString("737"), Number: common.PtrString("4917610000000000"), HolderName: common.PtrString("Simon Hopper"), ExpiryMonth: common.PtrString("03"), ExpiryYear: common.PtrString("2030"), } browserInfo := payments.BrowserInfo{ AcceptHeader: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", UserAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1", } paymentRequest := payments.PaymentRequest{ Reference: "YOUR_ORDER_NUMBER", Amount: amount, MerchantAccount: "YOUR_MERCHANT_ACCOUNT", ThreeDS2RequestData: &threeDS2RequestData, Card: &card, BrowserInfo: &browserInfo, } // Send the request service := client.Payments() req := service.PaymentsApi.AuthoriseInput().PaymentRequest(paymentRequest) res, httpRes, err := service.PaymentsApi.Authorise(context.Background(), req) ``` #### Python ```py # Adyen Python API Library v12.5.1 import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "ADYEN_API_KEY" adyen.client.platform = "test" # The environment to use library in. # Create the request object(s) json_request = { "amount": { "currency": "EUR", "value": 15000 }, "merchantAccount": "YOUR_MERCHANT_ACCOUNT", "reference": "YOUR_ORDER_NUMBER", "threeDS2RequestData": { "deviceChannel": "app", "sdkVersion": "STATE_DATA" }, "card": { "cvc": "737", "expiryMonth": "03", "expiryYear": "2030", "holderName": "Simon Hopper", "number": "4917610000000000" }, "browserInfo": { "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1", "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" } } # Send the request result = adyen.payment.payments_api.authorise(request=json_request) ``` #### Ruby ```rb # Adyen Ruby API Library v9.5.1 require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'ADYEN_API_KEY' adyen.env = :test # Set to "live" for live environment # Create the request object(s) request_body = { :amount => { :currency => 'EUR', :value => 15000 }, :merchantAccount => 'YOUR_MERCHANT_ACCOUNT', :reference => 'YOUR_ORDER_NUMBER', :threeDS2RequestData => { :deviceChannel => 'app', :sdkVersion => 'STATE_DATA' }, :card => { :cvc => '737', :expiryMonth => '03', :expiryYear => '2030', :holderName => 'Simon Hopper', :number => '4917610000000000' }, :browserInfo => { :userAgent => 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1', :acceptHeader => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' } } # Send the request result = adyen.payment.payments_api.authorise(request_body) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v17.3.0 // Require the parts of the module you want to use import { Client, PaymentAPI, Types } from "@adyen/api-library"; // Initialize the client object const client = new Client({apiKey: "ADYEN_API_KEY", environment: "TEST"}); // Create the request object(s) const amount: Types.payment.Amount = { currency: "EUR", value: 15000 }; const threeDS2RequestData: Types.payment.ThreeDS2RequestData = { sdkVersion: "STATE_DATA", deviceChannel: "app" }; const card: Types.payment.Card = { cvc: "737", number: "4917610000000000", holderName: "Simon Hopper", expiryMonth: "03", expiryYear: "2030" }; const browserInfo: Types.payment.BrowserInfo = { acceptHeader: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1" }; const paymentRequest: Types.payment.PaymentRequest = { reference: "YOUR_ORDER_NUMBER", amount: amount, merchantAccount: "YOUR_MERCHANT_ACCOUNT", threeDS2RequestData: threeDS2RequestData, card: card, browserInfo: browserInfo }; // Send the request const paymentAPI = new PaymentAPI(client); const response = paymentAPI.authorise(paymentRequest); ``` []() You receive a response containing a `resultCode` of: *  **IdentifyShopper**. This means that you need to perform the [Identify the shopper](#get-the-3d-secure-2-device-fingerprint) flow. You also get the following parameters from the response, which you'll need to create a transaction in the SDK: * `additionalData.threeds2.threeDS2DirectoryServerInformation.directoryServerId` * `additionalData.threeds2.threeDS2DirectoryServerInformation.publicKey` * `additionalData.threeds2.threeDS2ResponseData.messageVersion` * `additionalData.threeds2.threeDS2DirectoryServerInformation.rootCertificates` You will also receive a `threeds2.threeDS2Token` which you will need to store for later use. To optimize authorization rates, Adyen's [Authentication Engine](https://www.adyen.com/knowledge-hub/psd2-simplified-with-our-new-authentication-engine) routes each payment to either the 3D Secure 2 or the 3D Secure 1 flow, based on issuer performance. See [3D Secure fallback](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2#3d-secure-1-fallback) for more information. For a complete list of `resultCode` values and the actions you need to take, see [Result codes](/online-payments/payment-result-codes). Here's an example of a response showing an **IdentifyShopper** result code: **Response with IdentifyShopper** ```json { "additionalData": { "threeds2.threeDSServerTransID": "055fadfb-9fe4-4e70-99f0-9b8935bf1eb2", "threeds2.threeDS2DirectoryServerInformation.algorithm": "RSA", "threeds2.threeDS2ResponseData.messageVersion" : "2.1.0", "threeds2.threeDS2Token": "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...", "threeds2.threeDS2DirectoryServerInformation.directoryServerId": "A000000003", "threeds2.threeDS2DirectoryServerInformation.publicKey": "eyJrdHkiOiJSU0EiLCJlIjoiQVFBQiIsIm4iOiI4VFBxZkFQ==...", "threeds2.threeDS2DirectoryServerInformation.rootCertificates": "........" }, "pspReference": "8835495304426403", "resultCode": "IdentifyShopper" } ``` ## Step 2: Get the 3D Secure 2 device fingerprint If your server receives **IdentifyShopper** `resultCode`, start the 3D Secure 2 device fingerprinting process. 1. In your app, create an instance of [ `ADYServiceParameters` ](https://adyen.github.io/adyen-3ds2-ios/2.3.1/documentation/adyen3ds2/adyserviceparameters)passing the `directoryServerId` and the `publicKey` parameters from the `/authorise` [response](#payment-response-params) or from your [prefetched cached keys](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/browser-based-integration#optional-prefetch-device-fingerprinting-keys). ```swift ADYServiceParameters *parameters = [ADYServiceParameters new]; [parameters setDirectoryServerIdentifier:...]; // Retrieved from /authorise response. [parameters setDirectoryServerPublicKey:...]; // Retrieved from /authorise response. [parameters setDirectoryServerRootCertificates:...]; // Retrieved from /authorise response. ``` 2. Use the [`ADYService` ](https://adyen.github.io/adyen-3ds2-ios/2.3.1/documentation/adyen3ds2/adyservice)class to create a transaction. When using [Adyen 3DS2 iOS SDK version 2.2.0 and later](https://github.com/Adyen/adyen-3ds2-ios/releases/tag/2.2.0), you must set `transactionWithMessageVersion` to the value of `additionalData.threeds2.threeDS2ResponseData.messageVersion` from the `/authorise` response.\ For more information about the latest version, refer to [Migrating to 3DS2 SDK version 2.2.0](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/migrating-to-2-2). Keep a reference to your `ADYTransaction` instance until the transaction is complete. The following example shows how to create a transaction, using the `messageVersion`. **Create a transaction in the SDK** ```swift [ADYService serviceWithParameters:parameters appearanceConfiguration:nil completionHandler:^(ADYService *service) { NSError *error = nil; // We've set threedsMessageVersion to the value of additionalData.threeds2.threeDS2ResponseData.messageVersion ADYTransaction *transaction = [service transactionWithMessageVersion:threedsMessageVersion error:&error]; if (transaction) { ADYAuthenticationRequestParameters *authenticationRequestParameters = [transaction authenticationRequestParameters]; // Submit the authenticationRequestParameters to /authorise3ds2. } else { // An error occurred. } }]; ``` 4) Get the transaction's `authenticationRequestParameters`  class and pass the contents to your server.\ You'll get the following information: * `deviceInformation` * `SDKTransactionIdentifier` * `SDKApplicationIdentifier` * `SDKReferenceNumber` * `SDKEphemeralPublicKey` 5) From your server, make a POST [/authorise3ds2](https://docs.adyen.com/api-explorer/#/Payment/authorise3ds2) request to send the encrypted device fingerprint information to Adyen, specifying the [threeDS2RequestData](https://docs.adyen.com/api-explorer/Payment/latest/post/authorise3ds2#request-threeDS2RequestData) object containing: * `sdkEncData`: Device information * `sdkTransID`: SDK Transaction Identifier * `sdkAppID`: SDK Application Identifier * `sdkReferenceNumber`: SDK Reference Number * `sdkEphemPubKey`: Object that contains the SDK Ephemeral Public Key. The SDK provides output as a string. Transform this string into a JSON object to send in your [/authorise3ds2](https://docs.adyen.com/api-explorer/#/Payment/authorise3ds2) request. Also make sure you include the `threeds2.threeDS2Token` that was returned in the previous request. You can send [additional parameters](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/api-reference-3d-secure-2#3d-secure-2-additional-parameters) for better authorization rates, and to increase the chance of a frictionless flow. You do not have to send all the additional parameters. Send parameters that you know you can provide accurately, or that are mandatory in specific scenarios. **Send device fingerprint to Adyen** #### curl ```bash curl https://pal-test.adyen.com/pal/servlet/Payment/v68/authorise3ds2 \ -H 'x-api-key: ADYEN_API_KEY' \ -H 'content-type: application/json' \ -d '{ "merchantAccount": "YOUR_MERCHANT_ACCOUNT", "threeDS2Token": "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...", "threeDS2RequestData": { "deviceChannel": "app", "sdkAppID": "9063b12c-fcde-43c7-b28e-8d0af5520e8a", "sdkEncData": "", "sdkEphemPubKey": { "crv": "P-256", "kty": "EC", "x": "LYImJkRzS92vogM6AUPCBhJ20VagSe8IL0Q9SdisUSo", "y": "Rav4sKHnLUIUHVdyR4dyV7G2_EeAnuCn_6621ZhqZYU" }, "sdkReferenceNumber": "3DS_LOA_SDK_ADBV_739485_94783", "sdkTransID": "b60c9879-ac77-4918-a317-7b01c4317053/8Q==.." } }' ``` #### Java ```java // Adyen Java API Library v32.0.0 import com.adyen.Client; import com.adyen.enums.Environment; import com.adyen.model.payment.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.service.*; Client client = new Client("ADYEN_API_KEY", Environment.TEST); // Create the request object(s) // Send the request paymentApi service = new paymentApi(client); PaymentResult response = service.authorise3ds2(paymentRequest3ds2, null); ``` #### PHP ```php setXApiKey("ADYEN_API_KEY"); $client->setEnvironment(Environment::TEST); // Create the request object(s) // Send the request $service = new PaymentsApi($client); $response = $service->authorise3ds2($paymentRequest3ds2); ``` #### C\# ```cs // Adyen .net API Library v26.0.0 using Adyen; using Environment = Adyen.Model.Environment; using Adyen.Model; using Adyen.Model.Payment; using Adyen.Service; var config = new Config() { XApiKey = "ADYEN_API_KEY", Environment = Environment.Test }; var client = new Client(config); // Create the request object(s) // Send the request var service = new PaymentService(client); var response = service.Authorise3ds2(paymentRequest3ds2); ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v22.1.0 // Require the parts of the module you want to use const { Client, PaymentAPI } = require('@adyen/api-library'); const client = new Client({ apiKey: "ADYEN_API_KEY", environment: "TEST" }); // Create the request object(s) const paymentRequest3ds2 = { merchantAccount: "YOUR_MERCHANT_ACCOUNT", threeDS2Token: "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...", threeDS2RequestData: { deviceChannel: "app", sdkAppID: "9063b12c-fcde-43c7-b28e-8d0af5520e8a", sdkEncData: "", sdkEphemPubKey: { crv: "P-256", kty: "EC", x: "LYImJkRzS92vogM6AUPCBhJ20VagSe8IL0Q9SdisUSo", y: "Rav4sKHnLUIUHVdyR4dyV7G2_EeAnuCn_6621ZhqZYU" }, sdkReferenceNumber: "3DS_LOA_SDK_ADBV_739485_94783", sdkTransID: "b60c9879-ac77-4918-a317-7b01c4317053/8Q==.." } } // Send the request const paymentAPI = new PaymentAPI(client); const response = paymentAPI.authorise3ds2(paymentRequest3ds2); ``` #### Go ```go // Adyen Go API Library v16.1.0 import ( "context" "github.com/adyen/adyen-go-api-library/v9/src/common" "github.com/adyen/adyen-go-api-library/v9/src/adyen" "github.com/adyen/adyen-go-api-library/v9/src/payments" ) client := adyen.NewClient(&common.Config{ ApiKey: "ADYEN_API_KEY", Environment: common.TestEnv, }) // Create the request object(s) // Send the request service := client.Payments() req := service.PaymentsApi.Authorise3ds2Input().PaymentRequest3ds2(paymentRequest3ds2) res, httpRes, err := service.PaymentsApi.Authorise3ds2(context.Background(), req) ``` #### Python ```py # Adyen Python API Library v13.2.0 import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "ADYEN_API_KEY" adyen.client.platform = "test" # The environment to use library in. # Create the request object(s) json_request = { "merchantAccount": "YOUR_MERCHANT_ACCOUNT", "threeDS2Token": "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...", "threeDS2RequestData": { "deviceChannel": "app", "sdkAppID": "9063b12c-fcde-43c7-b28e-8d0af5520e8a", "sdkEncData": "", "sdkEphemPubKey": { "crv": "P-256", "kty": "EC", "x": "LYImJkRzS92vogM6AUPCBhJ20VagSe8IL0Q9SdisUSo", "y": "Rav4sKHnLUIUHVdyR4dyV7G2_EeAnuCn_6621ZhqZYU" }, "sdkReferenceNumber": "3DS_LOA_SDK_ADBV_739485_94783", "sdkTransID": "b60c9879-ac77-4918-a317-7b01c4317053/8Q==.." } } # Send the request result = adyen.payment.payments_api.authorise3ds2(request=json_request) ``` #### Ruby ```rb # Adyen Ruby API Library v10.1.0 require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'ADYEN_API_KEY' adyen.env = :test # Set to "live" for live environment # Create the request object(s) request_body = { :merchantAccount => 'YOUR_MERCHANT_ACCOUNT', :threeDS2Token => 'BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...', :threeDS2RequestData => { :deviceChannel => 'app', :sdkAppID => '9063b12c-fcde-43c7-b28e-8d0af5520e8a', :sdkEncData => '', :sdkEphemPubKey => { :crv => 'P-256', :kty => 'EC', :x => 'LYImJkRzS92vogM6AUPCBhJ20VagSe8IL0Q9SdisUSo', :y => 'Rav4sKHnLUIUHVdyR4dyV7G2_EeAnuCn_6621ZhqZYU' }, :sdkReferenceNumber => '3DS_LOA_SDK_ADBV_739485_94783', :sdkTransID => 'b60c9879-ac77-4918-a317-7b01c4317053/8Q==..' } } # Send the request result = adyen.payment.payments_api.authorise3ds2(request_body) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v22.1.0 // Require the parts of the module you want to use import { Client, PaymentAPI, Types } from "@adyen/api-library"; const client = new Client({ apiKey: "ADYEN_API_KEY", environment: "TEST" }); // Create the request object(s) // Send the request const paymentAPI = new PaymentAPI(client); const response = paymentAPI.authorise3ds2(paymentRequest3ds2); ``` []() You receive a response containing a `resultCode`. Some of the possible values for `resultCode` are: * **Authorised** – Indicates that the 3D Secure 2 authentication was frictionless, and the payment authorisation was successfully completed. This means that you can already proceed with the delivery of goods and services.  * **ChallengeShopper** – The issuer has requested further shopper interaction. This means that you'll have to perform the [challenge flow](#present-a-challenge). You also get the following parameters from the response, which you'll need to start the challenge flow in the SDK: * `threeds2.threeDS2ResponseData.threeDSServerTransID` * `threeds2.threeDS2ResponseData.acsTransID` * `threeds2.threeDS2ResponseData.acsReferenceNumber` * `threeds2.threeDS2ResponseData.acsSignedContent` * `threeds2.threeDS2Token` For a complete list of `resultCode` values and the actions that you need to take, see [Result codes](/online-payments/payment-result-codes). Here's an example of a challenge flow response: **Response showing ChallengeShopper** ```json { "additionalData": { "threeds2.threeDS2ResponseData.acsSignedContent": "eyJhbGciOiJQUzI1NiIsIngPVEFOQmdrcWhraUc5dtw4I-RBJ8_OUt8yIZEsoc...", "threeds2.threeDS2ResponseData.transStatus": "C", "threeds2.threeDS2ResponseData.acsChallengeMandated": "Y", "threeds2.threeDS2ResponseData.acsURL": "https://pal-test.adyen.com/threeds2simulator/services/ThreeDS2Simulator/v1/handle/83e78317-e73f-4a6f-j738-7hj09p07n178", "threeds2.threeDS2ResponseData.threeDSServerTransID": "930h2k09-1986-4hl2-800a-c8d7783918bf", "threeds2.threeDS2ResponseData.authenticationType": "01", "threeds2.threeDS2ResponseData.messageVersion": "2.1.0", "threeds2.threeDS2Token": "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...", "threeds2.threeDS2ResponseData.acsTransID": "45e79886-e60c-4c6d-a962-7aa43d59b150", "threeds2.threeDS2ResponseData.acsReferenceNumber": "ADYEN-ACS-SIMULATOR" }, "pspReference": "8825495326513370", "resultCode": "ChallengeShopper" } ``` ## Step 3: Present a challenge If your server receives **ChallengeShopper** `resultCode`, this means that the issuer would like to perform additional checks in order to verify that the shopper is indeed the cardholder. 1. Create an instance of [`ADYChallengeParameters` ](https://adyen.github.io/adyen-3ds2-ios/2.3.1/documentation/adyen3ds2/adychallengeparameters)and pass the following: * The values from the `/authorise3ds2` [response](#authorise3ds2-response). * `threeDSRequestorAppURL`: Supported in 3D Secure version 2.2.0 and later. By regulation, it is required to provide your app's URL in universal link format:`[NSURL URLWithString:@"https://{YOUR_UNIVERSAL_URL}"]`. In an [out-of-band (OOB) authentication](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/migrating-to-2-2#supported), the authenticating app uses this URL to call your app after an OOB authentication occurs. If you specified a previous version of 3D Secure in [step 2](#get-the-3d-secure-2-device-fingerprint), this parameter is ignored. For more information about the latest version, refer to [Migrating to 3DS2 SDK version 2.2.0](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2/migrating-to-2-2). Make sure to add the URL should to the app build settings. Go to **Info.plist** > **URL Types**. For more information, refer to the [Apple Developer documentation](https://developer.apple.com/documentation/uikit/inter-process_communication/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app). **Create instance of ADYChallengeParameters** ```swift NSDictionary *additionalData = ...; // Retrieved from Adyen. ADYChallengeParameters *parameters = [ADYChallengeParameters challengeParametersWithServerTransactionIdentifier:additionalData[@"threeds2.threeDS2ResponseData.threeDSServerTransID"] threeDSRequestorAppURL: [NSURL URLWithString:@"https://{YOUR_UNIVERSAL_URL}"] ACSTransactionIdentifier:additionalData[@"threeds2.threeDS2ResponseData.acsTransID"] ACSReferenceNumber:additionalData[@"threeds2.threeDS2ResponseData.acsReferenceNumber"] ACSSignedContent:additionalData[@"threeds2.threeDS2ResponseData.acsSignedContent"]]; ``` 2. Present the challenge. **Perform the challenge flow** ```swift [transaction performChallengeWithParameters:parameters completionHandler:^(ADYChallengeResult *result, NSError *error) { if (result) { NSString *transactionStatus = [result transactionStatus]; // Submit the transactionStatus to /authorise3ds2. } else { // An error occurred. } }]; ``` 3. When the challenge flow has been completed, get the `transactionStatus` from the `result` and pass this to your server. 4. From your server, make a POST [/authorise3ds2](https://docs.adyen.com/api-explorer/#/Payment/authorise3ds2) request specifying the `transStatus` generated by the SDK and the `threeds2.threeDS2Token`. **Send challenge result** #### curl ```bash curl https://pal-test.adyen.com/pal/servlet/Payment/v68/authorise3ds2 \ -H 'x-api-key: ADYEN_API_KEY' \ -H 'content-type: application/json' \ -d '{ "merchantAccount": "YOUR_MERCHANT_ACCOUNT", "threeDS2Result": { "transStatus": "Y" }, "threeDS2Token": "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+..." }' ``` #### Java ```java // Adyen Java API Library v26.3.0 import com.adyen.Client; import com.adyen.enums.Environment; import com.adyen.model.payment.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.service.*; Client client = new Client("ADYEN_API_KEY", Environment.TEST); // Create the request object(s) ThreeDS2Result threeDS2Result2 = new ThreeDS2Result() .transStatus("Y"); PaymentRequest3ds2 paymentRequest3ds2 = new PaymentRequest3ds2() .threeDS2Result(threeDS2Result2) .threeDS2Token("BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...") .merchantAccount("YOUR_MERCHANT_ACCOUNT"); // Send the request paymentApi service = new paymentApi(client); PaymentResult response = service.authorise3ds2(paymentRequest3ds2, null); ``` #### PHP ```php // Adyen PHP API Library v18.2.1 use Adyen\Client; use Adyen\Environment; use Adyen\Model\Payments\ThreeDS2Result; use Adyen\Model\Payments\PaymentRequest3ds2; use Adyen\Service\Payments\PaymentsApi; $client = new Client(); $client->setXApiKey("ADYEN_API_KEY"); $client->setEnvironment(Environment::TEST); // Create the request object(s) $threeDS2Result2 = new ThreeDS2Result(); $threeDS2Result2 ->setTransStatus("Y"); $paymentRequest3ds2 = new PaymentRequest3ds2(); $paymentRequest3ds2 ->setThreeDS2Result($threeDS2Result2) ->setThreeDS2Token("BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...") ->setMerchantAccount("YOUR_MERCHANT_ACCOUNT"); // Send the request $service = new PaymentsApi($client); $response = $service->authorise3ds2($paymentRequest3ds2); ``` #### C\# ```cs // Adyen .net API Library v17.0.0 using Adyen; using Environment = Adyen.Model.Environment; using Adyen.Model; using Adyen.Model.Payment; using Adyen.Service; var config = new Config() { XApiKey = "ADYEN_API_KEY", Environment = Environment.Test }; var client = new Client(config); // Create the request object(s) ThreeDS2Result threeDS2Result2 = new ThreeDS2Result { TransStatus = "Y" }; PaymentRequest3ds2 paymentRequest3ds2 = new PaymentRequest3ds2 { ThreeDS2Result = threeDS2Result2, ThreeDS2Token = "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...", MerchantAccount = "YOUR_MERCHANT_ACCOUNT" }; // Send the request var service = new PaymentService(client); var response = service.Authorise3ds2(paymentRequest3ds2); ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v17.3.0 // Require the parts of the module you want to use const { Client, PaymentAPI } = require('@adyen/api-library'); // Initialize the client object const client = new Client({apiKey: "ADYEN_API_KEY", environment: "TEST"}); // Create the request object(s) const paymentRequest3ds2 = { merchantAccount: "YOUR_MERCHANT_ACCOUNT", threeDS2Result: { transStatus: "Y" }, threeDS2Token: "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+..." } // Send the request const paymentAPI = new PaymentAPI(client); const response = paymentAPI.authorise3ds2(paymentRequest3ds2); ``` #### Go ```go // Adyen Go API Library v10.4.0 import ( "context" "github.com/adyen/adyen-go-api-library/v9/src/common" "github.com/adyen/adyen-go-api-library/v9/src/adyen" "github.com/adyen/adyen-go-api-library/v9/src/payments" ) client := adyen.NewClient(&common.Config{ ApiKey: "ADYEN_API_KEY", Environment: common.TestEnv, }) // Create the request object(s) threeDS2Result2 := payments.ThreeDS2Result{ TransStatus: common.PtrString("Y"), } paymentRequest3ds2 := payments.PaymentRequest3ds2{ ThreeDS2Result: &threeDS2Result2, ThreeDS2Token: common.PtrString("BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+..."), MerchantAccount: "YOUR_MERCHANT_ACCOUNT", } // Send the request service := client.Payments() req := service.PaymentsApi.Authorise3ds2Input().PaymentRequest3ds2(paymentRequest3ds2) res, httpRes, err := service.PaymentsApi.Authorise3ds2(context.Background(), req) ``` #### Python ```py # Adyen Python API Library v12.5.1 import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "ADYEN_API_KEY" adyen.client.platform = "test" # The environment to use library in. # Create the request object(s) json_request = { "merchantAccount": "YOUR_MERCHANT_ACCOUNT", "threeDS2Result": { "transStatus": "Y" }, "threeDS2Token": "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+..." } # Send the request result = adyen.payment.payments_api.authorise3ds2(request=json_request) ``` #### Ruby ```rb # Adyen Ruby API Library v9.5.1 require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'ADYEN_API_KEY' adyen.env = :test # Set to "live" for live environment # Create the request object(s) request_body = { :merchantAccount => 'YOUR_MERCHANT_ACCOUNT', :threeDS2Result => { :transStatus => 'Y' }, :threeDS2Token => 'BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...' } # Send the request result = adyen.payment.payments_api.authorise3ds2(request_body) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v17.3.0 // Require the parts of the module you want to use import { Client, PaymentAPI, Types } from "@adyen/api-library"; // Initialize the client object const client = new Client({apiKey: "ADYEN_API_KEY", environment: "TEST"}); // Create the request object(s) const threeDS2Result2: Types.payment.ThreeDS2Result = { transStatus: "Y" }; const paymentRequest3ds2: Types.payment.PaymentRequest3ds2 = { threeDS2Result: threeDS2Result2, threeDS2Token: "BQABAQC2LEWucYNwQRzhH9c1/hup5ZZa9HUehFbwdC86PAfhpGJ/+...", merchantAccount: "YOUR_MERCHANT_ACCOUNT" }; // Send the request const paymentAPI = new PaymentAPI(client); const response = paymentAPI.authorise3ds2(paymentRequest3ds2); ``` You receive **Authorised** as the `resultCode` if the payment was successful.  **Response** ```json { "additionalData": { "liabilityShift": "true", "authCode": "44402", "avsResult": "4 AVS not supported for this card type", "threeDOffered": "true", "refusalReasonRaw": "AUTHORISED", "authorisationMid": "1000", "acquirerAccountCode": "TestPmmAcquirerAccount", "cvcResult": "1 Matches", "avsResultRaw": "4", "threeDAuthenticated": "true", "cvcResultRaw": "M", "acquirerCode": "TestPmmAcquirer", "acquirerReference": "7CASOGMCCB4" }, "pspReference": "8825495331860022", "resultCode": "Authorised", "authCode": "44402" } ``` ## UI customizations The SDK inherits your app's theme to ensure the UI of the challenge flow fits your app's look and feel. If you require further UI customizations, the SDK provides some customization options through the `ADYAppearanceConfiguration` class.  To customize the UI: * Create an instance of `ADYAppearanceConfiguration`, configure the [UI elements](#customizable-ui-elements) that you want to customize, and pass the configuration instance when you initialize `ADYService`.\ For example, to change the color of the  **Continue** button to red and to change its corner radius: **Customize Continue button** ```swift ADYAppearanceConfiguration *appearanceConfiguration = [ADYAppearanceConfiguration new]; [[appearanceConfiguration buttonAppearanceForButtonType:ADYAppearanceButtonTypeContinue] setBackgroundColor:[UIColor redColor]]; [[appearanceConfiguration buttonAppearanceForButtonType:ADYAppearanceButtonTypeContinue] setTextColor:[UIColor whiteColor]]; [[appearanceConfiguration buttonAppearanceForButtonType:ADYAppearanceButtonTypeContinue] setCornerRadius:3.0f]; [ADYService transactionWithParameters:parameters appearanceConfiguration:appearanceConfiguration completionHandler:...]; ``` ### Customizable UI elements Refer to [ADYAppearanceConfiguration](https://adyen.github.io/adyen-3ds2-ios/2.3.1/documentation/adyen3ds2/adyappearanceconfiguration) class reference documentation for a complete list of customizable properties. You can also customize the following UI elements used in the challenge flow: | Customizable elements | Customizable properties | | --------------------------- | --------------------------------------------------------------------------- | | Body | * Font * Font color * Line height | | Header | - Font - Font color - Line height | | Info items | * Font * Font color * Line height * Border color | | Input fields | - Font - Font color - Separator color - Keyboard appearance | | Input fields header | * Font * Font color | | Navigation bar | - Background color - Status bar style | | Screen | * Background color | | Submit/Next/Continue button | - Font - Text transform - Font color - Background color - Corner radius | | Cancel button | * Font * Text transform * Font color | | Resend button | - Font - Text transform - Text color | | OOB button | * Font * Text transform * Text color | ## Get the SDK version **Get the current SDK version** ```swift NSString* threeDS2SDKVersion = ADY3DS2SDKVersion(); let threeDS2SDKVersion = ADY3DS2SDKVersion() ``` ## Testing 3D Secure 2 Before going live, use the following card numbers and credentials to test your integration. We recommend testing each **Card Type**. To test how your integration handles different 3D Secure 2 authentication scenarios, use our test card numbers. All our test cards use the following expiry dates and security codes: | Expiry Date | CVC/CVV | CID | | ----------- | ------- | ---- | | 03/2030 | 737 | 7373 | When prompted for 3D Secure 2 text challenges, use the following credentials: * For mobile, use password: **1234** * For web, use password: **password** | Card Type | Card Number | | ------------------- | ------------------- | | Cartes Bancaires | 4035 5014 2814 6300 | | Maestro [1](#nocvc) | 5000 5500 0000 0029 | | Mastercard | 5454 5454 5454 5454 | | Visa | 4917 6100 0000 0000 | []()1 This card doesn't require a CVC. When you make a payment request with these cards, you'll receive the following result codes depending on your integration: * **RedirectShopper**: You'll receive this result code if you are using the [Redirect authentication](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/3d-secure-1). * **IdentifyShopper**: You'll receive this result code if you are using the [Native authentication](/online-payments/classic-integrations/classic-api-integration/3d-secure-authentication/native-3ds2). * **ChallengeShopper**: You might get this result code after you submit the 3D Secure 2 device fingerprinting result in a Native authentication, indicating a challenge flow. To test the web-based flow where the device fingerprinting step is skipped (because the issuer's ACS has not configured a `threeDSMethodURL`), and you get a **ChallengeShopper** `resultCode` *immediately* after submitting the payment request, use the following card: | Card Type | Card Number | | --------- | ------------------- | | Visa | 4212 3456 7891 0006 | To test the frictionless flow, specify in your payment request: * `amount.value`: **12002** #### App-based integration To test different authentication scenarios for app-based integration, use the following test cards: | Card number | Authentication scenario | | ------------------- | ------------------------------------------ | | 5201 2855 6567 2311 | Basic text authentication | | 5201 2874 9905 2008 | Basic single select | | 5201 2815 9233 1633 | Basic multi select | | 5201 2888 2269 6974 | Basic out-of-band (OOB) authentication | | 5201 2895 0084 3268 | HTML OOB authentication | | 5201 2861 5377 1465 | App single select then text authentication | #### Other scenarios | Card number | Scenario | | ------------------- | ---------------------------------------------------- | | 4199 3500 0000 0002 | The card is not enrolled for 3D Secure transactions, | | 5201 2829 9900 5515 | There was a technical error. | ## See also * [iOS SDK on GitHub](https://github.com/Adyen/adyen-3ds2-ios)