3DS Payment Integration
3DS Payment Authentication allows you to authenticate a payment request using 3DS. This guide will outline the requirements for authenticating a payment using 3DS through Wpay and will highlight where the 3DS payment flow and information differs from the normal guide for Making a Payment.
The typical flow for making a payment with 3DS authentication is as follows:
Step 1 - Make a Payment Request:
- Ensure you have a payment instrument obtained either from the customer's wallet (for saved instruments) or from tokenizing a payment instrument (for new instruments) which is supported for 3DS authentication.
- Make a payment request and include the
requires3DS
flag in the payment request to indicate that you wish to apply 3DS authentication to the payment - Check the payment response to determine if 3DS authentication is required as part of the payment.
- Should the outcome of the payment provide an error outcome indicating
3DS TOKEN REQUIRED
then you will need to authenticate the payment via 3DS utilising the Frames SDK. See Step 2.
- Should the outcome of the payment provide an error outcome indicating
Step 2 - Request 3DS Authentication:
- Utilizing the Frames SDK request 3DS authentication for the requested payment. The outcome of the 3DS authentication will either be frictionless or a challenge required.
- Should the 3DS process be successful you will be provided with the 3DS
token
andreference
data which will be required when making the subsequent payment request.
Step 3 - Make a Final Payment Request including the 3DS Data:
- Include the
requires3DS
flag as well as the 3DStoken
andreference
data in the payment request and process the payment - The 3DS data will be authenticated with the issuer to ensure that it is valid and the payment will then be processed.
1. Make a Payment Request
1.1. Request Payment with 3DS Authentication
Make a payment request and include the merchantPayload
and set the requires3DS
flag to true.
Example of required merchantPayload
:
merchantPayload
:"merchantPayload": {
"payload": {
"requires3DS": true
},
"schemaId": "0a221353-b26c-4848-9a77-4a8bcbacf228"
}
Example of payment request with included merchantPayload
:
merchantPayload
:curl --location --request POST 'https://{{environment}}.wpay.com.au/wow/v1/pay/instore/customer/payments' \
--header 'X-Api-Key: {{yourAPIKey}}' \
--header 'Authorization: Bearer {{yourBearerToken}}' \
--header 'x-guest: false' \
--header 'Content-Type: application/json' \
--data-raw '{
"data": {
"transactionType": {
"creditCard": "PREAUTH",
"giftCard": "PURCHASE",
"payPal": "PURCHASE",
"googlePay": {
"creditCard": "PREAUTH",
"debitCard": "PURCHASE"
},
"applePay": {
"creditCard": "PREAUTH",
"debitCard": "PURCHASE"
}
},
"merchantPayload": {
"payload": {
"requires3DS": true
},
"schemaId": "0a221353-b26c-4848-9a77-4a8bcbacf228"
},
"clientReference": "UNIQUE_CLIENT_REFERENCE",
"orderNumber": "UNIQUE_ORDER_NO",
"payments": [
{
"paymentInstrumentId": "213553",
"amount": 10.5
},
{
"paymentInstrumentId": "215319",
"amount": 6.5
}
]
},
"meta": {
"fraud": {
"provider": "cybersource",
"version": "CyberSourceTransaction_1.101",
"format": "XML",
"responseFormat": "XML",
"message": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\r\n<RequestMessage xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\r\n <merchantID>TEST_MERCHANT_ID</merchantID>\r\n <merchantReferenceCode>1234-26IO8JUN</merchantReferenceCode>\r\n <billTo>\r\n <firstName>Jane</firstName>\r\n <lastName>Doe</lastName>\r\n <street1>407 ELIZABETH STREET</street1>\r\n <city>SURRY HILLS</city>\r\n <state>NSW</state>\r\n <postalCode>2199</postalCode>\r\n <country>AU</country>\r\n <phoneNumber>0400000000</phoneNumber>\r\n <email>[email protected]</email>\r\n <ipAddress>202.39.111.236</ipAddress>\r\n <dateOfBirth>1987-02-14</dateOfBirth>\r\n <customerID>3732442</customerID>\r\n </billTo>\r\n <shipTo>\r\n <firstName>Jane</firstName>\r\n <lastName>Doe</lastName>\r\n <phoneNumber>0400000000</phoneNumber>\r\n <email>[email protected]</email>\r\n </shipTo>\r\n <item id=\"0\">\r\n <unitPrice>7.59</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Mccain Protein Plus Frozen Meal Satay Chicken</productName>\r\n <productSKU>483660</productSKU>\r\n </item>\r\n <item id=\"1\">\r\n <unitPrice>2.00</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Habee Savers Needles Household Repair</productName>\r\n <productSKU>159489</productSKU>\r\n </item>\r\n <item id=\"2\">\r\n <unitPrice>6.60</unitPrice>\r\n <quantity>5</quantity>\r\n <productName>Chicken Breast Fillet Skinless Small</productName>\r\n <productSKU>118963</productSKU>\r\n </item>\r\n <item id=\"3\">\r\n <unitPrice>5.43</unitPrice>\r\n <quantity>5</quantity>\r\n <productName>Chicken Drumsticks </productName>\r\n <productSKU>169014</productSKU>\r\n </item>\r\n <item id=\"4\">\r\n <unitPrice>3.50</unitPrice>\r\n <quantity>4</quantity>\r\n <productName>Chicken Thigh Cutlets Skinless</productName>\r\n <productSKU>166830</productSKU>\r\n </item>\r\n <item id=\"5\">\r\n <unitPrice>10.80</unitPrice>\r\n <quantity>4</quantity>\r\n <productName>Lamb Diced Heart Smart</productName>\r\n <productSKU>208970</productSKU>\r\n </item>\r\n <item id=\"6\">\r\n <unitPrice>4.94</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Macro Chicken Lovely Legs Free Range</productName>\r\n <productSKU>700257</productSKU>\r\n </item>\r\n <item id=\"7\">\r\n <unitPrice>19.64</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Macro Organic Whole Chicken</productName>\r\n <productSKU>229320</productSKU>\r\n </item>\r\n <item id=\"8\">\r\n <unitPrice>9.60</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Msa Australian Beef Steak Porterhouse</productName>\r\n <productSKU>208988</productSKU>\r\n </item>\r\n <item id=\"9\">\r\n <unitPrice>15.20</unitPrice>\r\n <quantity>3</quantity>\r\n <productName>Roast Pork Shoulder Boneless Small</productName>\r\n <productSKU>203420</productSKU>\r\n </item>\r\n <item id=\"10\">\r\n <unitPrice>10.80</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Select Corned Beef Silverside </productName>\r\n <productSKU>148345</productSKU>\r\n </item>\r\n <item id=\"11\">\r\n <unitPrice>13.00</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Clairol Nice N Easy 114a Natural Lightest Golden Brown</productName>\r\n <productSKU>226536</productSKU>\r\n </item>\r\n <purchaseTotals>\r\n <currency>AUD</currency>\r\n <grandTotalAmount>298.09</grandTotalAmount>\r\n </purchaseTotals>\r\n <merchantDefinedData>\r\n <mddField id=\"19\">Pickup</mddField>\r\n <mddField id=\"10\">NO</mddField>\r\n <mddField id=\"3\">Woolworths WOLLI CREEK, WOLLI CREEK</mddField>\r\n <mddField id=\"1\">2017-09-22 16:00</mddField>\r\n <mddField id=\"2\">NSW</mddField>\r\n <mddField id=\"12\">NO</mddField>\r\n <mddField id=\"16\">103</mddField>\r\n <mddField id=\"23\"></mddField>\r\n <mddField id=\"17\">2017-09-18 12:40</mddField>\r\n <mddField id=\"18\">2017-09-18 12:40</mddField>\r\n <mddField id=\"25\">2017-09-22 16:00</mddField>\r\n <mddField id=\"20\">WEB</mddField>\r\n <mddField id=\"57\">Normal</mddField>\r\n <mddField id=\"58\"></mddField>\r\n <mddField id=\"59\" />\r\n <mddField id=\"60\">298.09</mddField>\r\n </merchantDefinedData>\r\n <afsService run=\"true\" />\r\n <deviceFingerprintID>18S###-26IO####</deviceFingerprintID>\r\n</RequestMessage>"
},
"challengeResponses": [
{
"instrumentId": "213553",
"type": "STEP_UP",
"token": "55bda344-c0ec-####-####-############"
}
]
}
}'
var myHeaders = new Headers();
var environment = "substitute environment-value here"
var yourAPIkey = "YOUR-API-KEY";
var accessToken = "ACCESS-TOKEN";
var selectedIntrument1 = "1ST_SELECTED_INTRUMENT_NUMBER"
var selectedIntrument2 = "2ND_SELECTED_INTRUMENT_NUMBER"
myHeaders.append("X-Api-Key", yourAPIKey);
myHeaders.append("Authorization", `Bearer ${accessToken}`);
myHeaders.append("x-guest", "false");
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({
"data": {
"transactionType": {
"creditCard": "PREAUTH",
"giftCard": "PURCHASE",
"payPal": "PURCHASE",
"googlePay": {
"creditCard": "PREAUTH",
"debitCard": "PURCHASE"
},
"applePay": {
"creditCard": "PREAUTH",
"debitCard": "PURCHASE"
}
},
"merchantPayload": {
"payload": {
"requires3DS": true
},
"schemaId": "0a221353-b26c-4848-9a77-4a8bcbacf228"
},
"clientReference": "UNIQUE_CLIENT_REFERENCE",
"orderNumber": "UNIQUE_ORDER_NO",
"payments": [
{
"paymentInstrumentId": selectedInstrument1,
"amount": 10.5
},
{
"paymentInstrumentId": selectedInstrument2,
"amount": 6.5
}
]
},
"meta": {
"fraud": {
"provider": "cybersource",
"version": "CyberSourceTransaction_1.101",
"format": "XML",
"responseFormat": "XML",
"message": "<?xml version="1.0" encoding="Windows-1252"?>rn<RequestMessage xmlns:xsd="http: //www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">rn <merchantID>TEST_MERCHANT_ID</merchantID>rn <merchantReferenceCode>1234-26IO8JUN</merchantReferenceCode>rn <billTo>rn <firstName>Jane</firstName>rn <lastName>Doe</lastName>rn <street1>407 ELIZABETH STREET</street1>rn <city>SURRY HILLS</city>rn <state>NSW</state>rn <postalCode>2199</postalCode>rn <country>AU</country>rn <phoneNumber>0400000000</phoneNumber>rn <email>[email protected]</email>rn <ipAddress>202.39.111.236</ipAddress>rn <dateOfBirth>1987-02-14</dateOfBirth>rn <customerID>3732442</customerID>rn </billTo>rn <shipTo>rn <firstName>Jane</firstName>rn <lastName>Doe</lastName>rn <phoneNumber>0400000000</phoneNumber>rn <email>[email protected]</email>rn </shipTo>rn <item id="0">rn <unitPrice>7.59</unitPrice>rn <quantity>2</quantity>rn <productName>Mccain Protein Plus Frozen Meal Satay Chicken</productName>rn <productSKU>483660</productSKU>rn </item>rn <item id="1">rn <unitPrice>2.00</unitPrice>rn <quantity>2</quantity>rn <productName>Habee Savers Needles Household Repair</productName>rn <productSKU>159489</productSKU>rn </item>rn <item id="2">rn <unitPrice>6.60</unitPrice>rn <quantity>5</quantity>rn <productName>Chicken Breast Fillet Skinless Small</productName>rn <productSKU>118963</productSKU>rn </item>rn <item id="3">rn <unitPrice>5.43</unitPrice>rn <quantity>5</quantity>rn <productName>Chicken Drumsticks </productName>rn <productSKU>169014</productSKU>rn </item>rn <item id="4">rn <unitPrice>3.50</unitPrice>rn <quantity>4</quantity>rn <productName>Chicken Thigh Cutlets Skinless</productName>rn <productSKU>166830</productSKU>rn </item>rn <item id="5">rn <unitPrice>10.80</unitPrice>rn <quantity>4</quantity>rn <productName>Lamb Diced Heart Smart</productName>rn <productSKU>208970</productSKU>rn </item>rn <item id="6">rn <unitPrice>4.94</unitPrice>rn <quantity>2</quantity>rn <productName>Macro Chicken Lovely Legs Free Range</productName>rn <productSKU>700257</productSKU>rn </item>rn <item id="7">rn <unitPrice>19.64</unitPrice>rn <quantity>2</quantity>rn <productName>Macro Organic Whole Chicken</productName>rn <productSKU>229320</productSKU>rn </item>rn <item id="8">rn <unitPrice>9.60</unitPrice>rn <quantity>2</quantity>rn <productName>Msa Australian Beef Steak Porterhouse</productName>rn <productSKU>208988</productSKU>rn </item>rn <item id="9">rn <unitPrice>15.20</unitPrice>rn <quantity>3</quantity>rn <productName>Roast Pork Shoulder Boneless Small</productName>rn <productSKU>203420</productSKU>rn </item>rn <item id="10">rn <unitPrice>10.80</unitPrice>rn <quantity>2</quantity>rn <productName>Select Corned Beef Silverside </productName>rn <productSKU>148345</productSKU>rn </item>rn <item id="11">rn <unitPrice>13.00</unitPrice>rn <quantity>2</quantity>rn <productName>Clairol Nice N Easy 114a Natural Lightest Golden Brown</productName>rn <productSKU>226536</productSKU>rn </item>rn <purchaseTotals>rn <currency>AUD</currency>rn <grandTotalAmount>298.09</grandTotalAmount>rn </purchaseTotals>rn <merchantDefinedData>rn <mddField id="19">Pickup</mddField>rn <mddField id="10">NO</mddField>rn <mddField id="3">Woolworths WOLLI CREEK, WOLLI CREEK</mddField>rn <mddField id="1">2017-09-22 16:00</mddField>rn <mddField id="2">NSW</mddField>rn <mddField id="12">NO</mddField>rn <mddField id="16">103</mddField>rn <mddField id="23"></mddField>rn <mddField id="17">2017-09-18 12:40</mddField>rn <mddField id="18">2017-09-18 12:40</mddField>rn <mddField id="25">2017-09-22 16:00</mddField>rn <mddField id="20">WEB</mddField>rn <mddField id="57">Normal</mddField>rn <mddField id="58"></mddField>rn <mddField id="59" />rn <mddField id="60">298.09</mddField>rn </merchantDefinedData>rn <afsService run="true" />rn <deviceFingerprintID>18S###-26IO####</deviceFingerprintID>rn</RequestMessage>"
},
"challengeResponses": [
{
"instrumentId": selectedInstrument1,
"type": "STEP_UP",
"token": "55bda344-c0ec-####-####-############"
}
]
}
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch(`https://${environment}.wpay.com.au/wow/v1/pay/instore/customer/payments`, requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
1.2. Check Payment Response to Determine if 3DS Authentication is Required
{
"data": {
"transactionId": "9b8e30bb-c8bb-4762-8a47-2233e59c21d7",
"paymentRequestId": "1037fca0-9118-4664-9f63-696ecbcfe44d",
"type": "PAYMENT",
"status": "REJECTED",
"rollback": "NOT_REQUIRED",
"grossAmount": 50.5,
"executionTime": "2022-02-21T08:51:54.908Z",
"merchantReferenceId": "82799438",
"clientReference": "80085011",
"instruments": [
{
"paymentInstrumentId": "2159648",
"instrumentType": "CREDIT_CARD",
"transactions": []
}
],
"subTransactions": [
{
"errorCode": "3DS_001",
"errorMessage": "3DS TOKEN REQUIRED",
"threeDS": {
"paymentInstrumentId": "2159648",
"sessionId": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxMDM3ZmNhMC05MTE4LTQ2NjQtOWY2My02OTZlY2JjZmU0NGQiLCJpYXQiOjE2NDU0MzM1MTguMDQzLCJpc3MiOiI2MGI2ODk3ZDhmZjhhNzQ5OGY4ZDFhYmUiLCJPcmdVbml0SWQiOiI2MGFmOGExZTBiYWM1ZDUwY2MyNmYzM2MiLCJQYXlsb2FkIjp7InBheW1lbnRJbnN0cnVtZW50SWQiOiIyMTU5NjQ4IiwidG9rZW5UeXBlIjoiUEFOIiwib3JkZXJJbmZvcm1hdGlvbiI6eyJhbW91bnREZXRhaWxzIjp7ImN1cnJlbmN5IjoiQVVEIiwiYW1vdW50Ijo1MC41fX19LCJPYmplY3RpZnlQYXlsb2FkIjp0cnVlLCJSZWZlcmVuY2VJZCI6IjVlYThkYThmLTVkOWYtNGZlYy04Nzg5LWE1NGM5Mzg2MzlkYyJ9.xcz0QKB6Ngq7zDPVk_rOALTwvzo-tQm-0u9D3OHek0g"
}
}
]
},
"meta": {}
}
Where:
- The
"errorCode": "3DS_001"
indicate that a 3DS token is required and that 3DS authentication should be requested. - The
threeDS
-sessionId
is required when completing authentication via 3DS in the next step.
2. Request 3DS2 Authentication
Using the sessionId
obtained in the previous step you will use the Wpay Frames SDK to request 3DS authentication from your customer's issuing bank.
if (paymentResponse.status === 'APPROVED') {
paymentComplete = true;
paymentStatus = 'Payment Complete';
} else {
// If error code is 3DS_001 then failure was due to a 3DS challenge
if (paymentResponse.subTransactions[0].errorCode === '3DS_001') {
const sessionId = paymentResponse.subTransactions[0].threeDS.sessionId;
// Perform 3DS authentication
const threeDSResponse = await capture3DS(sessionId, this.selectedInstrument, FRAMES.ActionTypes.ValidatePayment);
if (threeDSResponse.threeDSData &&
(threeDSResponse.threeDSData.status === 'AUTHENTICATION_SUCCESSFUL' ||
threeDSResponse.threeDSData.ActionCode === 'SUCCESS')) {
challengeResponses.push(
threeDSResponse.challengeResponse,
);
} else {
paymentFailed = true;
this.paymentStatus =
(threeDSResponse.threeDSData && threeDSResponse.threeDSData.Payment &&
threeDSResponse.threeDSData.Payment.ExtendedData &&
threeDSResponse.threeDSData.Payment.ExtendedData.ChallengeCancel === '01') ?
'Payment Failed - 3DS verification cancelled by user' :
'Payment Failed - 3DS verification failed';
}
} else {
paymentFailed = true;
paymentStatus = 'Payment Failed';
}
}
Where:
cardCaptureResponse.errorCode
will show any errors encoutered during 3DS authentication as defined in the section Error Codes
2.1. Authenticate payment via 3DS
Usually a customer will be authenticated frictionlessly meaning that no customer authentication is required, however in some cases the card issuer may require additional authentication. In this case a challenge-response is requested from the customer. This usually takes the form of an OTP via SMS.
Where a challenge-response is generated from the customer's issuer you will render a 3DS Challenge Model. While the content is controlled by the issuer there are some modifications that can be made to better fit this model into your existing CX.
Controlling the visibility of the 3DS Challenge Model.
The Model can be controlled in a couple of ways, size and the spinner.
let showSpinner = true;
private async capture3DS(sessionId, paymentInstrumentId, actionType) {
const enrollmentRequest = {
sessionId,
paymentInstrumentId,
threeDS: {
consumerAuthenticationInformation: {
acsWindowSize: settings.customer.acsWindowSize,
},
},
};
// Create a new payment validation frames action
const action = framesSDK.createAction(actionType, enrollmentRequest);
// Start the action, creating a new JWT and initialising cardinal
await action.start();
// Set the placeholder for the challenge IFrame to be injected
action.createFramesControl('3DSValidation', 'overlay');
const elementHandle = document.getElementById('overlay');
const renderEventListener = () => {
this.showSpinner = false;
this.show3DS = true;
};
const closeEventListener = () => {
this.showSpinner = true;
this.show3DS = false;
};
// Add the event listeners for OnRender and OnClose for the 3DS challenge response
elementHandle.addEventListener(FRAMES.FramesCardinalEventType.OnRender, renderEventListener);
elementHandle.addEventListener(FRAMES.FramesCardinalEventType.OnClose, closeEventListener);
// Check card enrolment, allowing cardinal show issuer challenge
const authorizationResponse = await action.complete();
// Romove the event listeners for OnRender and OnClose for the 3DS challenge response
elementHandle.removeEventListener(FRAMES.FramesCardinalEventType.OnRender, renderEventListener);
elementHandle.removeEventListener(FRAMES.FramesCardinalEventType.OnClose, closeEventListener);
// 3DS check complete, use returned information to provide a challenge response within the payment endpoint
console.log(`3DS authorization complete: ${JSON.stringify(authorizationResponse)}`);
if (actionType === FRAMES.ActionTypes.ValidatePayment) {
paymentAuthentication = authorizationResponse;
} else if (actionType === FRAMES.ActionTypes.ValidateCard) {
cardValidation = authorizationResponse;
}
return authorizationResponse;
}
<div class="container">
<!--
3DS iFrame Challenge response placeholer.
Includes a Vue.js class which controls the visible of this model,
based on the value of the show3DS variable.
-->
<div
id="overlay"
class="overlay"
style=""
v-bind:class="{ hidden: !this.show3DS }">
</div>
<!-- Card Capture iFrame place holder -->
<div id="cardGroupPlaceholder"></div>
<!--
Display the Spinner component, when
the paymentDisabled variable is true or
the showSpinner variable is true.
-->
<div class="processing"
v-bind:class="{ hidden: !this.paymentDisabled || this.showSpinner === false }">
<Spinner/>
</div>
</div>
/*
You provide can style the 3DS Challenge reponse iframe model
with custom css as shown below:
*/
.overlay {
position: fixed; top: 0; bottom: 0; left: 0; right: 0; background: rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
align-items: center;
z-index: 1;
justify-content: center;
}
.overlay iframe {
background: white;
padding: 5px;
border-radius: 5px;
border: 1px solid black;
}
/* Positioning the Spinner component. */
.processing {
text-align: center;
}
Where:
acsWindowSize
allows you to control the size of the 3DS challenge window and has values defined in the FAQs- After validation of the card entered by the user the
showSpinner
is set to try showing a spinner while we wait for the issuer to return
Show the 3DS payment challenge response modal
When action.complete
is called and the renderEventListener
is fired, causing:
- the
showSpinner
to be set tofalse
, causing this spinner to be hidden and - the
show3DS
variable will be set totrue
, causing the Challenge Response Modal to be displayed like the one shown below:

Sample 3DS2 OTP screen for a $12 payment
Once the challenge is authenticated (in the above example this means the one time password that has been texted to the customer is entered and submitted), the closeEventListener
is fired, setting the show3DS
variable to false
hiding the challenge-response iFrame.
Example of 3DS Challenge Response:
Below is an example of the response from the 3DS authentication request made through the Frames SDK. You can take the response as is and use it when making a payment as part of the challengeResponses
array in the next step.
{
"type": "3DS-frictionless",
"instrumentId": "213553",
"token": "{{challengeResponseToken}}",
"reference": "{{ServerJWT}}"
}
3. Make a Final Payment Request including the 3DS Data
Now that we've completed our 3DS authentication we can add the required 3DS data to the challengeResponses
and attempt to reprocess the payment.
curl --location --request POST 'https://{{environment}}.wpay.com.au/wow/v1/pay/instore/customer/payments' \
--header 'X-Api-Key: {{yourAPIKey}}' \
--header 'Authorization: Bearer {{yourBearerToken}}' \
--header 'x-guest: false' \
--header 'Content-Type: application/json' \
--data-raw '{
"data": {
"transactionType": {
"creditCard": "PREAUTH",
"giftCard": "PURCHASE",
"payPal": "PURCHASE",
"googlePay": {
"creditCard": "PREAUTH",
"debitCard": "PURCHASE"
},
"applePay": {
"creditCard": "PREAUTH",
"debitCard": "PURCHASE"
}
},
"merchantPayload": {
"payload": {
"requires3DS": true
},
"schemaId": "0a221353-b26c-4848-9a77-4a8bcbacf228"
},
"clientReference": "UNIQUE_CLIENT_REFERENCE",
"orderNumber": "UNIQUE_ORDER_NO",
"payments": [
{
"paymentInstrumentId": "213553",
"amount": 10.5
},
{
"paymentInstrumentId": "215319",
"amount": 6.5
}
]
},
"meta": {
"fraud": {
"provider": "cybersource",
"version": "CyberSourceTransaction_1.101",
"format": "XML",
"responseFormat": "XML",
"message": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\r\n<RequestMessage xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\r\n <merchantID>TEST_MERCHANT_ID</merchantID>\r\n <merchantReferenceCode>1234-26IO8JUN</merchantReferenceCode>\r\n <billTo>\r\n <firstName>Jane</firstName>\r\n <lastName>Doe</lastName>\r\n <street1>407 ELIZABETH STREET</street1>\r\n <city>SURRY HILLS</city>\r\n <state>NSW</state>\r\n <postalCode>2199</postalCode>\r\n <country>AU</country>\r\n <phoneNumber>0400000000</phoneNumber>\r\n <email>[email protected]</email>\r\n <ipAddress>202.39.111.236</ipAddress>\r\n <dateOfBirth>1987-02-14</dateOfBirth>\r\n <customerID>3732442</customerID>\r\n </billTo>\r\n <shipTo>\r\n <firstName>Jane</firstName>\r\n <lastName>Doe</lastName>\r\n <phoneNumber>0400000000</phoneNumber>\r\n <email>[email protected]</email>\r\n </shipTo>\r\n <item id=\"0\">\r\n <unitPrice>7.59</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Mccain Protein Plus Frozen Meal Satay Chicken</productName>\r\n <productSKU>483660</productSKU>\r\n </item>\r\n <item id=\"1\">\r\n <unitPrice>2.00</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Habee Savers Needles Household Repair</productName>\r\n <productSKU>159489</productSKU>\r\n </item>\r\n <item id=\"2\">\r\n <unitPrice>6.60</unitPrice>\r\n <quantity>5</quantity>\r\n <productName>Chicken Breast Fillet Skinless Small</productName>\r\n <productSKU>118963</productSKU>\r\n </item>\r\n <item id=\"3\">\r\n <unitPrice>5.43</unitPrice>\r\n <quantity>5</quantity>\r\n <productName>Chicken Drumsticks </productName>\r\n <productSKU>169014</productSKU>\r\n </item>\r\n <item id=\"4\">\r\n <unitPrice>3.50</unitPrice>\r\n <quantity>4</quantity>\r\n <productName>Chicken Thigh Cutlets Skinless</productName>\r\n <productSKU>166830</productSKU>\r\n </item>\r\n <item id=\"5\">\r\n <unitPrice>10.80</unitPrice>\r\n <quantity>4</quantity>\r\n <productName>Lamb Diced Heart Smart</productName>\r\n <productSKU>208970</productSKU>\r\n </item>\r\n <item id=\"6\">\r\n <unitPrice>4.94</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Macro Chicken Lovely Legs Free Range</productName>\r\n <productSKU>700257</productSKU>\r\n </item>\r\n <item id=\"7\">\r\n <unitPrice>19.64</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Macro Organic Whole Chicken</productName>\r\n <productSKU>229320</productSKU>\r\n </item>\r\n <item id=\"8\">\r\n <unitPrice>9.60</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Msa Australian Beef Steak Porterhouse</productName>\r\n <productSKU>208988</productSKU>\r\n </item>\r\n <item id=\"9\">\r\n <unitPrice>15.20</unitPrice>\r\n <quantity>3</quantity>\r\n <productName>Roast Pork Shoulder Boneless Small</productName>\r\n <productSKU>203420</productSKU>\r\n </item>\r\n <item id=\"10\">\r\n <unitPrice>10.80</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Select Corned Beef Silverside </productName>\r\n <productSKU>148345</productSKU>\r\n </item>\r\n <item id=\"11\">\r\n <unitPrice>13.00</unitPrice>\r\n <quantity>2</quantity>\r\n <productName>Clairol Nice N Easy 114a Natural Lightest Golden Brown</productName>\r\n <productSKU>226536</productSKU>\r\n </item>\r\n <purchaseTotals>\r\n <currency>AUD</currency>\r\n <grandTotalAmount>298.09</grandTotalAmount>\r\n </purchaseTotals>\r\n <merchantDefinedData>\r\n <mddField id=\"19\">Pickup</mddField>\r\n <mddField id=\"10\">NO</mddField>\r\n <mddField id=\"3\">Woolworths WOLLI CREEK, WOLLI CREEK</mddField>\r\n <mddField id=\"1\">2017-09-22 16:00</mddField>\r\n <mddField id=\"2\">NSW</mddField>\r\n <mddField id=\"12\">NO</mddField>\r\n <mddField id=\"16\">103</mddField>\r\n <mddField id=\"23\"></mddField>\r\n <mddField id=\"17\">2017-09-18 12:40</mddField>\r\n <mddField id=\"18\">2017-09-18 12:40</mddField>\r\n <mddField id=\"25\">2017-09-22 16:00</mddField>\r\n <mddField id=\"20\">WEB</mddField>\r\n <mddField id=\"57\">Normal</mddField>\r\n <mddField id=\"58\"></mddField>\r\n <mddField id=\"59\" />\r\n <mddField id=\"60\">298.09</mddField>\r\n </merchantDefinedData>\r\n <afsService run=\"true\" />\r\n <deviceFingerprintID>18S###-26IO####</deviceFingerprintID>\r\n</RequestMessage>"
},
"challengeResponses": [
{
"instrumentId": "213553",
"type": "STEP_UP",
"token": "55bda344-c0ec-####-####-############"
},
{
"type": "3DS-frictionless",
"instrumentId": "213553",
"token": "{{challengeResponseToken}}",
"reference": "{{ServerJWT}}"
}
]
}
}'
var myHeaders = new Headers();
var environment = "substitute environment-value here"
var yourAPIkey = "YOUR-API-KEY";
var accessToken = "ACCESS-TOKEN";
var challengeResponseToken = "CHALLENGE_RESPONSE_TOKEN";
var serverJWT = "SERVER_JWT";
var selectedIntrument1 = "1ST_SELECTED_INTRUMENT_NUMBER"
var selectedIntrument2 = "2ND_SELECTED_INTRUMENT_NUMBER"
myHeaders.append("X-Api-Key", yourAPIKe);
myHeaders.append("Authorization", `Bearer ${yourBearerToken}`);
myHeaders.append("x-guest", "false");
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({
"data": {
"transactionType": {
"creditCard": "PREAUTH",
"giftCard": "PURCHASE",
"payPal": "PURCHASE",
"googlePay": {
"creditCard": "PREAUTH",
"debitCard": "PURCHASE"
},
"applePay": {
"creditCard": "PREAUTH",
"debitCard": "PURCHASE"
}
},
"merchantPayload": {
"payload": {
"requires3DS": true
},
"schemaId": "0a221353-b26c-4848-9a77-4a8bcbacf228"
},
"clientReference": "UNIQUE_CLIENT_REFERENCE",
"orderNumber": "UNIQUE_ORDER_NO",
"payments": [
{
"paymentInstrumentId": selectedIntrument1,
"amount": 10.5
},
{
"paymentInstrumentId": selectedIntrument2,
"amount": 6.5
}
]
},
"meta": {
"fraud": {
"provider": "cybersource",
"version": "CyberSourceTransaction_1.101",
"format": "XML",
"responseFormat": "XML",
"message": "<?xml version="1.0" encoding="Windows-1252"?>rn<RequestMessage xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">rn <merchantID>TEST_MERCHANT_ID</merchantID>rn <merchantReferenceCode>1234-26IO8JUN</merchantReferenceCode>rn <billTo>rn <firstName>Jane</firstName>rn <lastName>Doe</lastName>rn <street1>407 ELIZABETH STREET</street1>rn <city>SURRY HILLS</city>rn <state>NSW</state>rn <postalCode>2199</postalCode>rn <country>AU</country>rn <phoneNumber>0400000000</phoneNumber>rn <email>[email protected]</email>rn <ipAddress>202.39.111.236</ipAddress>rn <dateOfBirth>1987-02-14</dateOfBirth>rn <customerID>3732442</customerID>rn </billTo>rn <shipTo>rn <firstName>Jane</firstName>rn <lastName>Doe</lastName>rn <phoneNumber>0400000000</phoneNumber>rn <email>[email protected]</email>rn </shipTo>rn <item id="0">rn <unitPrice>7.59</unitPrice>rn <quantity>2</quantity>rn <productName>Mccain Protein Plus Frozen Meal Satay Chicken</productName>rn <productSKU>483660</productSKU>rn </item>rn <item id="1">rn <unitPrice>2.00</unitPrice>rn <quantity>2</quantity>rn <productName>Habee Savers Needles Household Repair</productName>rn <productSKU>159489</productSKU>rn </item>rn <item id="2">rn <unitPrice>6.60</unitPrice>rn <quantity>5</quantity>rn <productName>Chicken Breast Fillet Skinless Small</productName>rn <productSKU>118963</productSKU>rn </item>rn <item id="3">rn <unitPrice>5.43</unitPrice>rn <quantity>5</quantity>rn <productName>Chicken Drumsticks </productName>rn <productSKU>169014</productSKU>rn </item>rn <item id="4">rn <unitPrice>3.50</unitPrice>rn <quantity>4</quantity>rn <productName>Chicken Thigh Cutlets Skinless</productName>rn <productSKU>166830</productSKU>rn </item>rn <item id="5">rn <unitPrice>10.80</unitPrice>rn <quantity>4</quantity>rn <productName>Lamb Diced Heart Smart</productName>rn <productSKU>208970</productSKU>rn </item>rn <item id="6">rn <unitPrice>4.94</unitPrice>rn <quantity>2</quantity>rn <productName>Macro Chicken Lovely Legs Free Range</productName>rn <productSKU>700257</productSKU>rn </item>rn <item id="7">rn <unitPrice>19.64</unitPrice>rn <quantity>2</quantity>rn <productName>Macro Organic Whole Chicken</productName>rn <productSKU>229320</productSKU>rn </item>rn <item id="8">rn <unitPrice>9.60</unitPrice>rn <quantity>2</quantity>rn <productName>Msa Australian Beef Steak Porterhouse</productName>rn <productSKU>208988</productSKU>rn </item>rn <item id="9">rn <unitPrice>15.20</unitPrice>rn <quantity>3</quantity>rn <productName>Roast Pork Shoulder Boneless Small</productName>rn <productSKU>203420</productSKU>rn </item>rn <item id="10">rn <unitPrice>10.80</unitPrice>rn <quantity>2</quantity>rn <productName>Select Corned Beef Silverside </productName>rn <productSKU>148345</productSKU>rn </item>rn <item id="11">rn <unitPrice>13.00</unitPrice>rn <quantity>2</quantity>rn <productName>Clairol Nice N Easy 114a Natural Lightest Golden Brown</productName>rn <productSKU>226536</productSKU>rn </item>rn <purchaseTotals>rn <currency>AUD</currency>rn <grandTotalAmount>298.09</grandTotalAmount>rn </purchaseTotals>rn <merchantDefinedData>rn <mddField id="19">Pickup</mddField>rn <mddField id="10">NO</mddField>rn <mddField id="3">Woolworths WOLLI CREEK, WOLLI CREEK</mddField>rn <mddField id="1">2017-09-22 16:00</mddField>rn <mddField id="2">NSW</mddField>rn <mddField id="12">NO</mddField>rn <mddField id="16">103</mddField>rn <mddField id="23"></mddField>rn <mddField id="17">2017-09-18 12:40</mddField>rn <mddField id="18">2017-09-18 12:40</mddField>rn <mddField id="25">2017-09-22 16:00</mddField>rn <mddField id="20">WEB</mddField>rn <mddField id="57">Normal</mddField>rn <mddField id="58"></mddField>rn <mddField id="59" />rn <mddField id="60">298.09</mddField>rn </merchantDefinedData>rn <afsService run="true" />rn <deviceFingerprintID>18S###-26IO####</deviceFingerprintID>rn</RequestMessage>"
},
"challengeResponses": [
{
"instrumentId": "213553",
"type": "STEP_UP",
"token": "55bda344-c0ec-####-####-############"
},
{
"type": "3DS-frictionless",
"instrumentId": "213553",
"token": challengeResponseToken,
"reference": ServerJWT
}
]
}
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch(`https://${environment}.wpay.com.au/wow/v1/pay/instore/customer/payments`, requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
Where:
type
is either 3DS or 3DS-frictionless depending on whether the frictionless or normal 3DS authenticationflow was applied.token
is the challengeResponseToken received from the 3DS authenticationreference
is the ServerJWT received from the 3DS authentication
3DS Payment Success Response
Should the payment be successful you will receive an approved payment. The only difference between the payment response for a successful payment made with vs without a 3DS authenticationis the inclusion of the threeDSData
as part of the response payload.
{
"paymentRequest": {
"expiryTime": "2021-11-17T08:27:32.309Z",
"grossAmount": 12.4,
"usesRemaining": 1,
"merchantPayload": {
"payload": {
"requires3DS": true
},
"schemaId": "0a221353-b26c-4848-9a77-4a8bcbacf228"
},
"paymentRequestId": "cdbf72ab-03f6-4445-98dc-ec79bce91f17",
"merchantReferenceId": "9c92a1f2-89c2-47f4-a1d5-dafe6e89bb50"
},
"cardValidation": {},
"cardCapture": {},
"paymentAuthentication": {
"threeDSData": {
"id": "6371373770786754404005",
"submitTimeUtc": "2021-11-17T08:22:57Z",
"status": "AUTHENTICATION_SUCCESSFUL",
"clientReferenceInformation": {
"code": "cdbf72ab-03f6-4445-98dc-ec79bce91f17"
},
"consumerAuthenticationInformation": {
"acsTransactionId": "f3166c8b-f4c7-484e-99d8-f153fcd14976",
"authenticationTransactionId": "UsFCe2c0h6cmh8S94sg0",
"ecommerceIndicator": "spa",
"eciRaw": "02",
"paresStatus": "Y",
"specificationVersion": "2.2.0",
"threeDSServerTransactionId": "c271835d-d874-413b-846b-17b481bba171",
"ucafAuthenticationData": "Y2FyZGluYWxjb21tZXJjZWF1dGg=",
"ucafCollectionIndicator": "2",
"veresEnrolled": "Y",
"directoryServerTransactionId": "25050f2a-752d-4b7c-a2c8-7c0e8a379e17"
}
},
"challengeResponse": {
"type": "3DS-frictionless",
"instrumentId": "1506694",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjZGJmNzJhYi0wM2Y2LTQ0NDUtOThkYy1lYzc5YmNlOTFmMTciLCJpYXQiOjE2MzcxMzczNzcuNDg3LCJpc3MiOiI2MGI2ODk3ZDhmZjhhNzQ5OGY4ZDFhYmUiLCJPcmdVbml0SWQiOiI2MGFmOGExZTBiYWM1ZDUwY2MyNmYzM2MiLCJQYXlsb2FkIjp7ImlkIjoiNjM3MTM3Mzc3MDc4Njc1NDQwNDAwNSIsInN1Ym1pdFRpbWVVdGMiOiIyMDIxLTExLTE3VDA4OjIyOjU3WiIsInN0YXR1cyI6IkFVVEhFTlRJQ0FUSU9OX1NVQ0NFU1NGVUwiLCJjbGllbnRSZWZlcmVuY2VJbmZvcm1hdGlvbiI6eyJjb2RlIjoiY2RiZjcyYWItMDNmNi00NDQ1LTk4ZGMtZWM3OWJjZTkxZjE3In0sImNvbnN1bWVyQXV0aGVudGljYXRpb25JbmZvcm1hdGlvbiI6eyJhY3NUcmFuc2FjdGlvbklkIjoiZjMxNjZjOGItZjRjNy00ODRlLTk5ZDgtZjE1M2ZjZDE0OTc2IiwiYXV0aGVudGljYXRpb25UcmFuc2FjdGlvbklkIjoiVXNGQ2UyYzBoNmNtaDhTOTRzZzAiLCJlY29tbWVyY2VJbmRpY2F0b3IiOiJzcGEiLCJlY2lSYXciOiIwMiIsInBhcmVzU3RhdHVzIjoiWSIsInNwZWNpZmljYXRpb25WZXJzaW9uIjoiMi4yLjAiLCJ0aHJlZURTU2VydmVyVHJhbnNhY3Rpb25JZCI6ImMyNzE4MzVkLWQ4NzQtNDEzYi04NDZiLTE3YjQ4MWJiYTE3MSIsInVjYWZBdXRoZW50aWNhdGlvbkRhdGEiOiJZMkZ5WkdsdVlXeGpiMjF0WlhKalpXRjFkR2c9IiwidWNhZkNvbGxlY3Rpb25JbmRpY2F0b3IiOiIyIiwidmVyZXNFbnJvbGxlZCI6IlkiLCJkaXJlY3RvcnlTZXJ2ZXJUcmFuc2FjdGlvbklkIjoiMjUwNTBmMmEtNzUyZC00YjdjLWEyYzgtN2MwZThhMzc5ZTE3In19LCJPYmplY3RpZnlQYXlsb2FkIjp0cnVlfQ.OON_4vZk4di0neHFdgBKYznJCP04dn5MxA_thAU5INg",
"reference": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjZGJmNzJhYi0wM2Y2LTQ0NDUtOThkYy1lYzc5YmNlOTFmMTciLCJpYXQiOjE2MzcxMzczNzQuOTE4LCJpc3MiOiI2MGI2ODk3ZDhmZjhhNzQ5OGY4ZDFhYmUiLCJPcmdVbml0SWQiOiI2MGFmOGExZTBiYWM1ZDUwY2MyNmYzM2MiLCJQYXlsb2FkIjp7InBheW1lbnRJbnN0cnVtZW50SWQiOiIxNTA2Njk0IiwidG9rZW5UeXBlIjoiUEFOIiwib3JkZXJJbmZvcm1hdGlvbiI6eyJhbW91bnREZXRhaWxzIjp7ImN1cnJlbmN5IjoiQVVEIiwiYW1vdW50IjoxMi40fX19LCJPYmplY3RpZnlQYXlsb2FkIjp0cnVlLCJSZWZlcmVuY2VJZCI6ImE0YTM0NjY0LTI4NzYtNDhkMC1hNzc5LTEwZGQ3N2JmZjI3ZiJ9.h5isqwE_q_0loex354OkYjap3g1mczStfSXkrVYow_s"
}
},
"transactions": [
{
"type": "PAYMENT",
"status": "APPROVED",
"merchantId": "petculture",
"grossAmount": 12.4,
"instruments": [
{
"transactions": [
{
"type": "PAYMENT",
"amount": 12.4,
"status": "APPROVED",
"executionTime": "2021-11-17T08:22:58.390Z",
"paymentTransactionRef": "1000000021406539"
}
],
"instrumentType": "CREDIT_CARD",
"paymentInstrumentId": "1506694"
}
],
"executionTime": "2021-11-17T08:22:57.834Z",
"transactionId": "9adec1ec-c50e-4b8f-9dcc-122d41333691",
"clientReference": "9adec1ec-c50e-4b8f-9dcc-122d41333691",
"subTransactions": [
{
"fraudResponse": {
"clientId": null,
"decision": null,
"reasonCode": null
},
"partialSuccess": false,
"paymentResponses": [
{
"threeDS": {
"car": null,
"sli": null,
"dsTransID": "25050f2a-752d-4b7c-a2c8-7c0e8a379e17"
},
"receiptData": {
"scheme": "MASTERCARD",
"cardSuffix": "2235",
"expiryYear": "24",
"expiryMonth": "03"
},
"paymentToken": "a1d12c5e-9179-42ee-92ca-671fa9ec90b1",
"externalServiceCode": "00",
"paymentInstrumentId": "1506694",
"paymentInstrumentType": "CREDIT_CARD",
"paymentTransactionRef": "1000000021406539",
"externalServiceMessage": "APPROVED",
"extendedTransactionData": [
{
"field": "bin",
"value": "520000"
},
{
"field": "stan",
"value": "035772"
},
{
"field": "rrn",
"value": "000000035772"
},
{
"field": "mid",
"value": "6110006020Q0001"
},
{
"field": "terminalId",
"value": "Q0001100"
}
]
}
],
"transactionReceipt": "1000000021406539"
}
],
"paymentRequestId": "cdbf72ab-03f6-4445-98dc-ec79bce91f17",
"merchantReferenceId": "9c92a1f2-89c2-47f4-a1d5-dafe6e89bb50-1"
}
]
}
3DS Payment Error Response
Should an error occur either due to payment validation or due to 3DS an error response will be returned as per the below:
{
"data": {
"transactionId": "9b8e30bb-c8bb-4762-8a47-2233e59c21d7",
"paymentRequestId": "1037fca0-9118-4664-9f63-696ecbcfe44d",
"type": "PAYMENT",
"status": "REJECTED",
"rollback": "NOT_REQUIRED",
"grossAmount": 50.5,
"executionTime": "2022-02-21T08:51:54.908Z",
"merchantReferenceId": "82799438",
"clientReference": "80085011",
"instruments": [
{
"paymentInstrumentId": "2159648",
"instrumentType": "CREDIT_CARD",
"transactions": []
}
],
"subTransactions": [
{
"errorCode": "3DS_001",
"errorMessage": "3DS TOKEN REQUIRED",
"threeDS": {
"paymentInstrumentId": "2159648",
"sessionId": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxMDM3ZmNhMC05MTE4LTQ2NjQtOWY2My02OTZlY2JjZmU0NGQiLCJpYXQiOjE2NDU0MzM1MTguMDQzLCJpc3MiOiI2MGI2ODk3ZDhmZjhhNzQ5OGY4ZDFhYmUiLCJPcmdVbml0SWQiOiI2MGFmOGExZTBiYWM1ZDUwY2MyNmYzM2MiLCJQYXlsb2FkIjp7InBheW1lbnRJbnN0cnVtZW50SWQiOiIyMTU5NjQ4IiwidG9rZW5UeXBlIjoiUEFOIiwib3JkZXJJbmZvcm1hdGlvbiI6eyJhbW91bnREZXRhaWxzIjp7ImN1cnJlbmN5IjoiQVVEIiwiYW1vdW50Ijo1MC41fX19LCJPYmplY3RpZnlQYXlsb2FkIjp0cnVlLCJSZWZlcmVuY2VJZCI6IjVlYThkYThmLTVkOWYtNGZlYy04Nzg5LWE1NGM5Mzg2MzlkYyJ9.xcz0QKB6Ngq7zDPVk_rOALTwvzo-tQm-0u9D3OHek0g"
}
}
]
},
"meta": {}
}
Where
errorCode
will give the error received during the payment request. A full list of error codes can be found here.errorMessage
will give a description of the error received.
Additional Information
- A set of 3DS specific test cards are available to validate the full range of results available from issuers
- The list of 3DS error codes are listed here
- 3DS information (e.g. frame sizing) is included on our FAQs
Updated over 1 year ago