UPI Integration - TPV with S2S Flow
Integrate TPV through UPI using the procedure described in this section with S2S Flow.
Step 1: Validate VPA
When your customer makes payment through UPI, you can validate the customer’s Virtual Payment Address (VPA) and then initiate payment. The validateVpa API is used to validate the UPI handle. Validate the VPA (UPI handle) using the validateVpa API. For Try-It experience, refer to Validate VPA Handle API.
Sample request
Validate VPA
curl --location '`https://test.payu.in/merchant/postservice.php?form=2`' \
--header 'accept: application/json' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'form=2' \
--data-urlencode 'key=BmTY3G' \
--data-urlencode 'command=validateVPA' \
--data-urlencode 'var1=9999999999@upi' \
--data-urlencode 'hash=d415188799f49f554a24064752bd6ce4d8a18c075b7b88b534e3150f253c09ae28a48554d2d1ba4be66b8441b2cbc364491d26bcead605c5fcecf4eaf622e224'import requests
url = "https://secure.payu.in/merchant/postservice"
headers = {
"accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
data = {
"form": "2",
"key": "BmTY3G",
"command": "validateVPA",
"var1": "9999999999@upi",
"hash": "d415188799f49f554a24064752bd6ce4d8a18c075b7b88b534e3150f253c09ae28a48554d2d1ba4be66b8441b2cbc364491d26bcead605c5fcecf4eaf622e224"
}
response = requests.post(url, headers=headers, data=data)
print("Status Code:", response.status_code)
print("Response:", response.json())import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class ValidateVPA {
public static void main(String[] args) throws IOException, InterruptedException {
String url = "https://secure.payu.in/merchant/postservice";
Map<String, String> params = new HashMap<>();
params.put("form", "2");
params.put("key", "BmTY3G");
params.put("command", "validateVPA");
params.put("var1", "9999999999@upi");
params.put("hash", "d415188799f49f554a24064752bd6ce4d8a18c075b7b88b534e3150f253c09ae28a48554d2d1ba4be66b8441b2cbc364491d26bcead605c5fcecf4eaf622e224");
String formData = params.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "="
+ URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("accept", "application/json")
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status Code: " + response.statusCode());
System.out.println("Response: " + response.body());
}
}const axios = require('axios');
const qs = require('qs');
const url = 'https://secure.payu.in/merchant/postservice';
const data = {
form: '2',
key: 'BmTY3G',
command: 'validateVPA',
var1: '9999999999@upi',
hash: 'd415188799f49f554a24064752bd6ce4d8a18c075b7b88b534e3150f253c09ae28a48554d2d1ba4be66b8441b2cbc364491d26bcead605c5fcecf4eaf622e224'
};
const config = {
headers: {
'accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}
};
axios.post(url, qs.stringify(data), config)
.then(response => {
console.log('Status Code:', response.status);
console.log('Response:', response.data);
})
.catch(error => {
console.error('Error:', error.response ? error.response.data : error.message);
});<?php
$url = "https://secure.payu.in/merchant/postservice";
$data = array(
'form' => '2',
'key' => 'BmTY3G',
'command' => 'validateVPA',
'var1' => '9999999999@upi',
'hash' => 'd415188799f49f554a24064752bd6ce4d8a18c075b7b88b534e3150f253c09ae28a48554d2d1ba4be66b8441b2cbc364491d26bcead605c5fcecf4eaf622e224'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'accept: application/json',
'Content-Type: application/x-www-form-urlencoded'
));
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "Status Code: " . $httpCode . "\n";
echo "Response: " . $response . "\n";
$jsonResponse = json_decode($response, true);
print_r($jsonResponse);
?>#!/usr/bin/perl
use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common;
my $url = "https://secure.payu.in/merchant/postservice";
my %data = (
form => '2',
key => 'BmTY3G',
command => 'validateVPA',
var1 => '9999999999@upi',
hash => 'd415188799f49f554a24064752bd6ce4d8a18c075b7b88b534e3150f253c09ae28a48554d2d1ba4be66b8441b2cbc364491d26bcead605c5fcecf4eaf622e224'
);
my $ua = LWP::UserAgent->new;
$ua->timeout(30);
my $response = $ua->post($url,
Content_Type => 'application/x-www-form-urlencoded',
Content => \%data
);
if ($response->is_success) {
print "Status Code: " . $response->code . "\n";
print "Response: " . $response->decoded_content . "\n";
} else {
print "Error: " . $response->status_line . "\n";
}Validate VPA for Recurring Payment
curl -X POST "https://test.payu.in/merchant/postservice?form=2" \
-H "accept: application/json" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "key=JP***g" \
-d "command=validateVPA" \
-d "var1=9999999999@upi" \
-d "var2={\"validateAutoPayVPA\":\"1\"}" \
-d "hash=75uy573dce34375a5fa2970afa21023d53e1cf5b8cd80a6472poy9b7c964c7a5da9146c9007df8b7391cbaf2d7d7d91dcaae8bf1d19d1837315a3376d6dc827e"import requests
import json
url = "https://test.payu.in/merchant/postservice"
headers = {
"accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
var2_json = json.dumps({"validateAutoPayVPA": "1"})
data = {
"key": "JP***g",
"command": "validateVPA",
"var1": "9999999999@upi",
"var2": var2_json,
"hash": "75uy573dce34375a5fa2970afa21023d53e1cf5b8cd80a6472poy9b7c964c7a5da9146c9007df8b7391cbaf2d7d7d91dcaae8bf1d19d1837315a3376d6dc827e"
}
response = requests.post(url, headers=headers, data=data, params={"form": "2"})
print("Status Code:", response.status_code)
print("Response:", response.json())import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class ValidateAutoPayVPA {
public static void main(String[] args) throws IOException, InterruptedException {
String url = "https://test.payu.in/merchant/postservice?form=2";
String var2Json = "{\"validateAutoPayVPA\":\"1\"}";
Map<String, String> params = new HashMap<>();
params.put("key", "JP***g");
params.put("command", "validateVPA");
params.put("var1", "9999999999@upi");
params.put("var2", var2Json);
params.put("hash", "75uy573dce34375a5fa2970afa21023d53e1cf5b8cd80a6472poy9b7c964c7a5da9146c9007df8b7391cbaf2d7d7d91dcaae8bf1d19d1837315a3376d6dc827e");
String formData = params.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "="
+ URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("accept", "application/json")
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status Code: " + response.statusCode());
System.out.println("Response: " + response.body());
}
}const axios = require('axios');
const qs = require('qs');
const url = 'https://test.payu.in/merchant/postservice?form=2';
const var2Json = JSON.stringify({ validateAutoPayVPA: '1' });
const data = {
key: 'JP***g',
command: 'validateVPA',
var1: '9999999999@upi',
var2: var2Json,
hash: '75uy573dce34375a5fa2970afa21023d53e1cf5b8cd80a6472poy9b7c964c7a5da9146c9007df8b7391cbaf2d7d7d91dcaae8bf1d19d1837315a3376d6dc827e'
};
const config = {
headers: {
'accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}
};
axios.post(url, qs.stringify(data), config)
.then(response => {
console.log('Status Code:', response.status);
console.log('Response:', response.data);
})
.catch(error => {
console.error('Error:', error.response ? error.response.data : error.message);
});<?php
$url = "https://test.payu.in/merchant/postservice?form=2";
$var2Json = json_encode(array('validateAutoPayVPA' => '1'));
$data = array(
'key' => 'JP***g',
'command' => 'validateVPA',
'var1' => '9999999999@upi',
'var2' => $var2Json,
'hash' => '75uy573dce34375a5fa2970afa21023d53e1cf5b8cd80a6472poy9b7c964c7a5da9146c9007df8b7391cbaf2d7d7d91dcaae8bf1d19d1837315a3376d6dc827e'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'accept: application/json',
'Content-Type: application/x-www-form-urlencoded'
));
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "Status Code: " . $httpCode . "\n";
echo "Response: " . $response . "\n";
$jsonResponse = json_decode($response, true);
print_r($jsonResponse);
?>#!/usr/bin/perl
use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common;
use JSON;
my $url = "https://test.payu.in/merchant/postservice?form=2";
my $var2_json = encode_json({ validateAutoPayVPA => '1' });
my %data = (
key => 'JP***g',
command => 'validateVPA',
var1 => '9999999999@upi',
var2 => $var2_json,
hash => '75uy573dce34375a5fa2970afa21023d53e1cf5b8cd80a6472poy9b7c964c7a5da9146c9007df8b7391cbaf2d7d7d91dcaae8bf1d19d1837315a3376d6dc827e'
);
my $ua = LWP::UserAgent->new;
$ua->timeout(30);
my $response = $ua->post($url,
Content_Type => 'application/x-www-form-urlencoded',
Content => \%data
);
if ($response->is_success) {
print "Status Code: " . $response->code . "\n";
print "Response: " . $response->decoded_content . "\n";
} else {
print "Error: " . $response->status_line . "\n";
}Sample response
Success scenario
if successfully validated:
{
"status":"SUCCESS",
"vpa":"9999999999@upi",
"isVPAValid":1,
"isAutoPayVPAValid":1,
"isAutoPayBankValid":"NA",
"payerAccountName":"ABC"
}
Notes:
- The payerAccountName parameter can be empty or NA or will have a payer name based on the value given by the bank.
- If both isVPAValid and isAutoPayVPAValid is 1, you must initiate payment for Recurring Payments.
- Ignore the isAutoPayBankValid parameter in the response.
Failure scenarios
- If invalid VPA, the response is similar to the following:
{
"status":"SUCCESS","vpa":"abc@upi","isVPAValid":0,"payerAccountName":"NA"
} - Invalid VPA but handle supporting SI (Autopay):
{
"status":"SUCCESS","vpa":"abc@upi","isVPAValid":0,"isAutoPayVPAValid":1,"isAutoPayBankValid":"NA","payerAccountName":"NA"
}- Customer valid but handle not supporting SI (Autopay):
{
"status":"SUCCESS","vpa":"xyz@freecharge","isVPAValid":1,"isAutoPayVPAValid":0,"isAutoPayBankValid":"NA","payerAccountName":"XYZ"
}- Neither customer valid nor handle supporting Autopay:
{
"status":"SUCCESS","vpa":"xyz@freecharge","isVPAValid":0,"isAutoPayVPAValid":0,"isAutoPayBankValid":"NA","payerAccountName":"NA"
}Step 2: Post the request to PayU
With the following parameters, make the transaction request with the customer’s bank account number to the PayU using the Collect Payment (_payment) API.
Environment
| Test Environment | https://test.payu.in/_payment> |
| Production Environment | https://secure.payu.in/_payment> |
Request parameters
| Parameter | Description | Example |
keymandatory
|
String Merchant key provided by PayU during onboarding.
|
JPg***r |
|---|---|---|
txnidmandatory
|
String The transaction ID is a reference number for a specific order that is generated by the merchant.
|
ypl938459435 |
amountmandatory
|
String The payment amount for the transaction.
|
10.00 |
productinfomandatory
|
String A brief description of the product.
|
iPhone |
firstnamemandatory
|
String The first name of the customer.
|
Ashish |
emailmandatory
|
String The email address of the customer.
|
[[email protected]](mailto:[email protected]) |
phonemandatory
|
String The phone number of the customer.
|
|
mandatory
|
String It defines the payment category for which you wish to perform TPV. For Net Banking, pg= 'UPI'.
|
UPI |
mandatory
|
String It defines the bank with which you wish to perform TPV using the bank code. The values can be any one of the following values:
|
UPI |
vpamandatory
|
String The VPA or UPI handle of the customer.
|
|
beneficiarydetailmandatory
|
JSON This is a JSON format text and there should be key named **beneficiaryAccountNumber** with the list of account numbers and the ifscCode key with the list of corresponding IFSC codes (in the same order as provided in the beneficiaryAccountNumber key). You can post up to five account details in this parameter.
|
Refer to beneficiarydetail JSON object fields section below the table |
| api_version |
String The api_version "6" must be passed fro this parameter.
|
|
furlmandatory
|
String The success URL, which is the page PayU will redirect to if the transaction is successful.
|
|
surlmandatory
|
String The Failure URL, which is the page PayU will redirect to if the transaction is failed.
|
|
hashmandatory
|
String It is the hash calculated by the merchant. The hash calculation logic is:sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3 |udf4|udf5||||||beneficiarydetail|SALT)
|
|
s2s_client_ipmandatory
|
String This parameter must have the source IP of the customer.
|
|
s2s_device_infomandatory
|
String This parameter must have the customer agent's device.
|
|
txn_s2s_flowmandatory
|
String This parameter must be passed with the value as 4 for s2s response..
|
4 |
address1optional
|
String The first line of the billing address.
* *For Fraud Detection*\*: This information is helpful when it comes to issues related to fraud detection and chargebacks. Hence, it is required to provide the correct information.
|
|
address2optional
|
String The second line of the billing address.
|
|
cityoptional
|
String The city where your customer resides as part of the billing address.
|
|
stateoptional
|
String The state where your customer resides as part of the billing address,
|
|
countryoptional
|
String The country where your customer resides.
|
|
zipcodeoptional
|
String Billing address zip code is mandatory for the cardless EMI option.Character Limit-20
|
|
udf1optional
|
String User-defined fields (udf) are used to store any information corresponding to a particular transaction. You can use up to five udfs in the post designated as udf1, udf2, udf3, udf4, udf5.
|
|
udf2optional
|
String User-defined fields (udf) are used to store any information corresponding to a particular transaction. You can use up to five udfs in the post designated as udf1, udf2, udf3, udf4, udf5.
|
|
udf3optional
|
String User-defined fields (udf) are used to store any information corresponding to a particular transaction.
|
|
udf4optional
|
String User-defined fields (udf) are used to store any information corresponding to a particular transaction.
|
|
udf5optional
|
String User-defined fields (udf) are used to store any information corresponding to a particular transaction.
|
beneficiarydetail JSON object fields
It must contain the list of account numbers and the ifscCode key with the list of corresponding IFSC codes (in the same order as provided in the beneficiaryAccountNumber key). You can post up to five account details in this parameter. For example:
{"beneficiaryAccountNumber":"002001600674|00000031957292212|00000035955239352|00000035955239352",
"ifscCode":"KTKB0000046|KTKB0000023|KTKB0000035|KTKB0000035"}Checksum Logic for Hash
Sample Request
curl --request POST 'https://test.payu.in/_payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=JP***g' \
--data-urlencode 'txnid=upi_tpv_12345' \
--data-urlencode 'amount=10.00' \
--data-urlencode 'productinfo=iPhone' \
--data-urlencode 'firstname=Ashish' \
--data-urlencode '[email protected]' \
--data-urlencode 'phone=9876543210' \
--data-urlencode 'pg=UPI' \
--data-urlencode 'bankcode=UPITPV' \
--data-urlencode 'vpa=customer@upi' \
--data-urlencode 'beneficiarydetail={"beneficiaryAccountNumber":"002001600674","ifscCode":"KTKB0000046"}' \
--data-urlencode 'api_version=6' \
--data-urlencode 'surl=https://example.com/payment/success' \
--data-urlencode 'furl=https://example.com/payment/failure' \
--data-urlencode 's2s_client_ip=192.0.2.1' \
--data-urlencode 's2s_device_info=Mozilla/5.0' \
--data-urlencode 'txn_s2s_flow=4' \
--data-urlencode 'hash=YOUR_CALCULATED_HASH'import json
import requests
data = {
"key": "JP***g",
"txnid": "upi_tpv_12345",
"amount": "10.00",
"productinfo": "iPhone",
"firstname": "Ashish",
"email": "[email protected]",
"phone": "9876543210",
"pg": "UPI",
"bankcode": "UPITPV",
"vpa": "customer@upi",
"beneficiarydetail": json.dumps({
"beneficiaryAccountNumber": "002001600674",
"ifscCode": "KTKB0000046"
}),
"api_version": "6",
"surl": "https://example.com/payment/success",
"furl": "https://example.com/payment/failure",
"s2s_client_ip": "192.0.2.1",
"s2s_device_info": "Mozilla/5.0",
"txn_s2s_flow": "4",
"hash": "YOUR_CALCULATED_HASH"
}
response = requests.post("https://test.payu.in/_payment", data=data)
print(response.status_code, response.text)const params = new URLSearchParams({
key: 'JP***g',
txnid: 'upi_tpv_12345',
amount: '10.00',
productinfo: 'iPhone',
firstname: 'Ashish',
email: '[email protected]',
phone: '9876543210',
pg: 'UPI',
bankcode: 'UPITPV',
vpa: 'customer@upi',
beneficiarydetail: JSON.stringify({
beneficiaryAccountNumber: '002001600674',
ifscCode: 'KTKB0000046'
}),
api_version: '6',
surl: 'https://example.com/payment/success',
furl: 'https://example.com/payment/failure',
s2s_client_ip: '192.0.2.1',
s2s_device_info: 'Mozilla/5.0',
txn_s2s_flow: '4',
hash: 'YOUR_CALCULATED_HASH'
});
const response = await fetch('https://test.payu.in/_payment', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: params
});
console.log(response.status, await response.text());import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class UpiTpvPayment {
public static void main(String[] args) throws Exception {
Map<String, String> data = new LinkedHashMap<>();
data.put("key", "JP***g");
data.put("txnid", "upi_tpv_12345");
data.put("amount", "10.00");
data.put("productinfo", "iPhone");
data.put("firstname", "Ashish");
data.put("email", "[email protected]");
data.put("phone", "9876543210");
data.put("pg", "UPI");
data.put("bankcode", "UPITPV");
data.put("vpa", "customer@upi");
data.put("beneficiarydetail", "{\"beneficiaryAccountNumber\":\"002001600674\",\"ifscCode\":\"KTKB0000046\"}");
data.put("api_version", "6");
data.put("surl", "https://example.com/payment/success");
data.put("furl", "https://example.com/payment/failure");
data.put("s2s_client_ip", "192.0.2.1");
data.put("s2s_device_info", "Mozilla/5.0");
data.put("txn_s2s_flow", "4");
data.put("hash", "YOUR_CALCULATED_HASH");
String body = data.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "="
+ URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://test.payu.in/_payment"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}<?php
$data = [
'key' => 'JP***g',
'txnid' => 'upi_tpv_12345',
'amount' => '10.00',
'productinfo' => 'iPhone',
'firstname' => 'Ashish',
'email' => '[email protected]',
'phone' => '9876543210',
'pg' => 'UPI',
'bankcode' => 'UPITPV',
'vpa' => 'customer@upi',
'beneficiarydetail' => json_encode([
'beneficiaryAccountNumber' => '002001600674',
'ifscCode' => 'KTKB0000046'
]),
'api_version' => '6',
'surl' => 'https://example.com/payment/success',
'furl' => 'https://example.com/payment/failure',
's2s_client_ip' => '192.0.2.1',
's2s_device_info' => 'Mozilla/5.0',
'txn_s2s_flow' => '4',
'hash' => 'YOUR_CALCULATED_HASH'
];
$ch = curl_init('https://test.payu.in/_payment');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded']
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE) . ' ' . $response;
curl_close($ch);
?>Sample Response
{
"metaData": {
"message": null,
"referenceId": "c99a6455b3e0dc5cd7167ab8c8cc10d2fa153cb509e3f64c6cd0ed9c5b64a8c9",
"statusCode": null,
"txnId": "my_order_26075",
"txnStatus": "pending",
"unmappedStatus": "pending"
},
"result": {
"paymentId": "403993715535965242",
"merchantName": "Sudhanshu",
"merchantVpa": "payutest@hdfcbank",
"amount": "1.00",
"intentURIData": "pa=payutest@hdfcbank&pn=Kumar&tr=403993715535965242&tid=PPPL403993715535965242080126220900&am=1.00&cu=INR&tn=UPIIntent",
"acsTemplate": "PGh0bWw+PGJvZHk+PGZvcm0gbmFtZT0icGF5bWVudF9wb3N0IiBpZD0icGF5bWVudF9wb3N0IiBhY3Rpb249Imh0dHBzOi8vdGVzdC5wYXl1LmluL2M5OWE2NDU1YjNlMGRjNWNkNzE2N2FiOGM4Y2MxMGQyYzgzYTk5NmFhNDhiYTk4MmZjMGQ4MTI1MGY1ODgxZjMvaW50ZW50U2VhbWxlc3NIYW5kbGVyLnBocCIgbWV0aG9kPSJwb3N0Ij48aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJ0b2tlbiIgdmFsdWU9IjhERDNFRUFFLUI5NTktQzY1RS03MDczLTYzQTNGQUUxMjZGRiI+PGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0iYW1vdW50IiB2YWx1ZT0iMS4wMCI+PGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0ibWlocGF5aWQiIHZhbHVlPSJjOTlhNjQ1NWIzZTBkYzVjZDcxNjdhYjhjOGNjMTBkMmZhMTUzY2I1MDllM2Y2NGM2Y2QwZWQ5YzViNjRhOGM5Ij48aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJkaXNhYmxlSW50ZW50U2VhbWxlc3NGYWlsdXJlIiB2YWx1ZT0iMCI+PGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0icGF5ZWVWcGEiIHZhbHVlPSJwYXl1dGVzdEBoZGZjYmFuayI+PGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0icGF5ZWVOYW1lIiB2YWx1ZT0iU3VkaGFuc2h1Ij48aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJhZGRpdGlvbmFsQ2hhcmdlcyIgdmFsdWU9IjAiPjxpbnB1dCB0eXBlPSJoaWRkZW4iIG5hbWU9InRyYW5zYWN0aW9uRmVlIiB2YWx1ZT0iMS4wMCI+PC9mb3JtPjxzY3JpcHQgdHlwZT0ndGV4dC9qYXZhc2NyaXB0Jz4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5vbmxvYWQ9ZnVuY3Rpb24oKXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5mb3Jtc1sncGF5bWVudF9wb3N0J10uc3VibWl0KCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIDwvc2NyaXB0PjwvYm9keT48L2h0bWw+",
"otpPostUrl": "https://test.payu.in/ResponseHandler.php"
}
}Step 3: Invoke UPI Intent on Customer's Device
Step 3: Invoke UPI Intent on customer's device
You need to invoke intent in the customer's mobile device using the merchant VPA URL. Make sure that only this merchant VPA is embedded in the intent call since this helps to track the status of the transaction.
Open the UPI Intent as per the NPCI Guidelines. Merchants can also open any specific app instead of making the Generic Intent call. For example, Google Pay, PhonePe, etc. This URL can then be fired using an Intent or a hyperlink which would open an Intent tray with a list of available supporting apps on the user's mobile device. The following sample UPI Deep Link URL and the format used for creating the URL:
Sample URL (with values from the above sample JSON):
upi://pay?pa=payu@axisbank&pn=SMSPLUS&tr=8312916361&am=10.17Format for UPI Deep Linking URL (as per NPCI guidelines):
"upi://pay?pa=" + merchantVpa + "&pn=" + merchantName + "&tr=" + referenceId + "&am=" + amount UPI Deep Linking URL parameters description
Where the description of the parameters used in the URL is as described in the following table:
| Parameter | Description |
|---|---|
| merchantVpa | As received in JSON response in key merchantVPA' |
| merchantName | As received in JSON response in key merchantName. |
| referenceId | As received in JSON response in key referenceId. |
| amount | Amount of transaction. This must be the same as the amount passed to the initiatePayment API. |
Step 4: Check the response from PayU
Hash Validation Logic for Payment Response (Reverse Hashing)
While sending the response, PayU takes the exact same parameters that were sent in the request (in reverse order) to calculate the hash and returns it to you. You must verify the hash and then mark a transaction as a success or failure. This is to make sure the transaction has not tampered within the response.
The order of the parameters is similar to the following code block:
sha512(SALT|beneficiarydetail|status||||||udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key)
Store the mihpayid and txnid parameter values in response:PayU recommends you to make provisions to store the mihpayid and txnid parameter values (in the response) in your server as proof that TPV has been completed for a customer.
Sample response
The formatted response from PayU:
Array
(
[mihpayid] => 403993715524308315
[mode] => UPI
[status] => success
[unmappedstatus] => captured
[key] => JP***g
[txnid] => Job7NydtwPVAmy
[amount] => 10.00
[discount] => 0.00
[net_amount_debit] => 10
[addedon] => 2021-10-05 12:51:20
[productinfo] => iPhone
[firstname] => Ashish
[lastname] =>
[address1] =>
[address2] =>
[city] =>
[state] =>
[country] =>
[zipcode] =>
[email] => [email protected]
[phone] => 9876543210
[udf1] =>
[udf2] =>
[udf3] =>
[udf4] =>
[udf5] =>
[udf6] =>
[udf7] =>
[udf8] =>
[udf9] =>
[udf10] =>
[hash] => de4f82af65458c84080d6515c1a80d42af703be390346ef020974e520efeb4ab9ebe4752e63e70d6f00dedd671c663dfdb22d0f0c818c52790e911e8babd3f6e
[field1] => anything@payu
[field2] => Job7NydtwPVAmy
[field3] =>
[field4] => Ashish
[field5] => AXImAH1BxekGdTLY7qgjMXffAAjJj5Q75mY
[field6] =>
[field7] => Transaction completed successfully
[field8] =>
[field9] => Transaction completed successfully
[payment_source] => payu
[PG_TYPE] => UPI-PG
[bank_ref_num] => Job7NydtwPVAmy
[bankcode] => UPI
[error] => E000
[error_Message] => No Error
)
Step 5. Verify the payment
Upon receiving the response, PayU recommends you performing a reconciliation step to validate all transaction details.
You can verify your payments using either of the following methods:
Configure the webhooks to monitor the status of payments.
Webhooks enable a server to communicate with another server by sending an HTTP callback or message.
These callbacks are triggered by specific events or instances and operate at the server-to-server (S2S) level.
Know how to manage Webhooks for Payments.
Environment
| Test Environment | https://test.payu.in/merchant/postservice.php?form=2 |
| Production Environment | https://info.payu.in/merchant/postservice.php?form=2 |
Note: The hash logic for Verify Payment API is:
sha512(key|command|var1|salt) sha512
Sample request
curl --request POST
--url 'https://test.payu.in/merchant/postservice?form=2'
--header 'Content-Type: application/x-www-form-urlencoded'
--data key=JPM7Fg
--data command=verify_payment
--data var1=IhfgcZnXR4o4nB
--data hash=a0ae79fdd66c875af6e9b21c4a67f1822deb00f2df5e9f0b1948f3222f536a9bf741b24efbb1874ca0f84f76b036e6c0d641581d0100f7abe4aeed2f3264f5c9
Sample response
If credit card payment is made, the response is similar to the following:
{
"status":0,
"msg":"0 out of 1 Transactions Fetched Successfully",
"transaction_details":
{
"IhfgcZnXR4o4nB":
{
"mihpayid":"Not Found",
"status":"Not Found"
}
}
}If txnID is not found, the response is similar to the following:
{
"status":0,
"msg":"0 out of 1 Transactions Fetched Successfully",
"transaction_details":
{
"IhfgcZnXR4o4nB":
{
"mihpayid":"Not Found",
"status":"Not Found"
}
}
}Response parameters
| Parameter | Description | Example |
|---|---|---|
| status | This parameter returns the status of web service call. The status can be any of the following:
| 0 |
| msg | This parameter returns the reason string. | For example, any of the following messages are displayed:
|
| transaction_details | This parameter contains the response in a JSON format. For more information refer to JSON fields description for transaction_details parameter . | |
| request_id | PayU Request ID for a request in a Transaction. For example, a transaction can have a refund request. | 7800456 |
| bank_ref_num | This parameter returns the bank reference number. If the bank provides after a successful action. | 204519474956 |
To learn more about the possible error codes and their description, refer to Error Codes.
Updated about 16 hours ago
