This page describes implementation instructions for a custom 3D Secure 2 implementation. If you are looking for a client-side solution that supports 3D Secure 2 out of the box, we recommend using our Components or Drop-in solution instead.
How it works
In a full implementation, a payment eligible for 3D Secure 2 can go through either a frictionless or a challenge authentication flow before the payment is authorised. To support both flows, you need to build your own client-side and server-side implementation, with the option of using our 3D Secure 2 Component or helper functions.
3D Secure 2 is supported from v41 and later of /payments and /payments/details endpoints.
Here's a diagram for a 3D Secure 2 browser-based full implementation:
- 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. - Get the device fingerprint. If you receive an IdentifyShopper
resultCode
, you need to get the shopper's 3D Secure 2 device fingerprint. Create an iframe on the browser, send a device fingerprint request to the issuer, and then send the result to Adyen. If you get a response with an AuthorisedresultCode
, this indicates that the 3D Secure 2 authentication was frictionless, and the payment authorisation was successfully completed. - Present a challenge to the shopper. If you receive ChallengeShopper
resultCode
, this means that the issuer requires further shopper interaction. Depending on the logic on issuer's side, this result code can be returned after you submit a payment request or after you submit the device fingerprint result to Adyen. To handle a challenge flow, create an iframe, send a challenge request to the issuer, and then submit the challenge result to Adyen.
In case the issuer does not support 3D Secure 2, we will initiate a 3D Secure 1 fallback by default, indicated by a RedirectShopper resultCode
response. If you do not want to automatically fall back to 3D Secure 1, contact Support Team.
For a complete list of resultCode
values and the actions that you need to take, see Result codes.
Before you begin
Before you begin to integrate, make sure you have followed the Get started with Adyen guide to:
- Get an overview of the steps needed to accept live payments.
- Create your test account.
After you have created your test account:
- Get your API Key. Save a copy as you'll need it for API calls you make to the Adyen payments platform.
- Install one of our Libraries to connect with the Adyen APIs. For more information on these steps, refer to Get started with Adyen.
- 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.
-
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.
Submit a payment request
Submit a payment request with a POST /payments call. Include the following to indicate that you are ready to accept 3D Secure 2 payments:
channel
: webauthenticationData.threeDSRequestData.nativeThreeDS
: preferredbrowserInfo
: Collect information about your shopper's browser.threeDS2RequestData.notificationURL
:YOUR_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":"https://test.com"
},
"authenticationData" : {
"threeDSRequestData": {
"nativeThreeDS": "preferred"
}
},
"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:
-
resultCode
: IdentifyShopper or ChallengeShopper. Perform the corresponding 3D Secure 2 device fingerprinting or Present a challenge flows. If the transaction is exempted from 3D Secure 2, you might get an AuthorisedresultCode
. -
threeds2.fingerprintToken
orthreeds2.challengeToken
: Use this to start the corresponding Identify the shopper or Challenge the shopper flows. -
paymentData
: Use this for your succeeding POST /payments request.
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.
-
Base64 decode the
threeds2.fingerprintToken
from the /payments response.{ "threeDSMethodNotificationURL":"https:\/\/checkoutshopper-test.adyen.com\/checkoutshopper\/threeDSMethodNotification.shtml?originKey=pub.v2.82153..", "threeDSMethodUrl":"https:\/\/pal-test.adyen.com\/threeds2simulator\/acs\/startMethod.shtml", "threeDSServerTransID":"c9f82ec0-9e24-4f79-834d-6f8282de92fa" }
-
Create a
threeDSMethod
object with thethreeds2.threeDSServerTransID
andYOUR_3DS_METHOD_NOTIFICATION_URL
.const dataObj = { threeDSServerTransID : serverTransactionID, threeDSMethodNotificationURL : YOUR_3DS_METHOD_NOTIFICATION_URL };
-
Stringify the object.
const stringifiedDataObject = JSON.stringify(dataObj);
-
Base64url encode the object.
const encodedJSON = base64Url.encode(stringifiedDataObject);
-
Render a hidden HTML iframe in the browser, and send an HTTP POST to the
threeDSMethodURL
with athreeDSMethodData
field containing the base64url encoded JSON object.<form method="POST" action="${threeDSMethodURL}" id="3dform" target="NAME_OF_YOUR_IFRAME"> <input type="hidden" name="threeDSMethodData" value="${encodedJSON}" /> </form>
-
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. -
Make a POST /payments/details request from your server and include the
threeds2.fingerprint
and thepaymentData
objects as parameters.threeds2.fingerprint
: Pass a base64 encoded{"threeDSCompInd":"Y"}
.paymentData
: Pass thepaymentData
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.
-
Base64url 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" }
-
Create a
cReqData
object.const cReqData = {threeDSServerTransID : pResp.additionalData['threeDSServerTransID'], acsTransID : pResp.additionalData['acsTransID'], messageVersion : pResp.additionalData['.messageVersion'], challengeWindowSize : '05', messageType : 'CReq' }
Set the
challengeWindowSize
to any of the following identifiers:identifier size 01 250px x 400px 02 390px x 400px 03 500px x 600px 04 600px x 400px 05 100% x 100% -
Stringify the object.
const stringifiedDataObject = JSON.stringify(cReqData);
-
Base64url encode the
stringifiedDataObject
.const encodedcReq = base64Url.encode(stringifiedDataObject);
-
Render an iframe in the browser, and send an HTTP POST with a
creq
field containing the encoded CReq to theacsURL
. This will initiate the challenge window in the iframe.<form method="POST" action="${threeds2.threeDS2ResponseData.acsURL}" id="3dschallenge" target="NAME_OF_YOUR_IFRAME"> <input name="creq" value="${encodedcReq}" /> </form>
-
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 receive a response within 10 minutes, assume that something went wrong or the shopper aborted the transaction. Skip the next step and proceed to step 8.
{"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" }
-
Make a POST /payments/details request from your server and include the
details
and thepaymentData
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 thepaymentData
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, send {"transStatus": "U"}
in a base64 encoded format to Adyen to indicate that authentication or account verification could not be performed.
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"
}
Optional: Prefetch device fingerprinting keys
This functionality requires additional configuration on Adyen's end. To enable it, contact our Support Team.
You can opt to retrieve and cache 3D Secure device fingerprint keys for specific BIN ranges. When you cache the keys, you reduce the number of calls for each transaction as you can already start with performing 3D Secure 2 device fingerprinting.
To use cached keys for your authentication flow, you will need to:
- Retrieve and cache threeDSMethodURL once for each BIN.
- Generate a threeDSServerTransID for each transaction.
- Perform 3D Secure 2 device fingerprinting and submit the result in a payment request.
- Present a challenge if required by the issuer.
Make sure to update your cache regularly to get the latest keys and to avoid getting your transactions refused.
Get the 3D Secure 2 Method URL
To retrieve device fingerprinting keys, submit a POST get3dsAvailability request with a cardNumber
from a BIN range you want to prefetch the keys for, along with your merchantAccount
.
Sample request with card number
cardNumber
{
"merchantAccount":"YOUR_MERCHANT_ACCOUNT",
"cardNumber":"4917610000000000"
}
Response
{
"binDetails": {
"issuerCountry": "PL"
},
"dsPublicKeys": [
{
"brand": "visa",
"directoryServerId": "F013371337",
"publicKey": "eyJrdHkiOiJSU0==.."
}
],
"threeDS1Supported": true,
"threeDS2CardRangeDetails": [
{
"brandCode": "visa",
"endRange": "491761000000",
"startRange": "491761000000",
"threeDS2Version": "2.1.0",
"threeDSMethodURL": "https://pal-test.adyen.com/threeds2simulator/acs/startMethod.shtml"
}
],
"threeDS2supported": true
}
Cache the values of the following parameter for the specific BIN range:
threeDS2CardRangeDetails.threeDSMethodURL
If a card is registered with multiple 3D Secure 2 schemes, the threeDS2CardRangeDetails
array might contain a threeDSMethodURL
for each scheme.
Generate a 3D Secure 2 server transaction ID
The threeDSServerTransID
is a universally unique transaction identifier required when exchanging data between your shopper's browser and the issuer during the device fingerprinting process.
Generate a threeDSServerTransID
for each authentication transaction according to the following specifications:
- Length: 36 characters
- JSON Data Type: String
- Value accepted: Canonical format as defined in IETF RFC 4122. May use any of the specified versions if the output meets specified requirements.
For more information on the requirements, see EMVCo specifications.
Next, use the cached threeDS2CardRangeDetails.threeDSMethodURL
and the threeDSServerTransID
you generated to get the shopper's 3D Secure 2 device fingerprint.
Perform 3D Secure 2 device fingerprinting
-
Create the
threeDSMethod
object with thethreeds2.threeDSServerTransID
andYOUR_3DS_METHOD_NOTIFICATION_URL
.const dataObj = { threeDSServerTransID : serverTransactionID, threeDSMethodNotificationURL : YOUR_3DS_METHOD_NOTIFICATION_URL };
-
Stringify the object.
const stringifiedDataObject = JSON.stringify(dataObj);
-
Base64url encode the object.
const encodedJSON = base64Url.encode(stringifiedDataObject);
-
Render a hidden HTML iframe in the browser, and send an HTTP POST to the
threeDSMethodURL
with athreeDSMethodData
field containing the base64url encoded JSON object.
<form method="POST" action="${threeDSMethodURL}" id="3dform">
<input type="hidden" name="threeDSMethodData" value="${encodedJSON}" />
</form>
- 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"}
- Make a POST /payments request from your server and include a
threeDSCompInd
.
If you receive a response to YOUR_3DS_METHOD_NOTIFICATION_URL
within 10 seconds, send threeDSCompInd : Y
. Otherwise, send threeDSCompInd : N
.
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":"https:\/\/www.example.com\/YOUR_3DS_NOTIFICATION_URL",
"threeDSCompInd":"Y"
},
"authentication" : {
"native": "preferred"
},
"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 a resultCode
that can either be:
- 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 shopper interaction. Perform the Challenge flow.
For a complete list of resultCode
values 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"
}
Testing 3D Secure 2
To test how your integration handles different 3D Secure 2 authentication scenarios, you need to use a card number for the specific flow.
When prompted for 3D Secure 2 text challenges, use the following credentials to authenticate:
- For native mobile integrations, use password: 1234
- For web and mobile browser integrations, use password: password
Depending on the authentication option, you can receive the following result codes:
- RedirectShopper: you receive this result code if you are using the Redirect authentication flow.
- IdentifyShopper: you receive this result code if you are using the Native authentication flow.
- ChallengeShopper: you receive this result code after you submit the 3D Secure 2 device fingerprinting result in a Native authentication, unless you specify a frictionless flow.
Depending on your integration, use the following test cards to simulate different authentication flows.
Card Type | Card Number | Expiry Date | Security Code (CVC/CVV/CID) |
---|---|---|---|
American Express | 3714 4963 5398 431 | 03/2030 | 7373 |
Bancontact / Maestro | 6703 4444 4444 4449 | 03/2030 | |
Bancontact / Visa | 4871 0499 9999 9910 | 03/2030 | 737 |
Cartes Bancaires / Visa Debit | 4035 5014 2814 6300 | 03/2030 | 737 |
Cartes Bancaires | 4360 0000 0100 0005 | 03/2030 | 737 |
China UnionPay (Credit) | 6250 9470 0000 0014 | 03/2030 | 123 |
China UnionPay (Debit) | 6250 9460 0000 0016 | 03/2030 | 123 |
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 |
Mastercard Credit | 2222 4000 1000 0008 | 03/2030 | 737 |
Visa | 4917 6100 0000 0000 | 03/2030 | 737 |
Visa Classic | 4166 6766 6766 6746 | 03/2030 | 737 |
Challenge without fingerprint
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 |
Fingerprint without challenge
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 |
Native authentication
To test authentication scenarios for native mobile (app-based) integrations, 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 out-of-band (OOB) authentication |
5201 2861 5377 1465 | 03/2030 | 737 | App single select then text authentication |
4917 6100 0000 0042 | 03/2030 | 737 | Advanced: ACS sends an empty Challenge Response (CRes ) |
4917 6100 0000 0067 | 03/2030 | 737 | Advanced: Invalid content in the acsSignedContent field in Authentication Response (ARes ) |
4917 6100 0000 0059 | 03/2030 | 737 | Advanced: Challenge Response (CRes ) timeout |
Technical error
To test simulate an error due to a timeout during the 3D Secure 2 authentication on the issuer side, use the following test card:
Card number | Expiry Date | Security Code (CVC/CVV/CID) | Scenario |
---|---|---|---|
5201 2829 9900 5515 | 03/2030 | 737 | Depending on your configuration, the transaction might still proceed to a successful authorization. |
Advanced scenarios
Use the following test cards to test more advanced scenarios:
Card number | Scenario |
---|---|
5201 2815 0512 9736 | Return ARes with transStatus =Y |
5201 2812 6243 5268 | Return ARes with transStatus =N |
5201 2850 9382 3592 | Return ARes with transStatus =A |
5201 2828 2836 6351 | Return ARes with transStatus =U |
5201 2864 9681 6589 | Return ARes with transStatus =R |
5201 2846 7071 7533 | Return ARes with transStatus =U and transStatusReason =06 |
5201 2829 9900 5515 | Timeout error |
5201 2886 9531 5843 | Connection failure error |
5201 2858 9491 2800 | Version number not supported error |
5201 2852 4062 4612 | Access denied error |
5201 2859 4986 5169 | MCC not valid error |
5201 2829 4084 9714 | Invalid endpoint error |