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 number | 3DS Version | Emv Flow | Description |
|---|---|---|---|
4444444444444422 | 2.x (EMV) | Frictionless | Approved |
4444444444444455 | 2.x (EMV) | Frictionless | Declined |
4444444444443333 | 2.x (EMV) | Challenge | Card has 3DS Method |
4444444444446666 | 2.x (EMV) | Challenge | 3DS Method has 15 seconds timeout |
4444444499999999 | 2.x (EMV) | Challenge | No 3DS Method |
4444444411111111 | 1.0.2 | PaReq |
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.threeDSMethodTransactionIdthreeDSMethodUrl- value from the Status response:threeDSAuth.threeDSMethodUrlthreeDSMethodData
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 fieldthreeDSAuth.acsUrlcreq- CReq data from the fieldthreeDSAuth.creqof the status responsemerchantTermUrl- merchant url where an ACS server send PaResmerchantSessionData- merchant session data. This field will be sent along with the cres on yourcresUrl
<!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 fieldthreeDSAuth.acsUrlpaReq- PaReq data from the fieldthreeDSAuth.acsUrlof the status responsemerchantTermUrl- merchant url where an ACS server send PaResmerchantData- merchant data. This field will be sent along with the PaRes on yourmerchantTermUrl
<!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
| Source | Name | Javascript | Example |
|---|---|---|---|
| Header | Accept | text/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 | |
| Header | User-Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 | |
| Parameter | browserJavaEnabled | navigator.javaEnabled() | false |
| Parameter | browserJavascriptEnabled | true | true |
| Parameter | browserLanguage | navigator.language | en-GB |
| Parameter | browserColorDepth | screen.colorDepth | 24 |
| Parameter | browserScreenHeight | screen.height | 1080 |
| Parameter | browserScreenWidth | screen.width | 1920 |
| Parameter | browserTZ | new Date().getTimezoneOffset() | 1200 |
| Framework | ipAddress | 1.2.3.4 |