Element Javascript SDK

The Element SDK allows you to build your own UI and accept payments through Cashfree.

📘

Build your own UI (BYOU)

Element is our SDK solution for accepting payments when merchants want to display their own UI.

Element is our SDK solution for accepting payments when merchants want to display their own UI. Element works by binding itself to your UI elements. It can then process payments by using the values from those elements and initiating payment processing.

Resources

The SDK for sandbox and production are different. Both are listed below.

  • Sandbox:
    <script src="https://sdk.cashfree.com/js/core/1.0.26/bundle.sandbox.js"></script>
  • Production:
    <script src="https://sdk.cashfree.com/js/core/1.0.26/bundle.prod.js"></script>

Step 1: Initialize the Core SDK

Make sure you have included the Cashfree core SDK in your file.

const options = {}
const cfCheckout = Cashfree.initializeApp(options);

The orderToken is the same which we generated in the previous step when creating an order.

The options are handler methods which Cashfree SDK will invoke once the payment has completed.

nametyperequireddescription
onPaymentSuccessFunction (callback)YesHandle payment success
onPaymentFailureFunction (callback)YesHandler for payment failure
onErrorFunction (callback)YesHandler when there in an error while processing payment

Here is an example demonstrating how to initialise the options.

const options = {
	onPaymentSuccess: function(data) {
		console.log("Success:", data);
        /*
        {
            order:{
                    orderId: "some-orderid",
                    orderStatus: "PAID"
            },
            transaction:{
                txStatus: "SUCCESS,
                txMsg: "Transaction Message",
                transactionId: 1232132,
                transactionAmount: 1.00
            }
        }
        */
	},
	onPaymentFailure: function(data) {
		console.log("Failure:", data);
		/*
        {
            order:{
                    orderId: "some-orderid",
                    orderStatus: "ACTIVE"
            },
            transaction:{
                txStatus: "FAILED,
                txMsg: "Transaction Message",
                transactionId: 1232132,
                transactionAmount: 1.00
            }
        }
        */
	},
	onError: function(data) {
		console.log("Error:", data);
		/*
        {
            message: "Invalid card number"
            paymentMode: "card"
            type: "input_validation_error"
        }
        */
	},
};

Step 2: Introducing Elements

When you use the core SDK you will be rendering the payment UI by yourself. To help the SDK capture these details for payment processing, you have to tag these with specific elements which the SDK understands.

There are two ways you can configure elements in the SDK. You can either pass them individually for throw an array.

Passing a single element

const el = cfCheckout.element({
	pay: document.getElementById('pay-card'),
	type: 'card',
});
el.on('change', function(data){
    console.log(data)
});

Passing an array

cfCheckout.elements([
	{
		pay: document.getElementById('pay-card'),
		type: 'card',
		onChange: cardEventHandler
	},
	{
		pay: document.getElementById('pay-intent'),
		type: 'upi-intent',
		onChange: upiIntentHandler
	}
])                            

The sdk will emit the change event which will help you ensure that the input provided is valid. For example - if the card number passes basic checks like Luhn check etc. In the next step, we will show you how to accept payments for different payment instruments.

Step 3: Building components

Card

To accept card payments, you must ask the customer for their card details - card number, expiry month, expiry year, cvv and cardholder name. Prepare your html as below.

<div id="pay-card">
      <table>
           <tr><td>Card number</td><td><input  type="text" value="" data-card-number> </td></tr>
           <tr><td>card expiry MM</td><td><input  type="text" value="" data-card-expiry-mm> </td></tr>
           <tr><td>card expiry YY</td><td><input  type="text" value="" data-card-expiry-yy> </td></tr>
           <tr><td>card cvv</td><td><input  type="password" value="" data-card-cvv></td></tr>
           <tr><td>Card holder</td><td><input  type="text" value="" data-card-holder></td></tr>

      </table>
      <button id="pay-card-btn">Pay</button>
</div>

As you can see here the element created is pay-card. This element is a collection of HTML form inputs with each having a custom attribute. These input HTML elements capture the payment information.

attributedescription
data-card-numberHolds card number
data-card-expiry-mmHolds card expiry month in MM. Example 01 for January and 12 for December. Has to be of length == 2.
data-card-expiry-yyHolds card expiry year in YY format. Example 21 for 2021, 22 for 2022 etc. Has to be of length == 2.
data-card-cvvHolds card cvv. Recommended to use it as type="password"
data-card-holderHolds card holder name

Once you have the html form ready, here is a sample javascript to verify details and initiate payment.

<!doctype html>
<html lang="en">
  <head>
    
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
	<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
    <title>Cashfree Sample</title>
  </head>
  <body class="container">
	  <h1>Test Order Elemental</h1>
	  <div class="row">
		  <div class="d-flex flex-column">
			   <p>Order Amount: 1</p>
				<div id="pay-card">
					<div class="form-group">
						<label for="my-input">Holder Name</label>
						<input class="form-control" type="text" data-card-holder value="John Doe"> 
					</div>
					<div class="form-group">
						<label for="my-input">Card Number</label>
						<input class="form-control"  type="text" data-card-number value="4111111111111111"> 
					</div>
					<div class="form-group">
						<label for="my-input">Expiry MM</label>
						<input class="form-control"  type="text" data-card-expiry-mm value="12"> 
					</div>
					<div class="form-group">
						<label for="my-input">Holder Name</label>
						<input class="form-control"  type="text" data-card-expiry-yy value="24"> 
					</div>
					
					<div class="form-group">
						<label for="my-input">CVV</label>
						<input class="form-control"  type="password" data-card-cvv value="123">
					</div>
					<hr>
					<button class="btn btn-primary" id="pay-btn">Pay</button>
				</div>
		  </div>
	  </div>
    
   


    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
    <script type="text/javascript" src="https://sdk.cashfree.com/js/core/1.0.26/bundle.sandbox.js"></script>
    <script src="main.js"></script>
    
  </body>
</html>
$(document).ready(function (e) {
	let isCardReadyToPay = true;
    const config = {
        onPaymentSuccess: function (data) {
            if (data.order.status == "PAID") {
                $.ajax({
                    url: "checkstatus.php?order_id=" + data.order.orderId,
                    success: function (result) {
                        if (result.order_status == "PAID") {
                            alert("Order PAID");
                        }
                    },
                });
            }
        },
        onPaymentFailure: function (data) {
            alert(data.transaction.txMsg);
        },
        onError: function (err) {
            alert(err.message);
        },
    };
	const cfCheckout = Cashfree.initializeApp(config);
    cfCheckout.elements([
        {
            pay: document.getElementById("pay-card"),
            type: "card",
            onChange: cardEventHandler,
        },
    ]);

    function cardEventHandler(data) {
        isCardReadyToPay = data.isReadyToPay;
    }

    let order_token = "";
    $("#pay-btn").click(async function () {
        if (isCardReadyToPay)
            if (order_token == "") {
                $.ajax({
                    url: "fetchtoken.php",
                    success: async function (result) {
                        order_token = result["order_token"];
                        await cfCheckout.pay(order_token, "card");
                    },
                });
            } else {
                await cfCheckout.pay(order_token, "card");
            }
    });
});
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://sandbox.cashfree.com/pg/orders",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"customer_details\":{\"customer_id\":\"12345\",\"customer_email\":\"[email protected]\",\"customer_phone\":\"1299087801\"},\"order_amount\":1,\"order_currency\":\"INR\",\"order_note\":\"test order\"}",
  CURLOPT_HTTPHEADER => [
    "Accept: application/json",
    "Content-Type: application/json",
    "x-api-version: 2022-01-01",
    "x-client-id: TEST_CLIENT_ID",
    "x-client-secret: TEST_CLIENT_SECRET"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  header('Content-Type: application/json; charset=utf-8');
  echo json_encode(array("error" => 1));
  echo "cURL Error #:" . $err;
  die();

} else {
  $result = json_decode($response, true);
  header('Content-Type: application/json; charset=utf-8');
  $output = array("order_token" => $result["order_token"]);
  echo json_encode($output);
  die();
}
?>
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://sandbox.cashfree.com/pg/orders/" . $_GET["order_id"],
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => [
    "Accept: application/json",
    "Content-Type: application/json",
    "x-api-version: 2021-05-21",
    "x-client-id: TEST_CLIENT_ID",
    "x-client-secret: TEST_CLIENT_SECRET"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  header('Content-Type: application/json; charset=utf-8');
  echo json_encode(array("error" => 1));
  echo "cURL Error #:" . $err;
  die();

} else {
  $result = json_decode($response, true);
  header('Content-Type: application/json; charset=utf-8');
  $output = array("order_status" => $result["order_status"]);
  echo json_encode($output);
  die();
}
?>

UPI Intent

The SDK allows you to capture UPI payments through different methods - intent, a collect request or by creating a QR code. To build an intent workflow, you need to tell the SDK which app is calling the intent.

<div id="pay-intent">
       UPI App <select  data-upi-provider>
              <option value="">select</option>
              <option value="gpay">gpay</option>
              <option value="phonepe">phonepe</option>
              <option value="paytm">paytm</option>
              <option value="bhim">bhim</option>
       </select>
       <button id="pay-intent-btn">Pay</button>
</div>

To setup api-intent we will just add the same javascript code which helps the SDK identify the html element for intent.

const config = {
    onPaymentSuccess: function(data) {},
    onPaymentFailure: function(data) {},
    onError: function(err) {},
};
const cfCheckout = Cashfree.initializeApp(config);
let isUPIIntentReady = false;
let order_token = "";  //order_token is received after create order api is called
cfCheckout.elements([
       {
              pay: document.getElementById('pay-intent'),
              type: 'upi-intent',
              onChange: upiIntentHandler
       }
])
function upiIntentHandler(data){
       console.log("UPI intent --> ", data)
       isUPIIntentReady = data.isReadyToPay
}
$("#pay-intent-btn").click(async function() {
       if(!isUPIIntentReady) {
              alert("UPI Intent not ready to pay!")
              return
       }
      await cfCheckout.pay(order_token, 'upi-intent');
});

The only attribute we need for upi intent is data-upi-provider.

attributedescription
data-upi-providerHold the identifier for the mobile app. Values can be gpay, phonepe, paytm and bhim

UPI Collect

UPI collect based payments refer to customers entering the UPI ID (8987123112@ybl or rohit@okhdfc). We will then send a notification to the customer on their UPI application to approve this payment. Once the customer approves the payment in the upi mobile application, and has enough funds the payment will be completed.

Here is a simple html to render this payment form.

                <div id="pay-collect">
                        UPI Collect  <input  type="text" value="testsuccess@gocash" data-upi-id>
                        <button id="pay-collect-btn">Pay</button>
                </div>

To process payment here is the sample javascript code.


let isUPICollectReady = false;
let order_token = "";  //order_token is received after create order api is called
cfCheckout.elements([
         {
                  pay: document.getElementById('pay-collect'),
                  type: 'upi-collect',
                  onChange: upiCollectHandler
         }
]);

function upiCollectHandler(data){
         console.log("UPI collect --> ", data)
         isUPICollectReady = data.isReadyToPay
}
$("#pay-collect-btn").click(async function() {
         if(!isUPICollectReady) {
                  alert("UPI collect not ready to pay!")
                  return
         }
          await cfCheckout.pay(order_token, 'upi-collect')
});

There is only element attribute required for UPI checkout flow - the UPI id.

attributedescription
data-upi-idHolds the upi id of the customer

UPI QR Code

You can also choose to display a QR code which can be scanned by any UPI app to complete the payment. We do not require any input attributes to build the QR code.

<button id="pay-qr-btn">Pay</button>
<script>
document.getElementById('pay-qr-btn').addEventListener('click', async () => {
	await cfCheckout.pay(orderToken, 'upi-qrcode');
});
</script>

Mobile applications/Wallets

The SDK allows you to pay using different wallets and mobile applications, for instance - Amazon Pay, Google Pay, PhonePe, Jio money, Paytm, Airtel money, Freecharge, etc.

There are two attributes which we need to complete payments for these wallets - the wallet name and customers phone number.

attributedescription
data-app-nameHolds the app name. Values can be gpay phonepe paytm amazon airtel freecharge mobikwik jio ola
data-app-phonePhone number of the customer

Below is a sample payment form to collect app details. We need basically need the two attributes - data-app-name and data-app-phone.

 <div id="pay-app">
         <select  data-app-name>
                  <option value="">select</option>
                  <option value="gpay">gpay</option>
                  <option value="phonepe">phonepe</option>
                  <option value="paytm">paytm</option>
                  <option value="amazon">amazon</option>
                  <option value="airtel">airtel</option>
                  <option value="freecharge">freecharge</option>
                  <option value="mobikwik">mobikwik</option>
                  <option value="jio">jio</option>
                  <option value="ola">ola</option>
         </select>
         <input type="text" data-app-phone />
         <button id="pay-app-btn">Pay</button>
</div>

The javascript code is similar to the previous flows.

let isAppReady = false;
let order_token =  "";
cfCheckout.elements([
         {
                  pay: document.getElementById('pay-app'),
                  type: 'app',
                  onChange: appEventHandler
         },
]);
 function appEventHandler(data){
         console.log("App --> ", data)
         isAppReady = data.isReadyToPay
}
$("#pay-app-btn").click(async function() {
         if(!isAppReady) {
                  alert("App not ready to pay!")
                  return
         }
         await cfCheckout.pay(order_token, 'app')
});

BNPL

The SDK allows you to pay using different paylater applications, for instance - Lazypay, ZestMoney, Flexipay, Kotak, OlaPostpaid, etc.

There are two attributes that we need to complete payments for these wallets - the provider name and customers phone number.

attributedescription
data-providerHolds the app name. Values can be lazypay zestmoney olapostpaid kotak flexipay simpl
data-paylater-phonePhone number of the customer

Below is a sample payment form to collect paylater details. We need basically need the two attributes - data-provider and data-paylater-phone.

 <div id="pay-later">
         <select  data-provider>
                  <option value="">select</option>
                  <option value="lazypay">Lazy Pay</option>
                  <option value="olapostpaid">OlaMoney Post Paid</option>
                  <option value="flexipay">Hdfc Paylater</option>
                  <option value="kotak">Kotak Paylater</option>
                  <option value="zestmoney">Zestmoney pay later</option>
                  <option value="simpl">Simpl</option>
         </select>
         <input type="text" data-paylater-phone />
         <button id="pay-later-btn">Pay</button>
</div>

The javascript code is similar to the previous flows.

let isProviderReady = false;
let order_token = "";
cfCheckout.elements([
         {
                  pay: document.getElementById('pay-later'),
                  type: 'paylater',
                  onChange: paylaterEventHandler
         },
]);
 function paylaterEventHandler(data){
         console.log("App --> ", data)
         isProviderReady = data.isReadyToPay
}
$("#pay-later-btn").click(async function() {
         if(!isProviderReady) {
                  alert("App not ready to pay!")
                  return
         }
          await cfCheckout.pay(order_token, 'paylater')
});

Credit Card EMI

To accept credit card EMI payments, you must ask the customer for the following details - card number, card expiry month, card expiry year, card CVV, bank name, and tenure.

attributedescription
data-emi-numberHolds card number
data-emi-expiry-mmHolds card expiry month in MM. Example 01 for January and 12 for December. Has to be of length == 2.
data-emi-expiry-yyHolds card expiry year in YY format. Example 21 for 2021, 22 for 2022, etc. Has to be of length == 2.
data-emi-cvvHolds card CVV. Recommended to use it as type="password"
data-emi-bankHolds Bank Name for the corresponding card.Values can be HDFC ICICI Kotak RBL BOB Standard Chartered
data-emi-tenureHolds Tenure for the EMI payment.
Values are:
HDFC: 3 6 9 12
ICICI: 3 6 9 12
Kotak: 3 6 9 12 18 20 24 30 36
RBL: 3 6 9 12 18 24
BOB: 3 6 9 12 18 24 36
Standard Chartered: 3 6 9 12
INDUS: 3 6 9 12
AU: 3 6 9 12 18 24
HSBC: 3 6 9 12
YES: 3 6 9 12 18 24
CITI: 3 6 9 12
SBI: 3 6 9 12
FED: 3 6 9 12
Axis: 3 6 9 12 18 24
<div id="pay-ccemi">
      <table>
           <tr><td>Card number</td><td><input  type="text" value="" data-emi-number> </td></tr>
           <tr><td>card expiry MM</td><td><input  type="text" value="" data-emi-expiry-mm>  </td></tr>
           <tr><td>card expiry YY</td><td><input  type="text" value="" data-emi-expiry-yy>  </td></tr>
           <tr><td>card cvv</td><td><input  type="password" value="" data-emi-cvv></td></tr>

           <tr><td>Bank Name</td><td><input  type="text" value="" data-emi-bank></td></tr>
           <tr><td>Tenure</td><td><input  type="text" value="" data-emi-tenure></td></tr>

      </table>
      <button id="pay-ccemi-btn">Pay</button>
</div>

The javascript code is similar to the previous flows.

let isProviderReady = false;
let order_token = "";  //order_token is received after create order api is called
cfCheckout.elements([
         {
                  pay: document.getElementById('pay-ccemi'),
                  type: 'emi',
                  onChange: ccemiEventHandler
         },
]);
 function ccemiEventHandler(data){
         console.log("CCEMI --> ", data)
         isProviderReady = data.isReadyToPay
}
$("#pay-ccemi-btn").click(async function() {
         if(!isProviderReady) {
                  alert("CC EMI not ready to pay!")
                  return
         }
         await cfCheckout.pay(order_token, 'emi')
});

Cardless EMI

The SDK allows you to pay using different cardless applications. For example - Zestmoney, Flexmoney.

There are two attributes that we need to complete payments for cardless EMI - the provider name and customers phone number.

attributedescription
data-cardless-providerHolds the app name. Values can be flexmoney zestmoney.
data-cardless-phonePhone number of the customer

Below is a sample payment form to collect cardless EMI details. We need basically need the two attributes - data-cardless-provider and data-cardless-phone.

 <div id="cardless-emi">
         <select  data-cardless-provider>
                  <option value="">select</option>
                  <option value="flexmoney">FlexMoney</option>
                  <option value="zestmoney">ZestMoney</option>
         </select>
         <input type="text" data-cardless-phone />
         <button id="cardless-emi-btn">Pay</button>
</div>

The javascript code is similar to the previous flows.

let isProviderReady = false;
let order_token = "";
cfCheckout.elements([
         {
                  pay: document.getElementById('cardless-emi'),
                  type: 'cardlessemi',
                  onChange: cardlessEventHandler
         },
]);
function cardlessEventHandler(data){
         console.log("App --> ", data)
         isProviderReady = data.isReadyToPay
}
$("#cardless-emi-btn").click(async function() {
         if(!isProviderReady) {
                  alert("App not ready to pay!")
                  return
         }
          await cfCheckout.pay(order_token, 'cardlessemi')
});

Net Banking

If you want to accept payment using net banking, you will have to build out elements for net banking. There is only attribute for net banking that we receive - the bank code.

attributedescription
data-netbanking-codeHolds the bank code. The bank code is given by Cashfree’s for different banks. It ranges from 3001 to 3999. For example HDFC has a code of 3021
See here for more details.

The javascript code to process net banking payments is again similar to previous flows.

<div id="pay-nb">
    <input  type="text" value="" data-netbanking-code> 
  
</div>
<button id="pay-nb-btn">Pay</button>

Here we are showing you another way to initiate a Cashfree element.

const el = cfCheckout.element({
	pay: document.getElementById('pay-nb'),
	type: 'netbanking',
});
el.on('change', function(data){
    console.log(data);
    document.getElementById("onChangeNB").innerHTML = JSON.stringify(data)
});

document.getElementById('pay-nb-btn').addEventListener('click', async () => {
	await cfCheckout.pay(orderToken, 'netbanking');
});

Confirm payment

Once you received a response on either onPaymentSuccess or onPaymentFailure you should make an api call to your backend server to confirm the status of the payment. We will see that in the next step.

NPM

npm i cashfree-elementjs

For further instructions please visit the official npm page


What’s Next