Skip to main content

3D-Secure Card Payments

Overview

3D-Secure is a security protocol that is designed to provide an additional layer of security for online credit and debit card transactions. It is designed to ensure that the person making the transaction is the legitimate cardholder.

The cardholder may be required to enter a password or a one-time code to complete the transaction. This is done through a process called "step-up" authentication.

Below are the steps to process a 3D-Secure card payment using the Little Pay API.

  1. Get a device details collection URL
  2. Collect device details
  3. Check if the cardholder requires step-up authentication
  4. Render the step-up authentication page if the cardholder requires step-up authentication. Otherwise, process the payment
  5. Process the payment

Get a device details collection URL

To process a 3D-Secure card payment, you must first get a device details collection URL. This URL is used to collect device details from the cardholder's device. You can get the device details collection URL by making a POST request to the /pay/{intentId}/cspaToken endpoint. The request body should contain the card details. The response will contain the deviceDataCollectionUrl and the accessToken that you can use to collect the device details.

POST /pay/{intentId}/cspaToken
{
"type": "CARDS",
"payment": {
"cc_number": "",
"cc_cvv": "",
"cc_exp": "",
"cc_name": ""
}
}
Response:
{
"date": "2024-02-21T05:52:00.943Z",
"data": {
"reference": "",
"message": "Request processed successfully",
"paToken": {
"accessToken": "",
"deviceDataCollectionUrl": "https://centinelapi.cardinalcommerce.com/V1/Cruise/Collect",
"referenceId": "",
"token": ""
}
}
}

Collect device details

You can collect device details by making a POST request to the deviceDataCollectionUrl that you received in the previous step. The request body should contain the accessToken that you received in the previous step. You can use the following JavaScript code to collect the device details. The deviceDataCollectionUrl and the accessToken are used to create a form and an iframe that will be used to collect the device details. The form is then submitted to the deviceDataCollectionUrl.

Please note that this step is MANDATORY

const form = document.createElement("form");
form.id = "deviceDataCollectionForm";
form.method = "POST";
form.action = paToken.deviceDataCollectionUrl;
form.style.display = "none";
form.target = "collectionIframe";

const input = document.createElement("input");
input.type = "hidden";
input.name = "JWT";
input.value = paToken.accessToken;
input.id = "cardinal_collection_form_input";
form.appendChild(input);

const iframe = document.createElement("iframe");
iframe.name = "collectionIframe";
iframe.style.display = "none";
iframe.id = "cardinal_collection_iframe";
iframe.width = "10";
iframe.height = "10";

document.body.appendChild(form);
document.body.appendChild(iframe);
form.submit();

window.addEventListener("message", (event) => {
if (event.origin === "https://centinelapistag.cardinalcommerce.com") {
console.log("Little Pay: Device details collected successfully");
}
});

Check if the cardholder requires step-up authentication

You can check if the cardholder requires step-up authentication by making a POST request to the /pay/{intentId}/enroll. You must pass manually collected device information as a backup in case the device details collection fails. The response will contain the action, accessToken, and stepUpUrl that you can use to render the step-up authentication page if the cardholder requires step-up authentication.

POST /pay/{intentId}/enroll
{
"deviceInformation": {
"httpBrowserColorDepth": 24,
"httpBrowserJavaEnabled": true,
"httpBrowserJavaScriptEnabled": true,
"httpBrowserLanguage": "en-US",
"httpBrowserScreenHeight": 1080,
"httpBrowserScreenWidth": 1920,
"httpBrowserTimeDifference": -300
}
}
Response:
{
"date": "2024-03-07T06:12:21.337Z",
"data": {
"action": "",
"accessToken": "",
"stepUpUrl": ""
}
}

If the action is MAKE_PAYMENT, the cardholder does not require step-up authentication. You can proceed to process the payment. The stepUpUrl and accessToken will not be returned.

If the action is AUTHENTICATE, the cardholder requires step-up authentication. You can render the step-up authentication page using the stepUpUrl and accessToken.

If the action is FAILED, the request was rejected and the customer should be prompted to try using another payment method.

Below is an example of how you can collect the device details from the cardholder's browser.

const details = {
httpBrowserColorDepth: screen.colorDepth,
httpBrowserJavaEnabled: false,
httpBrowserJavaScriptEnabled: true,
httpBrowserLanguage: navigator.language,
httpBrowserScreenHeight: screen.height,
httpBrowserScreenWidth: screen.width,
httpBrowserTimeDifference: new Date().getTimezoneOffset(),
};

Render the step-up authentication page

Below is an example of how you can render the step-up authentication page using the stepUpUrl and accessToken.

The MD is the reference received in the when creating a payment intent. It will be used to process the payment. If it is not provided, the payment will fail.

If you had set metadata.authenticationRedirectUrl when creating a payment intent, the user will be redirected to that URL after step-up authentication is completed.

How to render in the page in a new tab

const form = document.createElement("form");
form.id = "stepUpForm";
form.method = "POST";
form.action = stepUpUrl;
form.target = "_blank"; //Will open in a new tab

const jwtInput = document.createElement("input");
jwtInput.type = "hidden";
jwtInput.name = "JWT";
jwtInput.value = accessToken;
form.appendChild(jwtInput);

const mdInput = document.createElement("input");
mdInput.type = "hidden";
mdInput.name = "MD";
mdInput.value = reference; //This is important. It is the reference received in the first step. It will be used to process the payment
form.appendChild(mdInput);

document.body.appendChild(form);

form.submit();

How to render the page in an iframe

<iframe id="stepUpIframe" name="stepUpIframe" style="display: none;"></iframe>
const form = document.createElement("form");
form.id = "stepUpForm";
form.method = "POST";
form.action = stepUpUrl;
form.target = "stepUpIframe"; //Will open in the iframe

const jwtInput = document.createElement("input");
jwtInput.type = "hidden";
jwtInput.name = "JWT";
jwtInput.value = accessToken;
form.appendChild(jwtInput);

const mdInput = document.createElement("input");
mdInput.type = "hidden";
mdInput.name = "MD";
mdInput.value = reference; //This is important. It is the reference received in the first step. It will be used to process the payment
form.appendChild(mdInput);

document.body.appendChild(form);

form.submit();

Process the payment

You can process the payment by making a POST request to the /pay/{intentId}/process endpoint.

POST /pay/{intentId}/process
{
"type": "CARDS"
}
Response:
{
"date": "2024-03-07T13:03:05.141Z",
"data": {
"status": "COMPLETED",
"message": "",
"provider": "CARDS",
"providerReference": "",
"amount": 1,
"currency": "KES",
"reference": ""
}
}

The status will be COMPLETED if the payment is successful. Otherwise, the status will be FAILED. If the status is FAILED, the message will contain the reason for the failure. The cardholder should be prompted to try using another payment method.