Search

Are you looking for test card numbers?

Would you like to contact support?

Default icon

Helper functions

Simplify your 3D Secure 2 API implementation with our helper functions.

Use our helper functions to:

  • Collect browser info and store data in properties required in the EMVCo specifications.
  • Perform base64url encoding and decoding.
  • Create an iframe with an onload event listener for the 3D Secure 2 device fingerprinting and challenge results.
  • Create a form with a target attribute to send the issuer requests for 3D Secure 2 device fingerprinting and the challenge.
  • Configure the challenge window size according to the EMVCo specifications.

Before you begin

Before you can start accepting 3D Secure 2 authenticated transactions, make sure that you:

  1. Sign up for an Adyen test account at https://www.adyen.com/signup
  2. Get your API Key. Save a copy as you'll need it for API calls you make to the Adyen payments platform.
  3. Install one of our Libraries to connect with the Adyen APIs. For more information on these steps, refer to Get started with Adyen.
  4. Read and understand the API-only integration guide. You should already know how to collect shopper information, either with the Card component or with your own payment form implementation.
  5. Set up your notification URLs. The issuer will send an HTTP POST containing the 3D Secure 2 device fingerprinting process and the challenge result to these URLs.

    • YOUR_3DS_METHOD_NOTIFICATION_URL: Absolute URL to where the issuer can post the result of the 3D Secure device fingerprinting process. 
    • YOUR_3DS_NOTIFICATION_URL: Absolute URL to where the issuer can post a base64url encoded Challenge Response (CRes) message, containing the challenge result.
  6. Import our helper functions by:

    • Cloning our repository from https://github.com/Adyen/adyen-3ds2-js-utils and importing the files into your project. 

      import collectBrowserInfo from "./browser";
      import base64Url from "./base64url";
      import createIframe from "./iframe";
      import createForm from "./form";
      import {validateChallengeWindowSize, getChallengeWindowSize} from "./config.js";
    • Or by building the file, hosting it, and then embedding it in your page. 

      <script type="text/javascript" src="YOUR_PATH/threeds2-js-utils.js">

Collect the shopper's browser information

The browserInfo object is required when submitting a 3D Secure 2 payment request. To get the required values for the transaction, use the collectBrowserInfo function. Pass on the values to your server.

const browserInf = collectBrowserInfo();
const requestObj =
{
    browserInfo         : {
        "acceptHeader"  : "TO BE ADDED BY SERVER",
        "colorDepth"    : browserInf.colorDepth,
        "javaEnabled"   : browserInf.javaEnabled,
        "language"      : browserInf.language,
        "screenHeight"  : browserInf.screenHeight,
        "screenWidth"   : browserInf.screenWidth,
        "timeZoneOffset": browserInf.timeZoneOffset,
        "userAgent"     : browserInf.userAgent
};

Submit a payment request

Submit a payment request with a POST /payments call. Include the additionalDatathreeDS2RequestData, and browserInfo objects to indicate that you are ready to accept 3D Secure 2 payments.

  • channel: web
  • allow3DS2true
  • browserInfo: Collect information about your shopper's browser.
  • notificationURLYOUR_3DS_NOTIFICATION_URL
To increase the likelihood of achieving a frictionless flow and higher authorisation rates, we also recommend that you send additional parameters in this list.
Request
curl https://checkout-test.adyen.com/v66/payments \
-H "X-API-key: [Your API Key here]" \
-H "Content-Type: application/json" \
-d '{
   "amount":{
      "currency":"EUR",
      "value":1500
   },
   "merchantAccount":"YOUR_MERCHANT_ACCOUNT",
   "reference":"TEST",
   "channel": "web",
   "threeDS2RequestData": {
      "notificationURL":"YOUR_3DS_NOTIFICATION_URL"
   },
   "additionalData" : {
    "allow3DS2": "true"
   },
    "returnUrl":"https://your-company.com/checkout/",
    "browserInfo":{
      "userAgent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.110 Safari\/537.36",
      "acceptHeader":"text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8",
      "language":"en",
      "colorDepth":24,
      "screenHeight":723,
      "screenWidth":1536,
      "timeZoneOffset":0,
      "javaEnabled":false
  },
   "paymentMethod":{
       "type":"scheme",
      "encryptedCardNumber":"adyenjs_0_1_18$MT6ppy0FAMVMLH...",
      "encryptedExpiryMonth":"adyenjs_0_1_18$MT6ppy0FAMVMLH...",
      "encryptedExpiryYear":"adyenjs_0_1_18$MT6ppy0FAMVMLH...",
      "encryptedSecurityCode":"adyenjs_0_1_18$MT6ppy0FAMVMLH..."
  },
 "reference":"YOUR_ORDER_NUMBER"
}'
Response

You'll receive a response containing:

Some issuers are not yet ready to support 3D Secure 2, or have better authorization rates for 3D Secure 1. To optimize authorization rates, Adyen's Authentication Engine routes each payment to either the 3D Secure 2 or the 3D Secure 1 flow, based on issuer performance. To handle this scenario, make sure that you have implemented the redirect authentication flow.

 For other possible resultCodes, and the actions that you need to take, see the Result codes.

{
  "resultCode": "IdentifyShopper",
  "authentication": {
    "threeds2.fingerprintToken": "eyJ0aHJlZURTTWV0aG9kVXJsIjoiaHR0cHM6XC9cL..."
  },
  "details": [
    {
      "key": "threeds2.fingerprint",
      "type": "text"
    }
  ],
  "paymentData": "YOUR_PAYMENT_DATA"
}

Get the 3D Secure 2 device fingerprint

If your server receives an  IdentifyShopper resultCode, you are required to perform the 3D Secure 2 device fingerprinting.

  1. Base64 decode the threeds2.fingerprintToken from the /payments response. 

    {
       "threeDSMethodUrl":"https:\/\/pal-test.adyen.com\/threeds2simulator\/acs\/startMethod.shtml",
       "threeDSServerTransID":"c9f82ec0-9e24-4f79-834d-6f8282de92fa"
    }
  2. Create objects and pass on the values of threeDSServerTransID and YOUR_3DS_METHOD_NOTIFICATION_URL. Next, use helper functions to base64url encode the data, create an iframe, and create a form that will send an HTTP POST to the threeDSMethodURL.

    const perform3DSDeviceFingerprint = (responseData) =>
    {
        const serverTransactionID = responseData.['threeDSServerTransID'];
        const threeDSMethodURL = responseData.['threeDSMethodURL'];
        const threedsContainer = document.getElementById('threedsContainer');
        const dataObj = {
            threeDSServerTransID : serverTransactionID,
            threeDSMethodNotificationURL : YOUR_3DS_METHOD_NOTIFICATION_URL
        };
        const stringifiedDataObject = JSON.stringify(dataObj);
        // Encode data
        const base64URLencodedData = base64Url.encode(stringifiedDataObject);
        const IFRAME_NAME = 'threeDSMethodIframe';
    
        // Create hidden iframe
        const iframe = createIframe(threedsContainer, IFRAME_NAME, '0', '0');
        // Create a form that will use the iframe to POST data to the threeDSMethodURL
        const form =  createForm('threedsMethodForm', threeDSMethodURL, IFRAME_NAME, 'threeDSMethodData', base64URLencodedData);
        threedsContainer.appendChild(form);
        setTimeout( function () {
            threedsContainer.removeChild( form );
        }, 1000 );
        form.submit();
    };
  3. Wait for the issuer's response posted in your YOUR_3DS_METHOD_NOTIFICATION_URL within 10 seconds from sending the HTTP POST. If do not get any response within 10 seconds, proceed to the next step.

     {"threeDSServerTransID":"f8062b92-66e9-4c5a-979a-f465e66a6e48"}

    To trigger your front end to remove the iframe after your notification URL receives a response or after 10 seconds has elapsed, see Handling the communication from notification URLs to your front end.

  4. Make a POST  /payments/details request from your server and include the threeds2.fingerprint and the paymentData objects as parameters.

    • threeds2.fingerprint: Pass a base64 encoded {"threeDSCompInd":"Y"}.
    • paymentData: Pass the paymentData from the initial payment response.

    If you received a response to YOUR_3DS_METHOD_NOTIFICATION_URL within 10 seconds, send {"threeDSCompInd": "Y"} in a base64url encoded format. Otherwise, send {"threeDSCompInd": "N"}.

Request
{
  "details": {
    "threeds2.fingerprint": "base64urlencoded_threeDSCompInd"
  },
  "paymentData": "YOUR_PAYMENT_DATA..."
}
Response

You'll receive a response containing a resultCode:

  • Authorised – Indicates that the 3D Secure 2 authentication was frictionless, and the payment authorisation was successfully completed. This state serves as an indicator to proceed with the delivery of goods and services. 
  • ChallengeShopper – The issuer has requested further verification of the shopper. See Challenge flow.

For other possible resultCodes and the actions that you need to take, see Result codes.

{
  "resultCode": "ChallengeShopper",
  "authentication": {
    "threeds2.challengeToken": "eyJ0aH..."
  },
  "details": [
    {
      "key": "threeds2.challengeResult",
      "type": "text"
    }
  ],
  "paymentData": "YOUR_PAYMENT_DATA"
}

Present a challenge

If your server receives a 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. Base64 decode the threeds2.challengeToken from the /payments response.

    {
      "acsReferenceNumber":"ADYEN-ACS-SIMULATOR",
      "acsTransID":"c9051915-57b0-4079-816c-6bbf1e29acc9",
      "acsURL":"https:\/\/pal-test.adyen.com\/threeds2simulator\/acs\/challenge.shtml",
      "messageVersion":"2.1.0",
      "threeDSNotificationURL":"https:\/\/test.com",
      "threeDSServerTransID":"24f8457e-dac9-404a-86dc-5c5b8b76d831"
    }
  2. Create a cReqData object and pass on the values of threeDSServerTransIDacsTransIDmessageVersion, and challengeWindowSize

    Set the challengeWindowSize to any of the following specifications:

    identifier size
    01 250px x 400px
    02 390px x 400px
    03 500px x 600px
    04 600px x 400px
    05 100% x 100%

    Next, base64url encode the CReq message, create an iframe, and to create a form that will send an HTTP POST to the acsURL.

    const perform3DSChallenge = (responseData) =>
     {
        const challengeWindowSize = validateChallengeWindowSize('04');// Corresponds to a 600px x 400px iframe size
    
        // Extract the ACS hosted url that will provide the content for the challenge iframe
        const acsURL = ['acsURL'];
    
        // Collate the data required to make a cReq
        const cReqData = {
            threeDSServerTransID : responseData.['threeDSServerTransID'],
            acsTransID : responseData.['acsTransID'],
            messageVersion : responseData.['messageVersion'],
            messageType : 'CReq',
            challengeWindowSize
        };
    
        const stringifiedDataObject = JSON.stringify(cReqData);
    
        // Encode data
        const base64URLencodedData = base64Url.encode(stringifiedDataObject);
    
        const IFRAME_NAME = 'threeDSChallengeIframe';
    
        const threedsContainer = document.getElementById('threedsContainer');
    
        const iframeSizesArr = getChallengeWindowSize(challengeWindowSize);
    
        // Create iframe with challenge window dimensions
        const iframe = createIframe(threedsContainer, IFRAME_NAME, iframeSizesArr[0], iframeSizesArr[1]);
    
        // Create a form that will use the iframe to POST data to the acsURL
        const form =  createForm('cReqForm', acsURL, IFRAME_NAME, 'creq', base64URLencodedData);
    
        threedsContainer.appendChild(form);
    
        setTimeout( function () {
            threedsContainer.removeChild( form );
        }, 1000 );
    
        form.submit();
    };
  3. Wait for the issuer's response which will be posted to YOUR_3DS_NOTIFICATION_URL within 10 minutes from sending the HTTP POST. The response will contain the Challenge Response (CRes) in a base64url encoded format. If you do not get a response within 10 minutes, proceed to the next step.

    {"cres":"eyJtZXNzYWdlVHlwZSI6IkNSZXMiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMS4wIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiI1ZWY2MzBiMC03NmQwLTRmY2It..."}

    Base64url decode the response and get the transStatus value. 

    {
      "messageType":"CRes",
      "messageVersion":"2.1.0",
      "threeDSServerTransID":"5ef630b0-76d0-4fcb-8a17-c81ecc86cff7",
      "acsTransID":"1f1bb4cc-05c9-49d0-a82c-e587c914a37b",
      "acsUiType":"01",
      "challengeCompletionInd":"Y",
      "transStatus":"Y"
    }

    To trigger your front end to remove the iframe after your notification URL receives a response or after 10 minutes has elapsed, see Handling the communication from notification URLs to your front end.

  4. Make a POST  /payments/details request from your server and include the details and the paymentData objects as parameters.
  • threeds2.challengeResult: Base64 encode the transStatus from the previous step and pass it to this parameter. For example, pass a base64 encoded {"transStatus": "Y"}.
  • paymentData: This is the paymentData from the latest API response, either from the /payments or from the /payments/details response if you are proceeding from the device fingerprinting flow.

If you do not receive a response in YOUR_3DS_NOTIFICATION_URL within 10 minutes, assume that something went wrong or the shopper aborted the transaction. In this case, send {"``transStatus": "U"}  in a base64 encoded format to Adyen in order to order to finalize the payment.

Request
{
  "details": {
    "threeds2.challengeResult": "base64urlencoded_transStatus"
  },
  "paymentData": "YOUR_PAYMENT_DATA"
}
Response

You'll receive Authorised as the resultCode if the payment was successful.

{
    "pspReference": "8535516988037431",
    "resultCode": "Authorised"
}

Handling the communication from notification URLs to your front end

The notification URLs YOUR_3DS_METHOD_NOTIFICATION_URL and YOUR_METHOD_NOTIFICATION_URL on your server are the ideal places from where you should perform the next /payments/details request. However, you may want to communicate with your front end after performing the device fingerprinting or after presenting a challenge in order to hide the iframes and to perform other actions if needed.

In case you don't have an existing implementation for your front end and back end communication, our recommended implementation is to:

  • Use the message event on the front end to listen to a window.postMessage method from the pages running the iframes at the notification URLs. See sample codes below:


Add this in the notification URLs, running within the iframe:

<script type="text/javascript">
 // For IdentifyShopper (3DSMethod) flow
 // NOTE: This redirect of the iframe should have happened within 10 seconds of POST-ing the form to the
 // threeDSMethodURL otherwise threeDSCompInd should be set to 'N'
     const data = {
         type: 'identifyShopper',
         threeDSCompInd: 'Y'
     };
 // For ChallengeShopper flow
 // NOTE: This redirect of the iframe should have happened within 10 minutes of POST-ing the form
 // to the acsURL otherwise transStatus should be set to 'U'
 const data = {
         type: 'challengeShopper',
         transStatus: 'Y',
 threeDSServerTransID: threeDSServerTransID
     };

    window.parent.postMessage(data, YOUR_WEBSITE_DOMAIN);

</script>

Add this in your website:

window.addEventListener("message", (e) =>
{
    if(e.origin === YOUR_HOSTED_DOMAIN_FOR_THE_NOTIFICATION_URLS){
        const eventData = e.data;
        // IdentifyShopper (3DSMethod) response
        if(eventData.hasOwnProperty('threeDSCompInd')){

            // If you haven't already performed the next /payments/details call from your notification URL this
            // represents a good place to initiate the an API request
            authorise3DS2RequestAfterIdentifyingShopper(eventData.threeDSCompInd);
        }

        // Challenge response
        if(eventData.hasOwnProperty('transStatus') && eventData.hasOwnProperty('threeDSServerTransID')){

            // If you haven't already performed the next /payments/details call from your notification URL this
            // represents a good place to initiate the an API request
            authorise3DS2RequestAfterChallenge(eventData.transStatus, eventData.threeDSServerTransID);
        }

        // Run code to remove the iframe from the '#threedsContainer' element
        hideIframe();
    }
});

Testing 3D Secure 2

To test how your integration handles different 3D Secure 2 authentication scenarios, use our test card numbers.
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 Expiry Date Security Code (CVC/CVV/CID)
American Express 3714 4963 5398 431 03/2030 7373
Cartes Bancaires 4035 5014 2814 6300 03/2030 737
Diners 3056 9309 0259 04 03/2030 737
Discover 6011 1111 1111 1117 03/2030 737
Maestro 5000 5500 0000 0029 03/2030 n/a
Mastercard 5454 5454 5454 5454 03/2030 737
Visa 4917 6100 0000 0000 03/2030 737

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.
  • IdentifyShopper: You'll receive this result code if you are using the Native authentication.
  • ChallengeShopper: You will get this result code after you submit the 3D Secure 2 device fingerprinting result in a Native authentication, unless you specify a frictionless 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 Expiry Date Security Code (CVC/CVV/CID)
Visa 4212 3456 7891 0006 03/2030 737

To test the frictionless flow, in which you perform a fingerprint but no challenge, use the following test card number:

Card number Expiry Date Security Code (CVC/CVV/CID) Authentication scenario
5201 2815 0512 9736 03/2030 737 Fingerprint but no challenge

App-based integration

To test different authentication scenarios for app-based integration, use the following test cards:

Card number Expiry Date Security Code (CVC/CVV/CID) Authentication scenario
5201 2855 6567 2311 03/2030 737 Basic text authentication
5201 2874 9905 2008 03/2030 737 Basic single select
5201 2815 9233 1633 03/2030 737 Basic multi select
5201 2888 2269 6974 03/2030 737 Basic out-of-band (OOB) authentication
5201 2895 0084 3268 03/2030 737 HTML OOB authentication
5201 2861 5377 1465 03/2030 737 App single select then text authentication

Other scenarios

Card number Expiry Date Security Code (CVC/CVV/CID) Scenario
4199 3500 0000 0002 03/2030 737 The card is not enrolled for 3D Secure transactions.
5201 2829 9900 5515 03/2030 737 There was a technical error. This test card simulates a timeout during the 3D Secure 2 authentication flow on the issuer side. Depending on your configuration, the transaction might still proceed to a successful authorization.