Third Party Validation on Razorpay Standard Integration

Know how Razorpay performs Third-Party Validation (TPV) of your customers' bank accounts in real-time using Razorpay Standard Integration.


Third-Party Validation (TPV) of bank accounts is a mandatory requirement for merchants in the BFSI (Banking, Financial Services and Insurance) sector dealing with Securities, Broking and Mutual Funds. As per Securities and Exchange Board of India (SEBI) guidelines, transactions must be made by the customers only from those bank accounts which are provided when they registered with your business.

With Razorpay, you can comply with the SEBI guidelines for online payment collections by offering TPV integrations with major banks at the Checkout. Customers can make payments using netbanking or UPI. UPI supports both collect and intent flows.

Handy Tips
You can issue Payment Links to customers to accept online payments from them through specific bank accounts. You can perform this third-party validation using our Payment Links API.

Feature Request
This is an on-demand feature. Please raise a request with our Support team to get this feature activated on your Razorpay account.

Integration Flow🔗

In TPV integration flow, Razorpay maps the customers' bank accounts to ensure that the payment is processed only from their registered bank accounts.

Given below are the steps:

  1. Collect Customer Bank Account Details
  2. Create an Order
  3. Add Checkout Code
  4. Handle Payment Success and Failure Events
  5. Store Details in Server
  6. Verify Payment Signature

Step 1: Collect Customer Bank Account details🔗

Collect the bank account details provided by the customer at the time of registration.

Step 2: Create an Order🔗

Pass the bank account details to the bank_account array of the Orders API:

/orders

Netbanking Only🔗

Given below is the sample code when method is netbanking.

Copycurl -u <YOUR_KEY_ID>:<YOUR_KEY_SECRET> \ -X POST https://api.razorpay.com/v1/orders \ -H "Content-Type: application/json" \ -d '{ "amount": 500, "method": "netbanking", "receipt": "BILL13375649", "currency": "INR", "bank_account": { "account_number": "765432123456789", "name": "Gaurav Kumar", "ifsc": "HDFC0000053" } }'
CopyRazorpayClient razorpay = new RazorpayClient("[YOUR_KEY_ID]", "[YOUR_KEY_SECRET]"); ArrayList Offer = new ArrayList<String>(); Offer.add("offer_JTUADI4ZWBGWur"); JSONObject orderRequest = new JSONObject(); orderRequest.put("amount", 1000); // amount in the smallest currency unit orderRequest.put("currency", "INR"); orderRequest.put("receipt", "BILL13375649"); orderRequest.put("method", "netbanking"); JSONObject bank_account = new JSONObject(); bank_account.put("account_number", "765432123456789"); bank_account.put("name", "Gaurav Kumar"); bank_account.put("ifsc, "HDFC0000053"); orderRequest.put("bank_account", bank_account); Order order = razorpayclient.orders.create(orderRequest); System.out.print(order);
Copyimport razorpay client = razorpay.Client(auth=("YOUR_ID", "YOUR_SECRET")) client.order.create({ { "amount": 500, "method": "netbanking", "receipt": "BILL13375649", "currency": "INR", "bank_account": { "account_number": "765432123456789", "name": "Gaurav Kumar", "ifsc": "HDFC0000053" } })
Copy$api = new Api($key_id, $secret); $api->order->create(array('amount' => 100, 'currency' => 'INR', bank_account => array( 'account_number' => '765432123456789', 'name' => 'Gaurav Kumar', 'ifsc' => 'HDFC0000053')));
CopyRazorpayClient client = new RazorpayClient(your_key_id, your_secret); Dictionary<string, object> options = new Dictionary<string,object>(); options.Add("amount", 50000); // amount in the smallest currency unit options.Add("receipt", "receipt#1"); options.Add("currency", "INR"); bank_account.account_number="765432123456789"; bank_account.name="Gaurav Kumar"; bank_account.ifsc="HDFC0000053"; options.Add("bank_account", bank_account); Order order = client.Order.Create(options);
Copyrequire "razorpay" Razorpay.setup('YOUR_KEY_ID', 'YOUR_SECRET') order = Razorpay::Order.create amount: 50000, currency: 'INR', receipt: 'receipt#1', bank_account: { account_number: '765432123456789', name: 'Gaurav Kumar', ifsc: 'HDFC0000053'}
Copyvar instance = new Razorpay({ key_id: 'YOUR_KEY_ID', key_secret: 'YOUR_SECRET' }) instance.orders.create({ amount: 50000, currency: "INR", receipt: "receipt#1", bank_account: { account_number: "765432123456789", name: "Gaurav Kumar", ifsc: "HDFC0000053" } })
Copyimport ( razorpay "github.com/razorpay/razorpay-go" ) client := razorpay.NewClient("YOUR_KEY_ID", "YOUR_SECRET") data := map[string]interface{}{ "amount": 50000, "currency": "INR", "receipt": "receipt#1", "bank_account": { "account_number": "765432123456789", "name": "Gaurav Kumar", "ifsc": "HDFC0000053" } } body, err := client.Order.Create(data, nil)
Copy{ "id": "order_GAWN9beXgaqRyO", "entity": "order", "amount": 500, "amount_paid": 0, "amount_due": 500, "currency": "INR", "receipt": "BILL13375649", "offer_id": null, "status": "created", "attempts": 0, "notes": [], "created_at": 1573044247 }

UPI Only🔗

Given below is the sample code when method is upi.

Copycurl -u <YOUR_KEY_ID>:<YOUR_KEY_SECRET> \ -X POST https://api.razorpay.com/v1/orders \ -H "Content-Type: application/json" \ -d '{ "amount": 500, "method": "upi", "receipt": "BILL13375649", "currency": "INR", "bank_account": { "account_number": "765432123456789", "name": "Gaurav Kumar", "ifsc": "HDFC0000053" } }'
CopyRazorpayClient razorpay = new RazorpayClient("[YOUR_KEY_ID]", "[YOUR_KEY_SECRET]"); ArrayList Offer = new ArrayList<String>(); Offer.add("offer_JTUADI4ZWBGWur"); JSONObject orderRequest = new JSONObject(); orderRequest.put("amount", 1000); // amount in the smallest currency unit orderRequest.put("currency", "INR"); orderRequest.put("receipt", "BILL13375649"); orderRequest.put("method", "upi"); JSONObject bank_account = new JSONObject(); bank_account.put("account_number", "765432123456789"); bank_account.put("name", "Gaurav Kumar"); bank_account.put("ifsc, "HDFC0000053"); orderRequest.put("bank_account", bank_account); Order order = razorpayclient.orders.create(orderRequest); System.out.print(order);
Copyimport razorpay client = razorpay.Client(auth=("YOUR_ID", "YOUR_SECRET")) client.order.create({ { "amount": 500, "method": "upi", "receipt": "BILL13375649", "currency": "INR", "bank_account": { "account_number": "765432123456789", "name": "Gaurav Kumar", "ifsc": "HDFC0000053" } })
Copy$api = new Api($key_id, $secret); $api->order->create(array('amount' => 100, 'method' => 'upi', 'currency' => 'INR', bank_account => array( 'account_number' => '765432123456789', 'name' => 'Gaurav Kumar', 'ifsc' => 'HDFC0000053')));
CopyRazorpayClient client = new RazorpayClient(your_key_id, your_secret); Dictionary<string, object> options = new Dictionary<string,object>(); options.Add("amount", 50000); // amount in the smallest currency unit options.Add("receipt", "receipt#1"); options.Add("currency", "INR"); options.Add("method", "upi"); bank_account.account_number="765432123456789"; bank_account.name="Gaurav Kumar"; bank_account.ifsc="HDFC0000053"; options.Add("bank_account", bank_account); Order order = client.Order.Create(options);
Copyrequire "razorpay" Razorpay.setup('YOUR_KEY_ID', 'YOUR_SECRET') order = Razorpay::Order.create amount: 50000, currency: 'INR', receipt: 'receipt#1', method: 'upi', bank_account: { account_number: '765432123456789', name: 'Gaurav Kumar', ifsc: 'HDFC0000053'}
Copyvar instance = new Razorpay({ key_id: 'YOUR_KEY_ID', key_secret: 'YOUR_SECRET' }) instance.orders.create({ amount: 50000, currency: "INR", receipt: "receipt#1", method: 'upi', bank_account: { account_number: "765432123456789", name: "Gaurav Kumar", ifsc: "HDFC0000053" } })
Copyimport ( razorpay "github.com/razorpay/razorpay-go" ) client := razorpay.NewClient("YOUR_KEY_ID", "YOUR_SECRET") data := map[string]interface{}{ "amount": 50000, "currency": "INR", "receipt": "receipt#1", "method": "upi", "bank_account": { "account_number": "765432123456789", "name": "Gaurav Kumar", "ifsc": "HDFC0000053" } } body, err := client.Order.Create(data)
Copy{ "id": "order_GAWRjlWkVcRh0V", "entity": "order", "amount": 500, "amount_paid": 0, "amount_due": 500, "currency": "INR", "receipt": "BILL13375649", "offer_id": null, "status": "created", "attempts": 0, "notes": [], "created_at": 1573044206 }

Netbanking & UPI🔗

Given below is the sample code when method is not passed.

Copycurl -u <YOUR_KEY_ID>:<YOUR_KEY_SECRET> \ -X POST https://api.razorpay.com/v1/orders \ -H "Content-Type: application/json" \ -d '{ "amount": 500, "receipt": "BILL13375649", "currency": "INR", "bank_account": { "account_number": "765432123456789", "name": "Gaurav Kumar", "ifsc": "HDFC0000053" } }'
CopyRazorpayClient razorpay = new RazorpayClient("[YOUR_KEY_ID]", "[YOUR_KEY_SECRET]"); ArrayList Offer = new ArrayList<String>(); Offer.add("offer_JTUADI4ZWBGWur"); JSONObject orderRequest = new JSONObject(); orderRequest.put("amount", 1000); // amount in the smallest currency unit orderRequest.put("currency", "INR"); orderRequest.put("receipt", "BILL13375649"); JSONObject bank_account = new JSONObject(); bank_account.put("account_number", "765432123456789"); bank_account.put("name", "Gaurav Kumar"); bank_account.put("ifsc, "HDFC0000053"); orderRequest.put("bank_account", bank_account); Order order = razorpayclient.orders.create(orderRequest); System.out.print(order);
Copyimport razorpay client = razorpay.Client(auth=("YOUR_ID", "YOUR_SECRET")) client.order.create({ { "amount": 500, "receipt": "BILL13375649", "currency": "INR", "bank_account": { "account_number": "765432123456789", "name": "Gaurav Kumar", "ifsc": "HDFC0000053" } })
Copy$api = new Api($key_id, $secret); $api->order->create(array('amount' => 100, 'currency' => 'INR', bank_account => array( 'account_number' => '765432123456789', 'name' => 'Gaurav Kumar', 'ifsc' => 'HDFC0000053')));
CopyRazorpayClient client = new RazorpayClient(your_key_id, your_secret); Dictionary<string, object> options = new Dictionary<string,object>(); options.Add("amount", 50000); // amount in the smallest currency unit options.Add("receipt", "receipt#1"); options.Add("currency", "INR"); bank_account.account_number="765432123456789"; bank_account.name="Gaurav Kumar"; bank_account.ifsc="HDFC0000053"; options.Add("bank_account", bank_account); Order order = client.Order.Create(options);
Copyrequire "razorpay" Razorpay.setup('YOUR_KEY_ID', 'YOUR_SECRET') order = Razorpay::Order.create amount: 50000, currency: 'INR', receipt: 'receipt#1', bank_account: { account_number: '765432123456789', name: 'Gaurav Kumar', ifsc: 'HDFC0000053'}
Copyvar instance = new Razorpay({ key_id: 'YOUR_KEY_ID', key_secret: 'YOUR_SECRET' }) instance.orders.create({ amount: 50000, currency: "INR", receipt: "receipt#1", bank_account: { account_number: "765432123456789", name: "Gaurav Kumar", ifsc: "HDFC0000053" } })
Copyimport ( razorpay "github.com/razorpay/razorpay-go" ) client := razorpay.NewClient("YOUR_KEY_ID", "YOUR_SECRET") data := map[string]interface{}{ "amount": 50000, "currency": "INR", "receipt": "receipt#1", "bank_account": { "account_number": "765432123456789", "name": "Gaurav Kumar", "ifsc": "HDFC0000053" } } body, err := client.Order.Create(data)
Copy{ "id": "order_GAWRjlWkVcRh0V", "entity": "order", "amount": 500, "amount_paid": 0, "amount_due": 500, "currency": "INR", "receipt": "BILL13375649", "offer_id": null, "status": "created", "attempts": 0, "notes": [], "created_at": 1573044206 }

Request Parameters🔗

Create a request payload using the following attributes:

amount mandatory

integer The transaction amount expressed in paise (currency supported is INR). For example, for an actual amount of ₹1, the value of this field should be 100.

currency mandatory

string The currency in which the transaction should be made. You can create Orders in INR only.

receipt optional

string Receipt number that corresponds to this Order, set for your internal reference. Maximum length 40 characters.

notes optional

json object Key-value pair that can be used to store additional information about the entity. Maximum 15 key-value pairs, 256 characters (maximum) each. For example, "note_key": "Beam me up Scotty”.

method optional

string The payment method used to make the payment. If this parameter is not passed, customers will be able to make payments using both netbanking and UPI payment methods. Possible values:

  • netbanking: Customers can make payments only using netbanking.
  • upi: Customers can make payments only using UPI.
bank_account

Details of the bank account that the customer has provided at the time of registration.

account_number mandatory
string The bank account number from which the customer should make the payment. For example, 765432123456789. Payments will not be processed for an incorrect account number.
name mandatory
string The name linked to the bank account. For example, Gaurav Kumar.
ifsc mandatory
string The bank IFSC. For example, HDFC0000053.

Step 3: Add Checkout Code🔗

Send the order_id obtained in the response of the previous step along with the other Checkout attributes to trigger Razorpay Checkout.

Following are two sample codes for Checkout:

With Handler Function

With Callback URL

  • On successful payment, your web page is displayed to the user.

  • On payment failure, the customer is notified of the reason for failure and requested to retry the payment.

  • On successful payment, the customer is redirected to the specified URL. For example, a payment success page.
  • On payment failure, the customer is requested to retry payment at Checkout.
  • Copy-paste the form parameters as options in your HTML code:

    Copy<button id="rzp-button1">Pay</button> <script src="https://checkout.razorpay.com/v1/checkout.js"></script> <script> var options = { "key": "YOUR_KEY_ID", // Enter the Key ID generated from the Dashboard "amount": "50000", // Amount is in currency subunits. Default currency is INR. Hence, 50000 refers to 50000 paise "currency": "INR", "name": "Acme Corp", "description": "Test Transaction", "image": "https://example.com/your_logo", "order_id": "order_Dd3Wbag7QXDuuL", //This is a sample Order ID. Pass the `id` obtained in the response of Step 1 "handler": function (response){ alert(response.razorpay_payment_id); alert(response.razorpay_order_id); alert(response.razorpay_signature) }, "prefill": { "name": "Gaurav Kumar", "email": "gaurav.kumar@example.com", "contact": "9999999999" }, "notes": { "address": "Razorpay Corporate Office" }, "theme": { "color": "#3399cc" } }; var rzp1 = new Razorpay(options); rzp1.on('payment.failed', function (response){ alert(response.error.code); alert(response.error.description); alert(response.error.source); alert(response.error.step); alert(response.error.reason); alert(response.error.metadata.order_id); alert(response.error.metadata.payment_id); }); document.getElementById('rzp-button1').onclick = function(e){ rzp1.open(); e.preventDefault(); } </script>
    Copy<button id="rzp-button1">Pay</button> <script src="https://checkout.razorpay.com/v1/checkout.js"></script> <script> var options = { "key": "YOUR_KEY_ID", // Enter the Key ID generated from the Dashboard "amount": "50000", // Amount is in currency subunits. Default currency is INR. Hence, 50000 refers to 50000 paise "currency": "INR", "name": "Acme Corp", "description": "Test Transaction", "image": "https://example.com/your_logo", "order_id": "order_Dd3Wbag7QXDuuL", //This is a sample Order ID. Pass the `id` obtained in the response of Step 1 "callback_url": "https://eneqd3r9zrjok.x.pipedream.net/", "prefill": { "name": "Gaurav Kumar", "email": "gaurav.kumar@example.com", "contact": "9999999999" }, "notes": { "address": "Razorpay Corporate Office" }, "theme": { "color": "#3399cc" } }; var rzp1 = new Razorpay(options); document.getElementById('rzp-button1').onclick = function(e){ rzp1.open(); e.preventDefault(); } </script>

    Know more about the Checkout Form Fields.

    Handy Tips

    • The open method of the Razorpay object (rzp1.open()) should be invoked by your site's JavaScript. This may or may not be a user-driven action such as a click.
    • UPI Intent Apps will appear on the standard checkout if the method is upi in the Orders API.

    Customers Complete the Payment🔗

    At the Checkout, customers complete the payment using the payment methods passed during the order creation.

    The supported payment methods are netbanking and upi. Razorpay Checkout for each payment method is displayed as below:

    Example: Netbanking TPV🔗

    Example: UPI TPV🔗

    The payment is marked as successful only when the bank account details entered in the order match those entered by the customer on the Checkout. If the customer tries to make payment with an account other than the registered account, Razorpay will fail the transaction.

    Step 4: Handle Payment Success and Failure🔗

    The way you handle payment success and failure scenarios depends on the Checkout sample code you opted for in the previous step.

    Checkout with Handler Function🔗

    If you used Sample Code with Handler Function:

    • On Payment Success

    Customer sees your application web page, and the Checkout returns the response object of the successful payment (razorpay_payment_id, razorpay_order_id and razorpay_signature). You need to collect these and send them to your server.

    Copy "handler": function (response){ alert(response.razorpay_payment_id); alert(response.razorpay_order_id); alert(response.razorpay_signature)}
    • On Payment Failure

    On payment failure, the customer is notified about the reason for failure and requested to retry the payment.

    Copyrzp1.on('payment.failed', function (response){ alert(response.error.code); alert(response.error.description); alert(response.error.source); alert(response.error.step); alert(response.error.reason); alert(response.error.metadata.order_id); alert(response.error.metadata.payment_id); }

    Know more about the error parameters.

    Checkout with Callback URL🔗

    If you used the Sample Code with the Callback URL:

    • On Payment Success:
      When you use a Callback URL, the response object of the successful payment (razorpay_payment_id, razorpay_order_id and razorpay_signature) is submitted to the Callback URL. Only successful authorizations are auto-submitted.

    • On Payment Failure:
      In case of failed payments, the Checkout Form is displayed again for payment retry.

    Step 5: Store Fields in your Server🔗

    A successful payment returns the following fields to the Checkout form.

    • You need to store these fields in your server.

    • You can confirm the authenticity of these details by verifying the signature in the next step.

    Copy{ "razorpay_payment_id": "pay_29QQoUBi66xm2f", "razorpay_order_id": "order_9A33XWu170gUtm", "razorpay_signature": "9ef4dffbfd84f1318f6739a3ce19f9d85851857ae648f114332d8401e0949a3d" }
    razorpay_payment_id
    string Unique identifier for the payment returned by Checkout only for successful payments.
    razorpay_order_id
    string Unique identifier for the order returned by Checkout.
    razorpay_signature
    string Signature returned by the Checkout. This is used to verify the payment.

    Step 6: Verify Signature🔗

    This is a mandatory step to confirm the authenticity of the details returned to the Checkout form for successful payments.

    To verify the razorpay_signature returned to you by the Checkout form:

    1. Create a signature in your server using the following attributes:

      • order_id: Retrieve the order_id from your server. Do not use the razorpay_order_id returned by Checkout.
      • razorpay_payment_id: Returned by Checkout.
      • key_secret: Available in your server.
        The key_secret that was generated from the Razorpay Dashboard.
    2. Use the SHA256 algorithm, the razorpay_payment_id and the order_id to construct a HMAC hex digest as shown below:

      Copygenerated_signature = hmac_sha256(order_id + "|" + razorpay_payment_id, secret); if (generated_signature == razorpay_signature) { payment is successful }
    3. If the signature you generate on your server matches the razorpay_signature returned to you by the Checkout form, the payment received is from an authentic source.

    Generate Signature on Your Server🔗

    Given below are the sample codes for payment signature verification.

    Copy/** * This class defines common routines for generating * authentication signatures for Razorpay Webhook requests. */ public class Signature { private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256"; /** * Computes RFC 2104-compliant HMAC signature. * * @param data * The data to be signed. * @param key * The signing key. * @return * The Base64-encoded RFC 2104-compliant HMAC signature. * @throws * java.security.SignatureException when signature generation fails */ public static String calculateRFC2104HMAC(String data, String secret) throws java.security.SignatureException { String result; try { // get an hmac_sha256 key from the raw secret bytes SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), HMAC_SHA256_ALGORITHM); // get an hmac_sha256 Mac instance and initialize with the signing key Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM); mac.init(signingKey); // compute the hmac on input data bytes byte[] rawHmac = mac.doFinal(data.getBytes()); // base64-encode the hmac result = DatatypeConverter.printHexBinary(rawHmac).toLowerCase(); } catch (Exception e) { throw new SignatureException("Failed to generate HMAC : " + e.getMessage()); } return result; } }
    Copyuse Razorpay\Api\Api; $api = new Api($key_id, $key_secret); $attributes = array('razorpay_signature' => '23233', 'razorpay_payment_id' => '332' , 'razorpay_order_id' => '12122'); $order = $api->utility->verifyPaymentSignature($attributes)
    Copyrequire 'razorpay' Razorpay.setup('key_id', 'key_secret') payment_response = { 'razorpay_order_id': '12122', 'razorpay_payment_id': '332', 'razorpay_signature': '23233' } Razorpay::Utility.verify_payment_signature(payment_response)
    Copyimport razorpay client = razorpay.Client(auth=("YOUR_ID", "YOUR_SECRET")) client.utility.verify_payment_signature({ 'razorpay_order_id': razorpay_order_id, 'razorpay_payment_id': razorpay_payment_id, 'razorpay_signature': razorpay_signature })
    Copy Dictionary<string, string> attributes = new Dictionary<string, string>(); attributes.Add("razorpay_payment_id", paymentId); attributes.Add("razorpay_order_id", Request.Form["razorpay_order_id"]); attributes.Add("razorpay_signature", Request.Form["razorpay_signature"]); Utils.verifyPaymentSignature(attributes);
    Copyvar { validatePaymentVerification } = require('./dist/utils/razorpay-utils'); validatePaymentVerification({"order_id": razorpayOrderId, "payment_id": razorpayPaymentId }, signature, secret);
    Copyimport ( "crypto/hmac" "crypto/sha256" "crypto/subtle" "encoding/hex" "fmt" ) func main() { signature := "477d1cdb3f8122a7b0963704b9bcbf294f65a03841a5f1d7a4f3ed8cd1810f9b" secret := "qp3zKxwLZxbMORJgEVWi3Gou" data := "order_J2AeF1ZpvfqRGH|pay_J2AfAxNHgqqBiI" //fmt.Printf("Secret: %s Data: %s\n", secret, data) // Create a new HMAC by defining the hash type and the key (as byte array) h := hmac.New(sha256.New, []byte(secret)) // Write Data to it _, err := h.Write([]byte(data)) if err != nil { panic(err) } // Get result and encode as hexadecimal string sha := hex.EncodeToString(h.Sum(nil)) fmt.Printf("Result: %s\n", sha) if subtle.ConstantTimeCompare([]byte(sha), []byte(signature)) == 1 { fmt.Println("Works") } }

    Post Signature Verification🔗

    After you have successfully completed the integration, you can set up webhooks, make test payments, replace test key with live key and integrate with other APIs.

    Capture Payment🔗

    After payment is authorized, you need to capture it to settle the amount to your bank account as per the settlement schedule. Payments that are not captured are auto-refunded after a fixed time.

    • Auto-capture payments (recommended)
      Authorized payments can be automatically captured. You can auto-capture all payments using global settings on the Razorpay Dashboard. Watch Out!
      Payment capture settings work only if you have integrated with Orders API in your server side. Know more about the Orders API.
    • Manually capture payments
      Each authorized payment can also be captured individually. You can manually capture payments:

    Know more about Capture Settings for payments.

    Timeouts🔗

    The transaction timeout is applicable only when your customer attempts the payment.

    The timeout is 3 to 15 minutes for an attempted payment. If there is a payment failure due to timeout, the customer is redirected to the Checkout page.

    ×