Skip to content

3-D Secure

Test Cards

You can use only this set of card numbers for simulating different 3DS scenarios, including 3DS 2.x (EMV) frictionless flow (approved/declined), challenge flow (with 3DS Method, without it, with a 15-second timeout), and a 3DS 1.0.2 PaReq card.

Card number3DS VersionEmv FlowDescription
44444444444444222.x (EMV)FrictionlessApproved
44444444444444552.x (EMV)FrictionlessDeclined
44444444444433332.x (EMV)ChallengeCard has 3DS Method
44444444444466662.x (EMV)Challenge3DS Method has 15 seconds timeout
44444444999999992.x (EMV)ChallengeNo 3DS Method
44444444111111111.0.2PaReq

Handling StatusResponse.threeDSAuth.threeDSAuthStep states

Step-by-step instructions with ready-to-use HTML templates for each possible authentication state:

  • THREEDS_METHOD / AREQ_PROCESSING — browser fingerprinting via a hidden iframe and waiting for AReq processing (3DS 2.x)
  • CREQ / CRES_PROCESSING — submitting a challenge request to the ACS server and waiting for the response (3DS 2.x)
  • PAREQ / PARES_PROCESSING — redirect to the ACS server and waiting for the response (3DS 1.x)

THREEDS_METHOD

3DS Method Main Page

Templates variables:

  • threeDSMethodTransactionId - value from the Status response: threeDSAuth.threeDSMethodTransactionId
  • threeDSMethodUrl - value from the Status response: threeDSAuth.threeDSMethodUrl
  • threeDSMethodData
threeDSMethodData = base64UrlSafe (
toJson (
{
"threeDSServerTransID" : "{{ threeDSMethodTransactionId }}",
"threeDSMethodNotificationURL" : "{{ merchantCompleteUrl }}"
}
)
)
  • merchantCompleteUrl - complete page url on a merchant site. See 3DS Merchant Complete Page for an example.
  • merchantNextUrl - next url after 3DS Method page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>3DS Method ...</title>
<script>
var fallbackTimeout = null;
function processForm() {
document.title = "Processing ...";
document.getElementById( "browserJavaEnabled" ).value = navigator.javaEnabled();
document.getElementById( "browserJavascriptEnabled" ).value = true;
document.getElementById( "browserLanguage" ).value = navigator.language;
document.getElementById( "browserColorDepth" ).value = screen.colorDepth;
document.getElementById( "browserScreenHeight" ).value = screen.height;
document.getElementById( "browserScreenWidth" ).value = screen.width;
document.getElementById( "browserTZ" ).value = new Date().getTimezoneOffset();
document.nextForm.submit();
}
function onPostMessage(event) {
if(!event.data.hasOwnProperty('methodNotification')) {
return;
}
document.getElementById( "threeDSCompInd" ).value = 'Y';
if(fallbackTimeout != null) {
clearTimeout(fallbackTimeout);
fallbackTimeout = null;
}
processForm();
}
function onPageLoaded() {
fallbackTimeout = setTimeout(processForm, 10 * 1000);
document.methodForm.submit();
window.addEventListener('message', onPostMessage);
}
</script>
</head>
<body onload="onPageLoaded()">
<div class="progress">
<div>
Verifying ...
</div>
</div>
<iframe style="width:0; height:0; border:0;" name="methodFrame"></iframe>
<form name="methodForm" target="methodFrame" action="{{ threeDSMethodUrl }}" method="POST">
<input type="hidden" name="threeDSMethodData" value="{{ threeDSMethodData }}">
</form>
<form name="nextForm" action="{{ merchantNextUrl }}" method="post">
<input type="hidden" name="threeDSServerTransID" value="{{ threeDSMethodTransactionId }}"/>
<input type="hidden" name="threeDSCompInd" id="threeDSCompInd" value="N"/>
<input type="hidden" name="browserJavaEnabled" id="browserJavaEnabled" value="" />
<input type="hidden" name="browserJavascriptEnabled" id="browserJavascriptEnabled" value="" />
<input type="hidden" name="browserLanguage" id="browserLanguage" value="" />
<input type="hidden" name="browserColorDepth" id="browserColorDepth" value="" />
<input type="hidden" name="browserScreenHeight" id="browserScreenHeight" value="" />
<input type="hidden" name="browserScreenWidth" id="browserScreenWidth" value="" />
<input type="hidden" name="browserTZ" id="browserTZ" value="" />
<noscript>
<input type="submit" name="submit" value="Continue"/>
</noscript>
</form>
</body>
</html>

3DS Merchant Complete Page

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>3DS Method Complete</title>
<script>
window.parent.postMessage({methodNotification: "COMPLETE"}, "*");
</script>
</head>
<body>
<p>
Please enable javascript.
Just sending a notification to the main page.
</p>
</body>
</html>

AREQ_PROCESSING

Waiting while AReq Processing

CREQ

Template variables:

  • acsUrl - 3DS ACS server url. You can get it from the status response and field threeDSAuth.acsUrl
  • creq - CReq data from the field threeDSAuth.creq of the status response
  • merchantTermUrl - merchant url where an ACS server send PaRes
  • merchantSessionData - merchant session data. This field will be sent along with the cres on your cresUrl
<!DOCTYPE html>
<html>
<head>
<title>Redirecting to ACS..</title>
</head>
<body onLoad="document.creq_form.submit()">
<form name="creq_form" action="{{ acsUrl }}" method="POST">
<input type="hidden" name="creq" value="{{ creq }}"/>
<input type="hidden" name="threeDSSessionData" value="{{ merchantSessionData }}"/>
<noscript>
<input type="submit" name="submit" value="Continue"/>
</noscript>
</form>
</body>
</html>

CRES_PROCESSING

Wait while CRes is processing

PAREQ

Template variables:

  • acsUrl - 3DS ACS server url. You can get it from the status response and field threeDSAuth.acsUrl
  • paReq - PaReq data from the field threeDSAuth.acsUrl of the status response
  • merchantTermUrl - merchant url where an ACS server send PaRes
  • merchantData - merchant data. This field will be sent along with the PaRes on your merchantTermUrl
<!DOCTYPE html>
<html>
<head>
<title>Redirecting to ACS..</title>
</head>
<body onLoad="document.pareq_form.submit()">
<form name="pareq_form" action="{{ acsUrl }}" method="POST">
<input type="hidden" name="TermUrl" value="{{ merchantTermUrl }}"/>
<input type="hidden" name="PaReq" value="{{ paReq }}"/>
<input type="hidden" name="MD" value="{{ merchantData }}"/>
<noscript>
<input type="submit" name="submit" value="Continue"/>
</noscript>
</form>
</body>
</html>

PARES_PROCESSING

Waiting while PaRes Processing

How to get Browser 3DS Fields

For 3DS optimisation, please add browser section, including IP and browser details.

Here is the simplest example how to get 3DS fields in html page.

<!DOCTYPE html>
<html>
<head>
<script>
function processForm() {
document.getElementById( "browserJavaEnabled" ).value = navigator.javaEnabled();
document.getElementById( "browserJavascriptEnabled" ).value = true;
document.getElementById( "browserLanguage" ).value = navigator.language;
document.getElementById( "browserColorDepth" ).value = screen.colorDepth;
document.getElementById( "browserScreenHeight" ).value = screen.height;
document.getElementById( "browserScreenWidth" ).value = screen.width;
document.getElementById( "browserTZ" ).value = new Date().getTimezoneOffset();
document.autoForm.submit();
}
</script>
</head>
<body onload="processForm()">
<form name="autoForm" action="YOUR_SITE_URL_TO_HANDLE_THIS_REQUEST" method="post">
<input type="hidden" name="browserJavaEnabled" id="browserJavaEnabled" value="" />
<input type="hidden" name="browserJavascriptEnabled" id="browserJavascriptEnabled" value="" />
<input type="hidden" name="browserLanguage" id="browserLanguage" value="" />
<input type="hidden" name="browserColorDepth" id="browserColorDepth" value="" />
<input type="hidden" name="browserScreenHeight" id="browserScreenHeight" value="" />
<input type="hidden" name="browserScreenWidth" id="browserScreenWidth" value="" />
<input type="hidden" name="browserTZ" id="browserTZ" value="" />
<noscript>
<input type="submit" name="submit" value="Continue 3DS"/>
</noscript>
</form>
</body>
</html>

Then on the YOUR_SITE_URL_TO_HANDLE_THIS_REQUEST you will receive browser details fields.

Also you will need to catch Accept and User-Agent headers.

Here is the table with these fields

SourceNameJavascriptExample
HeaderAccepttext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
HeaderUser-AgentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
ParameterbrowserJavaEnablednavigator.javaEnabled()false
ParameterbrowserJavascriptEnabledtruetrue
ParameterbrowserLanguagenavigator.languageen-GB
ParameterbrowserColorDepthscreen.colorDepth24
ParameterbrowserScreenHeightscreen.height1080
ParameterbrowserScreenWidthscreen.width1920
ParameterbrowserTZnew Date().getTimezoneOffset()1200
FrameworkipAddress1.2.3.4