3DS with the 3DS JavaScript API
This topic outlines all the steps that are required to add 3DS to your American Express Payment Gateway integration using the 3DS JavaScript(JS) API, including how to use the authentication result to process a payment.
To view examples of the API requests and responses used in the 3DS flow with the 3DS JavaScript API, download the Postman collection.
For more information about some generic 3DS features you can take advantage of in your integration, see FAQs. After you have completed your integration, see Testing your 3DS Integration to test it.
Prerequisites
To use 3DS with the 3DS JS API:
- Implement your basic Hosted Session integration.
- Implement any subsequent payment operations you want to use with the created session.
- Create a separate session to gather the card details before you proceed with the session to authenticate.
Step 1: Create and update session
3DS JS uses session-based authentication. For more information about the session-based authentication, see Authentication Options. As a first step, you must create a session, which you can then update with the request fields and values you wish to store in the session.
You can create a session using the CREATE SESSION request. This is a server-side WS API request and is a prerequisite for integrating with the JS API. It returns the following fields:
session.id
Unique session identifier which you must provide on subsequent requests to reference session contents.session.authenticationLimit
Limit on the number of transaction requests the payer's browser can submit. You can supply a value in the request or use the gateway's default. By default, the gateway sets it to 5, but you can provide a value up to 25. This limit prevents malicious users from using the authentication request as a potential carding attack and from performing Denial of Service (DoS) attacks on your site by submitting large numbers of potentially billable transactions.Any authentication retries you initiate are checked against the authentication limit.session.aes256Key
Key you can use to decrypt sensitive data passed to your website through the payer's browser or mobile device.session.version
Session version. You can use this field to implement optimistic locking of the session content.session.updateStatus
Summary of the outcome of the last attempt to modify the session.
After you have created the session, you can add or update fields in a session using the UPDATE SESSION request. This allows you to add payment and payer data into a session that can subsequently become the input to determine the risk associated with a payer in an authentication operation. The following table defines commonly used fields in a session.
Table: Session fields
Field | Required/Optional | Description |
---|---|---|
session.id or sourceOfFunds.provided.card.*
orsourceOfFunds.token
|
Required | Details of the card being used for the payment. You can also use network tokens and device payment tokens as source of funds in payer authentication. For more information, see FAQs. |
order.amount
|
Required | Total amount of the order. |
order.currency
|
Required | Currency of the order. |
transaction.id
|
Required | Unique identifier for this payment authentication. |
order.id
|
Required | Unique identifier for this order. |
authentication.channel
|
Required | Channel in which the authentication request is being initiated. You can specify one of the following:
|
authentication.redirectResponseUrl
|
Required | URL to which you want to redirect the payer after completing the payer authentication process. You do not need to provide this URL if you are certain that there will be no interaction with the payer. |
authentication.purpose
|
Optional | Purpose of the authentication. By default, this field is set to PAYMENT_TRANSACTION to indicate that authentication is to be performed when processing a card payment. However, you can specify a different purpose to indicate non-payment authentication. If you are establishing a payment agreement and not processing a payment along with it, provide ADD_CARD as the authentication purpose. See How can I submit a Non-Payment Authentication Request? Agreement details must be provided. |
authentication.acceptVersions
|
Optional | 3DS versions that you accept for this payment. If you do not specify a version, 3DS2 is accepted. The gateway uses 3DS2 if supported by the issuer and the card. If 3DS2 is not available, the authentication does not proceed. |
order.merchantCategoryCode
|
Optional | Merchant category code. Provide the value if you want to override the default value configured on your acquirer link. |
Step 2: Initialize the API
Reference the 3DS JS API (threeDS.js) from the gateway servers. This places a ThreeDS object into the window/global namespace.
Once you have created a session, initialize the 3DS JS API using the configure() function, with the following mandatory arguments in the threedsConfig map object:
merchantId
Your merchant identifier on the gateway.sessionId
Session ID that you created using the CREATE SESSION request.containerId
<div> ID in your HTML code where the API injects a hidden iframe.callback
Function to be invoked once the API has been initialized.configuration
JSON value supporting data elements like userLanguage (payment page language displayed to the user; optional) and wsVersion (WS API version).
The configure() function must be called during the page load or when the DOM is in ready state. It must be called only once for the page load. After calling this method, 3DS JS provides configuration values as member variables.
<html> <head> <script src="../../../../../../../static/threeDS/1.3.0/three-ds.min.js" data-error="errorCallback" data-cancel="cancelCallback"> </script> <script type="text/javascript"> //The output of this call will return 'false', since the API is not configured yet console.log(ThreeDS.isConfigured()); /** Configure method with the configuration{} parameter set and demonstrates the state change of the ThreeDS object before and after the configure method is invoked. */ ThreeDS.configure({ merchantId: {merchantId}, sessionId: {sessionId}, containerId: "3DSUI", callback: function () { if (ThreeDS.isConfigured()) console.log("Done with configure"); }, configuration: { userLanguage: "en-AU", //Optional parameter wsVersion: 81 } }); //The output of this call will return 'true', since the API is configured console.log(ThreeDS.isConfigured()); //The output of the following code might look like "ThreeDS JS API Version : 1.2.0" console.log("ThreeDS JS API Version : " + ThreeDS.version); </script> </head> <body> <div id="3DSUI"></div> </body> </html>
Step 3: Initiate authentication
Once all payer and payment data has been gathered into a session, you can initiate the authentication by invoking the initiateAuthentication() function. It calls the INITIATE AUTHENTICATION request of the Payer Authentication API and determines the versions of payer authentication available to you for a given card, based on the following:
- 3DS versions configured on your merchant profile
- Card type
- Preferences you have indicated in the request
- Version of 3DS the card has been enrolled in
- 3DS transaction filtering rules configured by you or Your payment service provider (PSP)
The function also enables any background activities, such as a 3DS2 ACS call to be carried out for purposes such as gathering additional payer data to support a subsequent authenticatePayer() function.
You can initiate authentication by calling the initiateAuthentication() function with the following mandatory arguments:
transactionId
Unique identifier for this payment authentication.orderId
Unique identifier for this order.callback
Callback function.optionalParams (optional)
Additional fields, such as correlationId.
If 3DS authentication of the payer is available, the following fields are returned in the data argument of the callback function. Otherwise, the response includes an error.
data.restApiResponse
Raw response from the Initiate Authentication REST API call.data.correlationId
Last correlation Id that was used for making the Initiate Authentication REST API call. It allows you to match the response to the request.data.gatewayRecommendation
Recommendation on your next actions, based on the 3DS transaction filtering rules configured by you or your PSP:PROCEED :
You can proceed to Step 4 to authenticate the payer.RESUBMIT_WITH_ALTERNATIVE_PAYMENT_DETAILS :
Ask the payer for alternative payment details, for example, a new card or another payment method and resubmit the request with the new details. Do not resubmit the same request.
data.authenticationVersion
Returns 3DS2 if authentication is available.
var optionalParams = { sourceOfFunds: { type: "CARD" }, }; ThreeDS.initiateAuthentication({orderId}, {transactionId}, function (data) { if (data && data.error) { var error = data.error; //Something bad happened, the error value will match what is returned by the Authentication API console.error("error.code : ", error.code); console.error("error.msg : ", error.msg); console.error("error.result : ", error.result); console.error("error.status : ", error.status); } else { console.log("After Initiate 3DS ", data); //data.response will contain information like gatewayRecommendation, authentication version, and so on. console.log("REST API raw response ", data.restApiResponse); console.log("Correlation Id", data.correlationId); console.log("Gateway Recommendation", data.gatewayRecommendation); console.log("HTML Redirect Code", data.htmlRedirectCode); console.log("Authentication Version", data.authenticationVersion); switch (data.gatewayRecommendation) { case "PROCEED": authenticatePayer();//merchant's method break; case "RESUBMIT_WITH_ALTERNATIVE_PAYMENT_DETAILS": tryOtherPayment();//Card does not support 3DS and transaction filtering rules require 3DS on this transaction: Ask the payer to select a different payment method. break; } } }, optionalParams);
{ "authentication":{ "3ds2":{ "methodCompleted":false, "methodSupported":"SUPPORTED" }, "redirect":{ "customized":{ "3DS":{ "methodPostData":"eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9xYTA0LmdhdGV3YXkubWFzdGVyY2FyZC5jb20vY2FsbGJhY2tJbnRlcmZhY2UvZ2F0ZXdheS80ZjNmMGQyMjM5NzQwODE2OWIwMWFiYzg2OTQyZTY5NzBmODA2M2M0MDU4ZjAzNjNlOTFlMmJiOTNkOTA0NzU3IiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiJhYWY5YjU5ZC0yZTA0LTRjZDUtOTQzOC01OGU4MGEzNzBiNWEifQ==", "methodUrl":"<method_url>" } } }, "redirectHtml":"<div id=\"initiate3dsSimpleRedirect\" xmlns=\"http://www.w3.org/1999/html\"> <iframe id=\"methodFrame\" name=\"methodFrame\" height=\"100\" width=\"200\" > </iframe> <form id =\"initiate3dsSimpleRedirectForm\" method=\"POST\" action=\"https://<host_name>/acs/v2/method\" target=\"methodFrame\"> <input type=\"hidden\" name=\"threeDSMethodData\" value=\"eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9xYTA0LmdhdGV3YXkubWFzdGVyY2FyZC5jb20vY2FsbGJhY2tJbnRlcmZhY2UvZ2F0ZXdheS80ZjNmMGQyMjM5NzQwODE2OWIwMWFiYzg2OTQyZTY5NzBmODA2M2M0MDU4ZjAzNjNlOTFlMmJiOTNkOTA0NzU3IiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiJhYWY5YjU5ZC0yZTA0LTRjZDUtOTQzOC01OGU4MGEzNzBiNWEifQ==\" /> </form> <script>document.getElementById(\"initiate3dsSimpleRedirectForm\").submit();</script> </div>", "version":"3DS2" }, "order":{ "currency":"AUD", "status":"AUTHENTICATION_INITIATED" }, "response":{ "gatewayCode":"AUTHENTICATION_IN_PROGRESS", "gatewayRecommendation":"PROCEED" }, "result":"SUCCESS", "sourceOfFunds":{ "provided":{ "card":{ "number":"512345xxxxxx0008" } }, "type":"CARD" }, "transaction":{ "authenticationStatus":"AUTHENTICATION_AVAILABLE" }, "version":"72" }
Step 4: Authenticate payer
If the INITIATE AUTHENTICATION response has indicated authentication to be available (transaction.authenticationStatus=AUTHENTICATION_AVAILABLE), you can authenticate the payer. Invoke the authenticatePayer() function when the payer clicks the Pay Now button on the checkout page. The function calls the AUTHENTICATE PAYER request of the Payer Authentication API.
You must invoke the authenticatePayer()
function by providing the following mandatory arguments:
orderId
Same order ID as you used in the precedinginitiateAuthentication()
function.transactionId
Same transaction ID as you used in the precedinginitiateAuthentication()
function.callback
Callback function.optionalParams(Optional)
Additional AUTHENTICATE PAYER request fields such as billing and shipping.
The following fields are returned in the data
argument of the callback function:
data.restApiResponse
Raw response from the AUTHENTICATE PAYER request. The returned fields depend on the flow (frictionless or challenge) and the authentication channel defined for the session. For a session-authenticated request, the response is filtered to remove data that is not related to the payer and only whitelisted fields are returned. For more information, see Session Basics.data.correlationId
Last correlation ID that was used for making the AUTHENTICATE PAYER request. It allows you to match the response to the request.data.gatewayRecommendation
Recommendation on your next actions, based on the 3DS transaction filtering rules configured by you or your payment service provider:PROCEED :
You can proceed to complete the authentication process (challenge flow) or proceed to complete the payment (frictionless flow). If the authorization for the payment was successful, proceed with capturing the funds, and if applicable, ship the goods.DO_NOT_PROCEED_ABANDON_ORDER :
Do not submit the same request again. The PSP, scheme, or issuer requires you to abandon the order.RESUBMIT_WITH_ALTERNATIVE_PAYMENT_DETAILS :
Ask the payer for alternative payment details (for example, a new card or another payment method) and resubmit the request with the new details. Do not resubmit the same request.
data.htmlRedirectCode
Redirect code. If thegatewayRecommendation
is PROCEED, insert this code into the page displayed to the payer.
If the gateway recommends you to PROCEED
:
- If the ACS has selected a frictionless flow for the payer, it redirects the payer's browser straight back to your web site, and you can proceed to Step 5 to submit a subsequent payment to the gateway. The gateway obtains the authentication data related to the payment and ensures that payments are processed only if all the 3DS transaction filtering rules (configured by you or your payment service provider) have passed.
- If the ACS has selected a challenge flow for the payer, redirect the payer to the ACS using the
htmlRedirectCode
provided in the response. After the challenge is completed, the ACS redirects the payer back to your web site and triggers a callback that contains theorderId
,transactionId
,gatewayRecommendation
, andrestApiResponse
fields. Determine the outcome of the challenge based on thegatewayRecommendation
field. The same rules apply as described above for theauthenticatePayer()
function response. If the recommendation is PROCEED, continue with Step 5.
var optionalParams = { fullScreenRedirect: true, billing: { address: { city: "London", country: "GBR" } } }; ThreeDS.authenticatePayer({orderId}, {transactionId}, function (data) { if (!data.error) { //data.response will contain all the response payload from the AUTHENTICATE_PAYER call. console.log("REST API response ", data.restApiResponse); console.log("HTML redirect code", data.htmlRedirectCode); displayReceipt(data); } }, optionalParams); function displayReceipt(apiResponse) { var responseBody = { "apiResponse": apiResponse }; var xhr = new XMLHttpRequest(); xhr.open('PUT', '3dsreceipt', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onreadystatechange = function () { if (xhr.readyState == XMLHttpRequest.DONE) { document.documentElement.innerHTML = this.response; } } xhr.send(JSON.stringify(responseBody)); }
{ "authentication":{ "3ds":{ "transactionId":"6dfa4509-1bf2-425b-965b-d44dd11f5f91" }, "3ds2":{ "3dsServerTransactionId":"8c4a911c-289a-46c2-a615-887e1cc01a6a", "acsTransactionId":"2a8234c9-e8ac-449d-a693-97a113b491fc", "directoryServerId":"A000000004", "dsTransactionId":"6dfa4509-1bf2-425b-965b-d44dd11f5f91", "methodCompleted":false, "methodSupported":"SUPPORTED", "protocolVersion":"2.2.0", "requestorId":"test2ID", "requestorName":"test2Name", "transactionStatus":"C" }, "method":"OUT_OF_BAND", "payerInteraction":"REQUIRED", "redirect":{ "customized":{ "3DS":{ "acsUrl":"https://<host_name>/acs/v2/prompt", "cReq":"eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImNhODM1ZDQxLTBlMDktNGI3OC1hNmUyLWQwZjJiNjFlZjBjOCJ9" } }, "domainName":"<domain_name>" }, "redirectHtml":"<div id=\"threedsChallengeRedirect\" xmlns=\"http://www.w3.org/1999/html\"> <form id =\"threedsChallengeRedirectForm\" method=\"POST\" action=\"https://<host_name>/acs/v2/prompt\" target=\"challengeFrame\"> <input type=\"hidden\" name=\"creq\" value=\"eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImNhODM1ZDQxLTBlMDktNGI3OC1hNmUyLWQwZjJiNjFlZjBjOCJ9\" /> </form> <iframe id=\"challengeFrame\" name=\"challengeFrame\" width=\"100%\" height=\"100%\" ></iframe> <script id=\"authenticate-payer-script\"> var e=document.getElementById(\"threedsChallengeRedirectForm\"); if (e) { e.submit(); e.remove(); } </script> </div>", "version":"3DS2" }, "correlationId":"test", "device":{ "browser":"MOZILLA", "ipAddress":"127.0.0.1" }, "merchant":"TEST_3DS2-1", "order":{ "amount":100, "authenticationStatus":"AUTHENTICATION_PENDING", "creationTime":"2021-04-13T02:22:59.113Z", "currency":"AUD", "id":"807a01b6-e6c8-4aa7-b8da-799bfff89496", "lastUpdatedTime":"2021-04-13T02:44:07.161Z", "merchantCategoryCode":"1234", "status":"AUTHENTICATION_INITIATED", "totalAuthorizedAmount":0, "totalCapturedAmount":0, "totalRefundedAmount":0, "valueTransfer":{ "accountType":"NOT_A_TRANSFER" } }, "response":{ "gatewayCode":"PENDING", "gatewayRecommendation":"PROCEED" }, "result":"PENDING", "sourceOfFunds":{ "provided":{ "card":{ "expiry":{ "month":"1", "year":"39" }, "number":"512345xxxxxx0008", "scheme":"MASTERCARD" } }, "type":"CARD" }, "timeOfLastUpdate":"2021-04-13T02:44:07.161Z", "timeOfRecord":"2021-04-13T02:22:59.113Z", "transaction":{ "acquirer":{ "merchantId":"99554411" }, "amount":100, "authenticationStatus":"AUTHENTICATION_PENDING", "currency":"AUD", "id":"42090084", "type":"AUTHENTICATION" }, "version":"60" }
Advanced integrations
The request submitted by the payer's browser to your web site on completion of the authenticatePayer()
method is parameterized allowing you to determine the authentication outcome. The individual authentication fields, for example, authentication.3ds2.transactionStatus.data
, can be useful in an advanced integration or if you need to provide the authentication data in a payment processed via another gateway. For more details, see How do I implement advanced payment session integrations?
Step 5: Use the authentication in a payment
When the result of the authenticatePayer()
function indicates that you can proceed with the payment (gatewayRecommendation=PROCEED), you can initiate a WS API AUTHORIZE or PAY operation. In addition to the standard fields, you must provide the following fields:
- order.id
Use the sameorderId
that you supplied in theinitiateAuthentication()
andauthenticatePayer()
functions. - authentication.transactionId: Use the same
transactionId
that you supplied in theinitiateAuthentication()
andauthenticatePayer()
functions. You do not need to include any of the fields in theauthentication
object, as the gateway uses the authentication.transactionId to look up the authentication results that it stored when you asked it to perform authentication. The gateway passes the required information to the acquirer.
URL | https://gateway-na.americanexpress.com/api/rest/version/<version>/merchant/<your_merchant_ID>/order/<your_order_ID>/transaction/<your_transaction_ID> |
HTTP Method | PUT |
{ "apiOperation":"PAY", "authentication":{ "transactionId":"<your_transaction_ID>" }, "session": { "id": "<your_session_id>" }, "transaction":{ "reference":"<your_order_ID>" } }
{ "authentication":{ "3ds":{ "acsEci":"02", "authenticationToken":"kHyn+7YFi1EUAREAAAAvNUe6Hv8=", "transactionId":"39c25b96-7bc3-4586-bee8-056479fed3af" }, "3ds2":{ "dsTransactionId":"39c25b96-7bc3-4586-bee8-056479fed3af", "protocolVersion":"2.2.0", "transactionStatus":"Y" }, "transactionId":"249213216", "version":"3DS2" }, "authorizationResponse":{ "posData":"1605S0100130", "transactionIdentifier":"TidTest" }, "device":{ "browser":"MOZILLA", "ipAddress":"127.0.0.1" }, "gatewayEntryPoint":"WEB_SERVICES_API", "merchant":"TEST_3DS2-1", "order":{ "amount":100.00, "authenticationStatus":"AUTHENTICATION_SUCCESSFUL", "chargeback":{ "amount":0, "currency":"AUD" }, "creationTime":"2021-04-13T02:11:06.102Z", "currency":"AUD", "id":"807a01b6-e6c8-4aa7-b8da-799bfff89496", "lastUpdatedTime":"2021-04-13T02:11:57.049Z", "merchantAmount":100.00, "merchantCategoryCode":"1234", "merchantCurrency":"AUD", "reference":"807a01b6-e6c8-4aa7-b8da-799bfff89496", "status":"CAPTURED", "totalAuthorizedAmount":100.00, "totalCapturedAmount":100.00, "totalRefundedAmount":0.00 }, "response":{ "acquirerCode":"00", "gatewayCode":"APPROVED" }, "result":"SUCCESS", "sourceOfFunds":{ "provided":{ "card":{ "brand":"MASTERCARD", "expiry":{ "month":"1", "year":"39" }, "fundingMethod":"CREDIT", "issuer":"<issuer>", "number":"512345xxxxxx0008", "scheme":"Mastercard", "storedOnFile":"NOT_STORED" } }, "type":"CARD" }, "timeOfLastUpdate":"2021-04-13T02:11:57.049Z", "timeOfRecord":"2021-04-13T02:11:56.973Z", "transaction":{ "acquirer":{ "batch":1, "id":"<acquirer_id>", "merchantId":"99554411" }, "amount":100.00, "authenticationStatus":"AUTHENTICATION_SUCCESSFUL", "authorizationCode":"028941", "currency":"AUD", "id":"1", "receipt":"1908266016", "reference":"807a01b6-e6c8-4aa7-b8da-799bfff89496", "source":"INTERNET", "stan":"496", "terminal":"1234", "type":"PAYMENT" }, "version":"60" }