JS Checkout Integration
To meet PCI DSS guidelines, your server must not store or process the user’s card detail. PhonePe’s WASL SDK provides an easy integration for a secure web app checkout that manages this for you.
Through this SDK, your website is completely shielded from sensitive card information, simplifying your compliance. The integration process is quick, requires minimal effort via a simple script tag, and delivers a secure, efficient checkout experience.
Integration Steps
- Configure Security: Add the required Content Security Policies (CSP) to your HTML page to ensure the SDK can load and function correctly.
- Load the SDK: Include the SDK library on your page using a simple script tag.
- Initialize the SDK: Instantiate and configure the SDK with your merchant-specific parameters upon page load.
- Handle User Action: Implement the event listener to capture the user’s ‘pay’ or ‘submit’ click, which will initiate the payment process.

Configure Security
To prevent XSS and data injection attacks, your HTML page should implement controlled resource loading with the following CSP policies:
Content-Security-Policy:
- UAT Sandbox : https://mercury-stg.phonepe.com
- Production: script-src ‘self’ https://mercury-t2.phonepe.com frame-src: ‘self’
<!DOCTYPE html>
<html>
<head>
<!-- https://mercury-uat.phonepe.com for integration -->
<meta http-equiv="Content-Security-Policy" content="script-src 'self' https://mercury-t2.phonepe.com frame-src: 'self' https://mercury-t2.phonepe.com">
<!-- https://mercury-uat.phonepe.com for integration -->
<script type="text/javascript" src="https://mercury-t2.phonepe.com/web-sdk/v1/<merchantId>/card-checkout"></script>
<meta name="referrer" content="origin" />
<meta content="width=device-width, initial-scale=1" name="viewport"></meta>
<style type="text/css">
#cardNumberDiv {
height: 42px;
}
#cardHolderNameDiv {
height: 42px;
}
#cardExpiryDiv {
height: 42px;
}
#cardCvvDiv {
height: 42px;
}
.inputfield {
margin-bottom: 32px;
position: relative;
}
.error {
margin-top: 4px;
position: absolute;
display: inline-block;
color: red;
font-size: 12px;
}
</style>
</head>
<body>
<h1>Phonepe card checkout SDK</h1>
<form id="myForm">
<div class="inputfield">
<div id="cardNumberDiv"></div>
<span id="cardNumberError" class="error" style="display: none;"></span>
</div>
<div class="inputfield">
<div id="cardHolderNameDiv">
</div>
<span id="cardHolderNameError" class="error" style="display: none;"></span>
</div>
<div class="inputfield">
<div id="cardExpiryDiv">
</div>
<span id="cardExpiryError" class="error" style="display: none;"></span>
</div>
<div class="inputfield">
<div id="cardCvvDiv">
</div>
<span id="cardCvvError" class="error" style="display: none;"></span>
</div>
<button id="submitBtn">Submit</button>
</form>
</body>
<script src="/js/pay.js"></script>
</html>const errorMapFieldToId = {
cardNumber: 'cardNumberError',
cardHolderName: 'cardHolderNameError',
cardExpiry: 'cardExpiryError',
cardCvv: 'cardCvvError'
};
window.onload = () => {
// Access the sdk instance from global window
const ppSdk = window.PhonepeWidget;
// Now you can use the ppSdk, to initialize the sdk and call the pay method
ppSdk?.init();
const submitBtn = document.getElementById("submitBtn");
submitBtn.addEventListener('click', (e) => {
e.preventDefault();
//Create the order & get the transaction token by doing a backend call to your server (merchant's server)
if(ppSdk) {
ppSdk.pay({
transactionToken: <transactionToken>,
cardData: {...},
callback: (data) => {
// pay api response
if(data.redirectUrl) {
//Depending on use case, Either we can open a new tab or redirect on same window.
window.location = data.redirectUrl;
}
}
})
}
})
};Load the SDK
Load the SDK in your browser by adding the following script tag to your HTML file.
//<!-- https://mercury-stg.phonepe.com for staging -->
<script type="text/javascript" src="https://mercury-t2.phonepe.com/web-sdk/v1/<merchantId>/card-checkout"></script>Initialize the SDK
Once the SDK has successfully loaded on your page, you must call the init method. This method requires a configuration object to be passed as an argument.
try {
window.PhonePeWidget.init();
} catch (error) {
// Catch the error while initilizing the PhonePeWidgit
}Handle User Action
When the user clicks the pay or submit button, you must call the sdk.pay() method and pass a configuration object to it.
📘 Getting the transactionToken
The transactionToken parameter required in the sdk.pay() configuration object is the same token you received from the Create Order API response.
{
transactionToken: string, // from create order api response
cardData: {
cardNumber: string; //Should have numbers only
cardHolderName: string;
expiryMonth: string; //Make sure to follow MM format, eg., 03-> March
expiryYear: string; // Follow YYYY format, eg., 2035
cardCvv: number; // can be of length 3 or 4 digit
},
callback: (data) => {
// handle validation or pay api response (success/failure) here.
}
}When you call the sdk.pay() method, the SDK initiates a two-step process: validation, followed by an API call. The callback destination depends on the outcome of the validation.
- Successful Validation
- If all input fields in the form are in a valid state, the SDK proceeds to call the Pay API.
- The response from this API call is then passed as an argument to the callback function that you provided in the
sdk.pay()method’s configuration.
- Validation Failure
- If any input field is not in a valid state, the SDK stops the process before calling the Pay API.
- It then invokes the callback function that you provided in the
sdk.init()method. - This callback receives an
eventDataobject, wherecurrentEventDatawill contain the state and error details for the first invalid field found in the form.
interface IPaymentSuccessResponse {
orderId: string;
state: string; // 'PENDING' | 'COMPLETED'
redirectUrl: string;
expireAt: number;
}interface IPaymentErrorResponse {
statusCode: string; // error status code ex - 400, 401, 500
message: string; // error message
errorCode: string // error constant , to let merchant use their own error message
}Now that you have integrated your website with the JS checkout flow, the next step is to conduct thorough UAT testing before proceeding to go live.