Checkout using Javascript Integration
Javascript based integration helps merchants overcome the PCI compliance overheads while it gives them the ultimate flexibility to define the checkout experience for the customer.
In this mode of integration, Juspay provides a card form that merchants can embed in their page. Doing so ensures that the card details are effectively collected on Juspay's page.
PCI Compliance Guidelines
As per PCI DSS guidelines, non compliant merchants cannot store users' card number on their server. The Pay-V3.js implementation on web platform is alternative provided by Juspay through which your website is completely shielded away from getting any sensitive card information.
Create Order
Order creation must be done with Juspay via a backend server to server call. For the API reference, please refer here.
Pay-V3.js
pay-v3.js is the recommended mode of checkout. This latest version uses iFrame elements to take the card input from the user, and a hidden iFrame to send the card information to Juspay servers. This offers better security and reduces the compliance overheads for you.
<script type="text/javascript"
src="https://api.juspay.in/pay-v3.js"></script>
Implementing Checkout Payment Form
Before we get to the details, let's take a quick look at a typical payment form. This is the part you can build with your web framework, or in HTML - whichever way you are used to building forms on web platform.
For New Cards
<form class="juspay_inline_form" id="payment_form">
<input type="hidden" class="merchant_id" value="guest"/>
<input type="hidden" class="order_id" value="guest_order"/>
<div class="card_number_div"></div>
<div class="name_on_card_div"></div>
<div class="card_exp_month_div"></div> - <div class="card_exp_year_div"></div>
<div class="security_code_div"></div>
<input type="checkbox" class="juspay_locker_save"> Save card information
<input type="checkbox" class="tokenize"> Merchant hosted consent screen
<input type="hidden" class="redirect" value="true"/>
<input type="hidden" class="offers" value="62dc1489-6d961ef28bc02617, de2f321f-c4ce-478a-bcca"/>
<input type="hidden" class="payment_channel" value="WEB"/>
<input type="radio" class="auth_type" value="" name="auth_type"> Verify with Secure Password
<button type="submit" id="common_pay_btn">Make Payment</button>
</form>
In the above form, you need to write the <div>
elements for card_number, card_exp_month, card_exp_year, security_code and name_on_card (optional) fields. You need to assign a unique class name for each div as given in above example.
The key tokenize should be passed only when tokenization consent screen is hosted by merchant. The value should be passed as true, only if customer has given consent for tokenization.
The key offers should be passed only when juspay offers are being used. The value for this key can set as the offerID which is received from List Offers
The key payment_channel is an optional field. The values for the same can be - MWEB, WEB, ANDROID or IOS.
Pay-V3.js listens to the form submit event and transports the card information securely to process it for payment. It also supports card tokenization which will tokenize the card information and provide a short-lived token. This token can then be used to initiate the transaction. This is accomplished by the following snippet.
<script type="text/javascript">
var juspay_form = Juspay.Setup({
payment_form: "#payment_form",
success_handler: function (status) {},
error_handler: function (
error_code,
error_message,
bank_error_code,
bank_error_message,
gateway_id
) {},
card_bin_digit_count: 6,
/* Fingerprint will work only if customer_id and client_auth_token are present in set-up as shown below */
customer: {
customer_id: "XXX",
client_auth_token: "tkn_SSS",
},
iframe_elements: {
card_number: {
/* Class name of the <div> which will hold the iframe element for card number. */
container: ".card_number_div",
attributes: {
/* Field Attributes, which you want to set for the <input> field inside the iframe element. */
placeholder: "4111 1111 1111 1111"
}
},
name_on_card: {
/* Class name of the <div> which will hold the iframe element for card holder name. */
container: ".name_on_card_div",
attributes: {
/* Field Attributes, which you want to set for the <input> field inside the iframe element. */
placeholder: "Cardholder Name"
}
},
card_exp_month: {
/* Class name of the <div> which will hold the iframe element for card expiry month. */
container: ".card_exp_month_div",
attributes: {
/* Field Attributes, which you want to set for the <input> field inside the iframe element. */
placeholder: "MM"
}
},
card_exp_year: {
/* Class name of the <div> which will hold the iframe element for card expiry year. */
container: ".card_exp_year_div",
attributes: {
/* Field Attributes, which you want to set for the <input> field inside the iframe element. */
placeholder: "YY"
}
},
security_code: {
/* Class name of the <div> which will hold the iframe element for card security code. */
container: ".security_code_div",
attributes: {
/* Field Attributes, which you want to set for the <input> field inside the iframe element. */
placeholder: "123"
}
}
},
/* Set `auto_tab_enabled` flag to true if you want to enable auto-switching between fields when the user types the valid data (recommended but optional).
* It will have the following order:`card_exp_month` -> `card_exp_year` ->`security_code`. */
auto_tab_enabled : true,
/* Set `auto_tab_from_card_number` to either `card_exp_month` or `name_on_card` based on which field is rendered after card_number (recommended but optional).
* Note 1: Please set `auto_tab_enabled` to `true` as shown above to enable this functionality. */
auto_tab_from_card_number : "card_exp_month",
/* Set `tokenize_support` flag to true if you want to check tokenize support response of a particular card bin. */
tokenize_support : true,
styles: {
/* Add common styling for all input fields here */
"input": {
},
/* Add the styling for card number input field here */
".card_number": {
"line-height": "10px",
"font-size": "16px"
},
/* Add the styling for card holder name input field here */
".name_on_card": {
"line-height": "20px",
"font-size": "16px",
},
/* Add the styling for card expiry month input field here */
".card_exp_month": {
"line-height": "30px",
"font-size": "16px",
"width": "60px"
},
/* Add the styling for card expiry year input field here */
".card_exp_year": {
"line-height": "40px",
"font-size": "16px",
"width": "60px"
},
/* Add the styling for card security code input field here */
".security_code": {
"line-height": "50px",
"font-size": "16px",
"width": "60px"
},
/* Add the styling to be added to input fields in focus state */
":focus": {
}
},
/* This function will be called with an event object as a parameter in two cases:
* 1. When some event occurs on the input field inside the iframe element.
* 2. The user clicks on the submit button and the values in some of the input fields are invalid. (In the second case, we will send the event object with the state of the first invalid field in the checkout form.)
* This event object will contain the state of the input field. You should use this event object to show validation messages in your checkout form. */
iframe_element_callback: function(event) {
/* The event information will be available in the event object */
console.log(event);
switch (event.target_element) {
case "card_number":
if (event.empty) {
frm.find(".card_number_div").addClass("invalid");
} else if (event.valid) {
juspay_form.get_card_fingerprint({ /* This function will give card fingerprint in Pay-v3 callback once complete card number has been entered */
success_handler: function (response) {
console.log("got success_handler response", response);
},
error_handler: function (response) {
console.log("got error_handler response", response);
},
});
frm.find(".card_number_div").removeClass("invalid");
} else if (event.partially_valid) {
frm.find(".card_number_div").removeClass("invalid");
} else {
frm.find(".card_number_div").addClass("invalid");
}
break;
},
},
})
</script>
<script type="text/javascript">
juspay_form.tokenize({
/* juspay_form is the reference of the object returned from Juspay.Setup() */
success_handler : function(response) {
/*
* response.token contains the card token
* response.start_payment() will start the transaction
*/
},
error_handler : function(response) {
}
})
</script>
Async Form Submission
There are cases where you might want to delay a transaction from happening when the user clicks on the “Make Payment” button. One use case for this would be if order ID needs to be generated only when the user clicks on the “Make Payment ” and not for every single page load.
Step 1: Ensure the submit button’s type attribute is changed to “button” instead of “submit”.
<button type=”submit”> Make Payment </button>
<button type=”button”> Make Payment </button>
Step 2: Perform async tasks
Making the button type to button will ensure PayV3 won’t be handling the submit functionality anymore. You now need to add a custom onClick event handler for the above button. Any async actions that need to be performed can be done in this event handler.
If orderID was generated at this point, then the hidden input’s value attribute can be updated at this point.
Step 3: Once async tasks are performed, you can ask PayV3 to perform submit action like:
formElement.onsubmit(new Event("submit"))
For Saved Cards
<form class="juspay_inline_form" id="payment_form1">
<input type="hidden" class="merchant_id" value="guest"/>
<input type="hidden" class="order_id" value="guest_order1"/>
<input type="hidden" class="card_token"/>
<input type="hidden" class="card_isin"/>
<div class="security_code_div"></div>
<input type="radio" class="auth_type" value="" name="auth_type"> Verify with Secure Password
<input type="hidden" class="redirect" value="true"/>
</form>
<form class="juspay_inline_form" id="payment_form2">
<input type="hidden" class="merchant_id" value="guest"/>
<input type="hidden" class="order_id" value="guest_order2"/>
<input type="hidden" class="card_token"/>
<input type="hidden" class="card_isin"/>
<div class="security_code_div"></div>
<input type="radio" class="auth_type" value="" name="auth_type"> Verify with Secure Password
<input type="hidden" class="redirect" value="true"/>
<input type="hidden" class="offers" value="62dc1489-6d961ef28bc02617, de2f321f-c4ce-478a-bcca"/>
<input type="hidden" class="payment_channel" value="WEB"/>
<button type="submit" class="make_payment">Pay</button>
</form>
In the above case, all the forms will have the same class name for common styling and different ids for identification. In the above form, you need to write the <div>
element for security_code fields. All the saved card forms should have the same class name for security_code divs.
<script type="text/javascript">
var juspay_form = Juspay.Setup({
payment_form: "#payment_form",
success_handler: function(status) {},
error_handler: function(error_code, error_message, bank_error_code, bank_error_message, gateway_id) {}
iframe_elements: {
security_code: {
/* Class name of the <div> which will hold the iframe element for card security code. */
container: ".security_code_div",
attributes: {
/* Field Attributes, which you want to set for the <input> field inside the iframe element. */
placeholder: "xxx"
}
}
},
styles: {
/* Add the styling for card security code input field here */
".security_code": {
"line-height": "50px",
"font-size": "16px",
"width": "60px"
},
/* Add the styling to be added to input fields in focus state */
":focus": {
}
},
/*
* This function will be called with an event object as parameter in two cases:
* 1. When some event occurs on the security_code field inside iframe element.
* 2. The user clicks on the submit button and the values in some of the input fields are invalid. (In second case, we will send the event object with state of the first invalid field in checkout form, which is security_code here.)
* This event object will contain the state of the input field. You should use this event object to show validation messages in your checkout form. */
iframe_element_callback: function(event) {
/* The event information will be available in the event object
* 1. event.target_element - (security_code)
* 2. event.valid - (true/false)
* 3. event.empty - (true/false)
* 4. event.card_brand */
}
})
</script>
<script type="text/javascript">
juspay_form.tokenize({
/* juspay_form is the reference of the object returned from Juspay.Setup() */
success_handler : function(response) {
/*
* response.token contains the card token
* response.start_payment() will start the transaction
*/
},
error_handler : function(response) {
}
})
</script>
Note:The parameter "name_on_card" is mandatory for calling tokenize function. If not passed, you might encounter CORS issue.
Pay-V3 Note
There is no need to write input elements here, since Juspay will be inserting their iframe elements inside the div, which will have the input element.
Card Form Validation
Juspay JS will validate the card elements. Merchants are only expected to handle the validation events.
Event | Possible Values | Description |
---|---|---|
event.target_element | card_number/ name_on_card/ card_exp_month/ card_exp_year/ security_code | Name of the field which generated this event |
event.type | focus/ blur/ keyup/ change | This field explains the event type which triggered the event callback |
event.valid | true/ false | This field explains whether the value inside the input field of target_element is valid or not |
event.empty | true/ false | This field explains whether the input field of target_element is empty or not |
event.card_isin | Card bin value of the card number (Available only when target_element is card_number) | |
event.card_brand | MASTERCARD/ VISA/ MAESTRO/ AMEX/ DINERS/ DISCOVER/ JCB/ RUPAY | Card brand value of the card number (Available only when target_element is card_number) |
event.card_type | DEBIT/ CREDIT | Card type identifier of the card number (Available only when target_element is card_number) |
event.card_sub_type | (Only available for >= 9 digit card bin requests) | |
event.partially_valid | This field explains whether the user is typing the card number correctly (Available only when target_element is card_number) | |
event.expiry_valid | This field explains whether the combination of month or year is valid or not. There may be a case when the input year is the current year and the input month is any month before the current month, then you will get valid=true for both month and year separately, but together they are not valid. To keep such cases in mind, you need to validate whether expiry_valid is true or not. (Available only when target_element is either card_exp_month or card_exp_year) | |
event.mandate_support | true/ false | This field explains whether the card number entered is eligible for the mandate transaction |
event.bank | (Only available for >= 9 digit card bin requests) | |
event.tokenize_support | true/ false | This field provides tokenize support response for a particular card bin |
Encoding the Card Details
<script type="text/javascript">
var juspay_form = Juspay.Setup({
payment_form: "#payment_form",
success_handler: function(status) {},
error_handler: function(error_code, error_message, bank_error_code, bank_error_message, gateway_id) {},
card_encoding_key: ":card_encoding_key",
card_encoding_version: "YYYY-MM-DD"
})
</script>
Note: The card_encoding_key can be found on Juspay's dashboard under Settings--> Security tab.
And the card_encoding_version is 2017-04-26.
For Netbanking, Wallets and UPI
<form class="juspay_inline_form" id="payment_form">
<input type="hidden" class="merchant_id" value="guest"/>
<input type="hidden" class="order_id" value="guest_order_101"/>
<input type="hidden" class="payment_method_type" value="NB"/>
<select class="payment_method">
<option value="NB_ALLB" label="Allahabad Bank">Allahabad Bank</option>
<option value="NB_ANDHRA" label="Andhra Bank">Andhra Bank</option>
<option>...</option>
<!-- More banks -->
<option value="NB_YESB" label="YES Bank">YES Bank</option>
</select>
<button type="submit" class="make_payment">Pay</button>
<input type="hidden" class="redirect" value="true"/>
<input type="hidden" class="offers" value="62dc1489-6d96-4c51-8dd0-1ef28bc02617, de2f321f-c4ce-478a-bcca-0b8983cdb506"/>
<input type="hidden" class="payment_channel" value="WEB"/>
</form>
<form class="juspay_inline_form" id="payment_form">
<input type="hidden" class="merchant_id" value="guest"/>
<input type="hidden" class="order_id" value="guest_order_101"/>
<input type="hidden" class="payment_method_type" value="WALLET"/>
<select class="payment_method">
<option value="FREECHARGE" label="Freecharge Wallet">Freecharge Wallet</option>
<option>...</option>
<!-- More wallets -->
<option value="SBIBUDDY" label="SBI Buddy">SBI Buddy</option>
</select>
<button type="submit" class="make_payment">Pay</button>
<input type="hidden" class="redirect" value="true"/>
<input type="hidden" class="offers" value="62dc1489-6d96-4c51-8dd0-1ef28bc02617, de2f321f-c4ce-478a-bcca-0b8983cdb506"/>
<input type="hidden" class="payment_channel" value="WEB"/>
</form>
<form class="juspay_inline_form" id="payment_form">
<input type="hidden" class="merchant_id" value="guest"/>
<input type="hidden" class="order_id" value="guest_order_101"/>
<input type="text" class="upi_vpa" value=""/>
<input type="hidden" class="payment_method_type" value="UPI"/>
<input type="hidden" class="payment_method" value="UPI"/>
<input type="hidden" class="txn_type" value="UPI_COLLECT"/>
<button type="submit" class="make_payment">Pay</button>
<input type="hidden" class="redirect" value="true"/>
<input type="hidden" class="offers" value="62dc1489-6d96-4c51-8dd0-1ef28bc02617, de2f321f-c4ce-478a-bcca-0b8983cdb506"/>
<input type="hidden" class="payment_channel" value="WEB"/>
</form>
Note: Input type - Offers and Payment_Channel are optional fields. Will be required if you use Juspay Offers Module. Learn more about here
<script type="text/javascript">
var juspay_form = Juspay.Setup({
payment_form: "#payment_form",
success_handler: function(status) {},
error_handler: function(error_code, error_message, bank_error_code, bank_error_message, gateway_id) {},
})
</script>
Besides the usual fields, there are some Juspay specific fields which will enable us to process the payment when the form is submitted.
- order_id field represents the order_id of the order object that you have just created.
- merchant_id field represents the merchant_id of your account. This will be provided by the Juspay team.
- payment_method_type field identifies the category of the payment instrument being used. It can be one of CARD, NB, WALLET, etc.
- payment_method field identifies the actual payment instrument being used. (Sample list of payment methods for NetBanking is shown in the form above)
- juspay_locker_save field indicates to Juspay whether we need to store this card after the payment is successful.
- If redirect is true, then we will choose the redirection flow for authentication. Otherwise, a popup window will be used for authentication. By default, popup window will be chosen for authentication.
Using EMI
To support EMI the pay-v3.js has been enhanced to take additional parameters:
- is_emi: Indicates if EMI is applicable for this transaction. Valid values are true and false.
- emi_bank: Issuing bank of the card
- emi_tenure: Tenure of EMI in months
- emi_type: Type of EMI ie STANDARD_EMI or NO_COST_EMI
Note: It is an error to pass is_emi and not pass emi_bank and emi_tenure.
Sample form with EMI support:
<form class="juspay_inline_form" id="payment_form">
<input type="hidden" class="merchant_id" value="guest">
<input type="hidden" class="order_id" value="guest_order"/>
<input type="hidden" class="is_emi" value="true" />
<input type="hidden" class="emi_bank" value="HDFC" />
<input type="hidden" class="emi_tenure" value="6" />
<input type="hidden" class="emi_type" value="STANDARD_EMI" />
<div class="card_number_div"></div>
<div class="name_on_card_div"></div>
<div class="card_exp_month_div"></div> - <div class="card_exp_year_div"></div>
<div class="security_code_div"></div>
<input type="checkbox" class="juspay_locker_save"> Save card information
<button type="submit" class="make_payment">Pay</button>
<input type="hidden" class="redirect" value="false">
<input type="hidden" class="offers" value="62dc1489-6d961ef28bc02617, de2f321f-c4ce-478a-bcca"/>
<input type="hidden" class="payment_channel" value="WEB"/>
</form>