campaign product id (also product2_id, product3_id, etc are allowed)
product1_qty
N
campaign product id quantity (also product2_qty, product3_qty, etc are allowed)
cardNumber
Y
cardMonth
Y
cardYear
Y
salesUrl
Y
The full url of the current page
browserData
Y
paayApiKey
C
Required if the PAAY API key was obtained from an external provider. (or)
Required if you want to use a specific PAAY API key when multiple PAAY plugins are configured
threedsData
O
Authentication Configuration (JSON String Format). See below.
This endpoint enforces fraud plugins and Checkout Champ basic fraud protection prior to calling PAAY. It may be necessary to pass ipAddress or a sessionId to properly evaluate fraud.
Authentication success...
Evaluating the script will return a token (jwt). Send this token on the Import Order API call as threedsAuthToken. An example of this is in the code sample below.
Required if the PAAY API key was obtained from an external provider. (or)
Required if you want to use a specific PAAY API key when multiple PAAY plugins are configured
threedsData
O
Authentication Configuration (JSON String Format). See below.
The responses are the same as noted on the Checkout page
3DS Data
This is a 3DS authentication configuration json string passed as threedsData parameter on both checkout and upsells. The key-value pairs in the json string are detailed in this table. All fields are optional.
Parameter
Description
Example
minimumAmount
Minimum transaction amount to trigger 3DS
100.00
enabledCardTypes
Comma-separated list of allowed card types
VISA, MASTERCARD
binData
Comma-separated BINs
411111,522222
minimumChallengeAmount
Minimum amount to trigger challenge flow
50.00
challengeWindowSize
Refer to PAAY API documentation for supported window sizes (challengeWindowSize)
-
merchantName
The merchant name to be used in the 3DS request
-
requestorName
The threeDSRequestor name to be used in the 3DS request
Force the PAAY challenge time-out in a specific duration (seconds)
rejectOrder
Use this flag to identify validation errors returned by PAAY; if blockOrder is 1 on the response, the order should not be processed.
1 or 0
Code Examples
Client-side code (sample)
Server-side code (sample)
Testing
If the 3DS parameters are passed in properly on the Import call and the transaction goes to a gateway that accepts 3rd Party 3DS you will see a tag that says *3DSecure underneath the result of the transaction.
Suggested PAAY Practices
Rebills
The recommendation is to use PAAY 3RI for rebill authentication
Trial Authentications
For trials, we recommend following these practices:
Hold Trial Charge - Authenticate the cycle 2 transaction amount and send as the initial authentication amount. Do not attempt a PAAY rebill authentication.
Full Authorize & Void and Validate Card Trials or any trial with either no cycle 1 price or only shipping for cycle 1 - Run the PAAY authentication using the cycle 2 transaction amount and then send to Checkout Champ as rebill 3DS parameters.
//Step 1: Common 3DS SDK script for Checkout and Upsale
<!-- Add 3DS SDK script in head tag of page, ensure integrity and crossorigin attributes are added. -->
<script
src="https://resources.checkoutchamp.com/js/sdk/paay-3ds-sdk-1.0.0.min.js"
integrity="sha384-6f1pKbNNie8uqmu3+5yLJHpiXgh28MbNik3nZ14nWgwOibcw1DtaDAm2wG5iGY40"
crossorigin="anonymous"
></script>
//Step 2: Common code example to handle 3DS authentication API response for Checkout and Upsale
<!-- Add below script in head or body tag of page needing 3DS authentication -->
<script type="text/javascript">
// Define 3DS configuration parameters for authentication
// Paramter can be added from server side
// For details about each parameter check ThreeDS Data sheet
function get3DSParameters() {
const parameters = {
"minimumAmount": 0,
"enabledCardTypes": "VISA,MASTERCARD",
"binData": "VISA",
"minimumChallengeAmount": 0,
"merchantName": "Test",
"requestorName": "Test",
"challengeIndicator": "02",
"forceTimeOut": 600,
"rejectOrder": 1,
"challengeWindowSize": "05"
};
return {
threedsData: JSON.stringify(parameters)
};
}
// Function to handle 3DS response and return a status object
function handle3DSResponse(jwt, extra, err) {
const errorMessage = err?.message || "";
if (extra?.blockOrder) {
return {
blockOrder: true,
message: errorMessage
}
}
return {
blockOrder: false,
cc3DSError: errorMessage,
threedsAuthToken: jwt
}
}
// Function to setup 3DS callbacks to be called by SDK
function set3DSCallback() {
window.__paayCallbacks = {
onComplete: function(jwt, extra) {
const authResponse = handle3DSResponse(jwt, extra);
// If blockOrder is true, block buyer from completing transaction
if (authResponse.blockOrder) {
// Display error message (authResponse.message) to buyer
return;
}
// Here proceed with completeChekout or completeUpsale call and pass authResponse as argument
},
onError: function(err, jwt, extra) {
const authResponse = handle3DSResponse(jwt, extra, err);
// If blockOrder is true, block buyer from completing transaction
if (authResponse.blockOrder) {
// Display custom error message (authResponse.message) to buyer
return;
}
// proceed with completeChekout or completeUpsale call and pass authResponse as argument
}
};
}
// Function to dispose 3DS callbacks
function dispose3DSCallback() {
try {
delete window.__paayCallbacks;
} catch(e) {
window.__paayCallbacks = undefined;
}
}
// Code example to call and handle 3DS authentication
async function threedsAuthenticate(authDetails) {
// Status object initialization with blockOrder and message keys
const status = {
blockOrder: false,
message: ""
};
try {
// Check if 3DS SDK object is initialized
// If not initialized returing true to block buyer from completing transaction
if (!window.PAAY3DS) {
status.blockOrder = true;
// Update below statement with appropriate message
status.message = "3DS SDK initialization failed";
return status;
}
// Payload object for 3DS auth API, parameters object is not needed if added from server side code
const parameters = get3DSParameters();
const payload = {
...authDetails,
...parameters
}
// Post API call with 3DS auth details invoking "https://api.checkoutchamp.com/order/threeds/authenticate/" API on server
const response = await fetch("<Base API Url>/threeds/authenticate",
{
headers: {
// Pass API Headers
},
method: "POST",
body: JSON.stringify(payload)
}
);
if (response.result === "SUCCESS") {
const resp = response.message;
// Check if 3DS authentication errored
if (resp?.action?.toLowerCase() === "error" || resp?.result?.toLowerCase() === "error") {
const errorMessage = resp.message || resp.errorMessage || resp.error || 'Unknown server error';
return handle3DSResponse(null, resp?.extra, { message: errorMessage });
}
// Check determining if 3DS auth is needed or not
if (!resp.requires3DS || !resp.script) {
return status;
}
// Setting up 3DS callback for SDK to call
set3DSCallback();
try {
status.blockOrder = true;
status.message = "";
// Evaluating and executing 3DS script returned from authenticate API
eval(resp.script);
return status;
} catch (err) {
status.blockOrder = true;
// Update below statement with custom message
status.message = "";
dispose3DSCallback();
return status;
}
} else {
const message = typeof response?.message === "string" ? response?.message : response?.message?.message;
if (response?.message?.extra?.validationError) {
status.blockOrder = true;
status.message = message;
return status;
}
return handle3DSResponse(response?.message?.jwt, response?.message?.extra, { message });
}
} catch (error) {
status.blockOrder = true;
// Update below statement with custom message or use error.message
status.message = "";
dispose3DSCallback();
return status;
}
}
</script>
//Step 3: Snippet for Checkout pages
<!-- Code example to complete Checkout -->
<script type="text/javascript">
async function completeChekout(authResponse) {
try {
// Add code logic to collect Checkout email, phone, billing, shipping, card (card number, CVV, card month, card year), product and other necessary details. Update below orderDetails object with details.
// ...
const orderDetails = {};
// Add 3DS JWT and Error message to API call payload if exists
if (authResponse.threedsAuthToken) {
orderDetails.threedsAuthToken = authResponse.threedsAuthToken;
}
if (authResponse.cc3DSError) {
orderDetails.cc3DSError = authResponse.cc3DSError;
}
// Post API call with order details invoking "https://api.checkoutchamp.com/order/import/order" API on server
const response = await fetch("<Base API URL>/complete/checkout",
{
headers: {
// Pass CheckoutChamp API headers
},
method: "POST",
body: JSON.stringify(orderDetails)
}
);
const responseData = await response.json();
if (responseData.result === "SUCCESS") {
// Route buyer to next upsell or thank you page
// If required to authroize card for upsell save or collection order id at this setup
// const orderId = responseData.message.orderId;
} else if (responseData.result === "MERC_REDIRECT") {
// Handle merchant redirect
} else {
const errorMessage = result.message;
// Show error on page and allow user to retry
}
} catch (error) {
// Show error on page and allow user to retry
}
}
// Code example of function gets called on submit button click for credit card checkout
async function submitCardCheckoutButtonClick() {
// Add logic below to collect buyer email, phone, billing address, shipping address, product and card (card number, card month, card year) details
// ...
const authDetails = {}
// Check if card number, card month or card year is empty. if yes block transaction and show error message to buyer
if (!authDetails.cardNumber || !authDetails.cardMonth || !authDetails.cardYear) {
// Display custom error message to buyer
return;
}
// Calling threedsAuthenticate function
const authResponse = await threedsAuthenticate(authDetails);
// If authResponse.blockOrder is true, block buyer from completing transaction
if (authResponse.blockOrder) {
// Display custom error message (authResponse.message) to buyer and allow user to retry
return;
}
// Proceed with Checkout
await completeChekout(authResponse);
}
</script>
//Step 4: Snippet for Upsale pages
<!-- Code snippet example to complete Upsale using /Import/Upsale -->
<script type="text/javascript">
async function completeUpsale(authResponse) {
try {
// Add logic to collect Upsell product details and other necessary details. Update below orderDetails object with details.
// ...
const orderDetails = {};
// Add 3DS JWT and Error message to API call payload if exists
if (authResponse.threedsAuthToken) {
orderDetails.threedsAuthToken = authResponse.threedsAuthToken;
}
if (authResponse.cc3DSError) {
orderDetails.cc3DSError = authResponse.cc3DSError;
}
// Post API call with order details invoking "https://api.checkoutchamp.com/order/import/upsale" API on server
const response = await fetch("<Base API URL>/complete/upsale",
{
headers: {
// Pass CheckoutChamp API headers
},
method: "POST",
body: JSON.stringify(authDetails)
}
);
const responseData = await response.json();
if (responseData.result === "SUCCESS") {
// Route buyer to next upsell or thank you page
// If required to authorize card for upsell save or collection order id at this setup
// const orderId = responseData.message.orderId;
} else if (responseData.result === "MERC_REDIRECT") {
// Handle merchant redirect
} else {
const errorMessage = result.message;
// Show error on page and allow user to retry
}
} catch (error) {
// Show error on page and allow user to retry
}
}
</script>
<!-- Code snippet example to call and handle submit for upsale -->
<script type="text/javascript">
async function submitUpsaleOnButtonClick() {
// Add logic to collect product details and other necessary details. Update below authDetails object with details.
// Note 3DS auth on upsell does not require passing buyer email, phone, address, card number, card month and card year details. Inplace of card details pass orderId on threedsAuthenticate request.
// ...
const authDetails = {}
if (!authDetails.orderId) {
// Display custom error message to buyer and allow user to retry
return;
}
const authResponse = await threedsAuthenticate(authDetails);
// If authResponse.blockOrder is true, block buyer from completing transaction
if (authResponse.blockOrder) {
// Display custom error message (authResponse.message) to buyer and allow user to retry
return;
}
// Proceed with Upsale
await completeUpsale(authResponse);
}
</script>
//Step 5: Server Side Code
<!-- Node Express service example -->
const express = require('express');
const axios = require('axios');
const app = express();
const PORT = 3000;
// Middleware to parse JSON request bodies
app.use(express.json());
// Example of API service calling CheckoutChamp 3DS Auth API
// Ensure "/threeds/authenticate" API always responds in below format
// {
// result: "SUCCESS", // or "ERROR"
// message: "<Error Message>" // or 3DS object returned from API
// }
app.post("/threeds/authenticate", (req, res) => {
try {
const payload = req.body;
// Parse and validate rquest body
// Add necessary guard or check before calling 3DS auth API
if (!payload.threedsData) {
return res.status(400).json({
result: "Error",
message: "Invalid request received"
});
}
// For Checkout use below check
if (!payload.cardNumber || !payload.cardYear || !payload.cardMonth) {
return res.status(400).json({
result: "Error",
message: "Missing card details"
});
}
// For Upsell use below check
if (!payload.orderId) {
return res.status(400).json({
result: "Error",
message: "OrderId is required"
});
}
// Add PAAY 3DS API key to payload
payload["paayApiKey"] = "";
const authAPIBaseUrl = new URL("https://api.checkoutchamp.com/order/threeds/authenticate");
// Append each key-value pair from the request object
Object.entries(payload).forEach(([key, value]) => {
authAPIBaseUrl.searchParams.append(key, value);
});
// Converting URL object to URL string with query params
// ALso any other required URL params to below API url
const updatedAuthAPIUrl = authAPIBaseUrl.toString();
// Also add other necessary URL params, auth token or (username or password)
const response = await axios.get(updatedAuthAPIUrl);
res.status(200).json({
result: response.result,
message: response.message
});
} catch (error) {
const statusCode = error.response ? error.response.status : 500;
res.status(statusCode).json({
result: "ERROR",
message: error.message
});
}
});
// Start the server
app.listen(PORT, () => {
console.log("Server Started");
});