[S2S] UPI Consent Transaction - Cross Border
This section describes step-by-step procedure to implement UPI Consent Transaction (SI mandate registration) for recurring UPI payments using PayU's Server-to-Server (S2S) integration with the Legacy Decoupled flow.
Prerequisites
Before starting the integration, ensure you have:
- Active PayU merchant account with UPI recurring payments enabled
- Merchant Key and Salt from PayU dashboard
- Test environment access for development
- Understanding of UPI payment flow (Collect vs Intent)
Payment consent flow
Send the UPI consent transaction request with S2S parameters.
Handle the response for UPI Collect and UPI Intent flows.
Set up webhooks to receive transaction status updates.
Confirm the mandate registration was successful.
Recurring Payments Flow
Send pre-debit notifications for upcoming recurring debits.
Execute recurring payment transactions using the registered mandate.
Payment Consent Transaction
Step 1: Post the Request
Before implementing, familiarize yourself with the required parameters.
Reference: For the UPI Consent Transaction - Cross Border Payments API Reference, refer to UPI Consent Transaction - CB.
Key Parameters for UPI Mandate Registration
Mandatory Parameters:
key,txnid,amount,productinfo,firstname,email,phone,lastnamesurl,furl,hashpg(must beUPI)bankcode(UPIfor Collect,INTENTfor Intent)si(must be1)si_details(JSON object with mandate details)api_version(must be7)
UPI-Specific Parameters:
vpa(mandatory for UPI Collect - customer's VPA handle)
S2S Flow Parameters (for UPI Intent):
txn_s2s_flow=4(Legacy Decoupled flow)s2s_client_ip(customer's source IP)s2s_device_info(customer's device/user agent)
Request Parameters
| Parameter | Description | Example |
|---|---|---|
keymandatory | String Merchant key provided by PayU during onboarding. | JPg****f |
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 |
lastnamemandatory | String The last name of the customer. | Kumar |
emailmandatory | String The email address of the customer. | [email protected] |
phonemandatory | String The phone number of the customer. | |
address1optional but recommended for higher approval rate | String The first line of the billing address. H.No- 17, Block C, Kalyan Bldg, Khardilkar Road, Mumbai Note: This information is helpful when it comes to issues related to fraud detection and chargebacks. Hence, it is must to provide the correct information. | 34 Saikripa-Estate, Tilak Nagar |
address2optional but recommended for higher approval rate | String The second line of the billing address. | |
cityoptional but recommended for higher approval rate | String The city where your customer resides as part of the billing address. | Mumbai |
stateoptional but recommended for higher approval rate | String The state where your customer resides as part of the billing address. | Maharashtra |
countryoptional but recommended for higher approval rate | String The country where your customer resides. | India |
zipcodemandatory | String Billing address zip code is mandatory for the cardless EMI option. Character Limit-20 | 400004 |
pgmandatory for seamless/s2s flow | String It defines the payment category and post UPI. | UPI |
bankcodemandatory for seamless/s2s flow | String Each payment option is identified with a unique bank code at PayU. For UPI Autopay, post UPI. | UPI |
surlmandatory | String The success URL, which is the page PayU will redirect to if the transaction is successful. | |
furlmandatory | String The Failure URL, which is the page PayU will redirect to if the transaction is failed. | |
vpa conditional | String Customer's VPA handle. Mandatory for UPI Collect flow. | customer@upi |
si mandatory | String Signifies successful consent taken from the user. Must be 1 for subscription setup. | 1 |
si_details mandatory | JSON String JSON object containing mandate details (billingAmount, billingCurrency, billingCycle, etc.). Refer to si_details JSON Object below. | See si_details accordion |
txn_s2s_flow conditional | Integer Parameter to enable S2S flow. Must be 4 for Legacy Decoupled flow (UPI Intent). | 4 |
s2s_client_ip conditional | String Source IP of the customer. Required for UPI Intent flow. | 10.200.12.12 |
s2s_device_info conditional | String Customer agent's device information. Required for UPI Intent flow. | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
udf1mandatory if AD bank request this detail | String This parameter must contain the Buyer's PAN and date of birth in the following format (separated by two pipe characters): Buyer's PAN\|\|Buyer'sDOB | AAAPZ1234C\|\|22/08/1972 |
udf3mandatory if AD bank request this detail | String This parameter must contain the invoice ID of the transaction (generated by the merchant) and merchant name in the following format (separated by two pipe characters): Invoice ID\|\|MerchantName | INV-123_1231\|\|MerchantName |
buyer_type_business optional in case of B2B transaction for cross-border payments | Binary To be sent as "1" in case the buyer is a business. In case of individual buyers, it can be skipped. Default is "0". Note: This will be included in hash if posted (covered in next section | 1 |
Hashing Logic
Parameters in the below sequence needs to be checked before generating the hash, if these params are being posted, it needs to be added in the hash calculation:
|additional_charges|miles|base_payuid|base_merchantid|paisa_mecode|subvention_amount|subvention_eligibility|merchant_data|payoutdetails|loan_id|twid_customer_hash|splitrequest|percentage_additional_charges|force_pa|udf_params|buyer_type_business
- Case1 example: Simple Hashing, if the merchant is not sending the api_version in the payment request, then it will be treated as hash sequence version 1.
key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|salt
- Case2 example: if the merchant is passing the additional_charges in the payment request then they have to append the additional_charges value in the raw hash sequence as below.
key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|salt|additional_charges
- Case3 example: If the merchant wants to pass additional_charges, buyer_type_business in the payment request, then hash formula for payment request will be:
key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|salt|additional_charges|buyer_type_business
- Case4 example: if the merchant wants to pass the api_version = 7 and buyer_type_business, udf_params in the payment request.
key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|salt|udf_params|buyer_type_businesssi_details JSON Object
The si_details parameter is a JSON object containing mandate details:
{
"billingAmount": "10.00",
"billingCurrency": "INR",
"billingCycle": "MONTHLY",
"billingInterval": 1,
"paymentStartDate": "2025-06-05",
"paymentEndDate": "2025-12-01"
}| Field | Description | Example |
|---|---|---|
billingAmountmandatory | StringMaximum amount for recurring transactions. | 10.00 |
billingCurrencymandatory | StringCurrency code. | INR |
billingCyclemandatory | StringBilling frequency: DAILY, WEEKLY, MONTHLY, YEARLY, ADHOC. | MONTHLY |
billingIntervalmandatory | IntegerInterval between billing cycles. | 1 |
paymentStartDatemandatory | StringMandate start date (YYYY-MM-DD). | 2025-06-05 |
paymentEndDatemandatory | StringMandate end date (YYYY-MM-DD). | 2025-12-01 |
Request Payload Structure
UPI Collect Flow
{
"key": "JPM7Fg",
"txnid": "upiConsentTxn12345",
"amount": "10.00",
"productinfo": "Monthly Subscription",
"firstname": "Ashish",
"lastname": "Kumar",
"email": "[email protected]",
"phone": "9988776655",
"address1": "34 Saikripa-Estate, Tilak Nagar",
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"zipcode": "400004",
"surl": "https://example.com/success",
"furl": "https://example.com/failure",
"udf1": "AAAPZ1234C||22/08/1972",
"udf3": "INV-123_1231||MerchantName",
"buyer_type_business": "1",
"pg": "UPI",
"bankcode": "UPI",
"vpa": "customer@upi",
"api_version": "7",
"si": "1",
"si_details": "{\"billingAmount\":\"10.00\",\"billingCurrency\":\"INR\",\"billingCycle\":\"MONTHLY\",\"billingInterval\":1,\"paymentStartDate\":\"2025-06-05\",\"paymentEndDate\":\"2025-12-01\"}",
"hash": "generated_hash_value"
}UPI Intent Flow (with S2S Parameters)
{
"key": "JPM7Fg",
"txnid": "upiIntentTxn12345",
"amount": "10.00",
"productinfo": "Monthly Subscription",
"firstname": "Ashish",
"lastname": "Kumar",
"email": "[email protected]",
"phone": "9988776655",
"address1": "34 Saikripa-Estate, Tilak Nagar",
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"zipcode": "400004",
"surl": "https://example.com/success",
"furl": "https://example.com/failure",
"udf1": "AAAPZ1234C||22/08/1972",
"udf3": "INV-123_1231||MerchantName",
"buyer_type_business": "1",
"pg": "UPI",
"bankcode": "INTENT",
"api_version": "7",
"si": "1",
"si_details": "{\"billingAmount\":\"10.00\",\"billingCurrency\":\"INR\",\"billingCycle\":\"MONTHLY\",\"billingInterval\":1,\"paymentStartDate\":\"2025-06-05\",\"paymentEndDate\":\"2025-12-01\"}",
"txn_s2s_flow": "4",
"s2s_client_ip": "10.200.12.12",
"s2s_device_info": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"hash": "generated_hash_value"
}Sample Requests
UPI Collect - cURL
curl --location --request POST 'https://test.payu.in/_payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=JPM7Fg' \
--data-urlencode 'txnid=upiConsentTxn12345' \
--data-urlencode 'amount=10.00' \
--data-urlencode 'firstname=Ashish' \
--data-urlencode 'lastname=Kumar' \
--data-urlencode '[email protected]' \
--data-urlencode 'phone=9988776655' \
--data-urlencode 'productinfo=Monthly Subscription' \
--data-urlencode 'address1=34 Saikripa-Estate, Tilak Nagar' \
--data-urlencode 'city=Mumbai' \
--data-urlencode 'state=Maharashtra' \
--data-urlencode 'country=India' \
--data-urlencode 'zipcode=400004' \
--data-urlencode 'surl=https://example.com/success' \
--data-urlencode 'furl=https://example.com/failure' \
--data-urlencode 'udf1=AAAPZ1234C||22/08/1972' \
--data-urlencode 'udf3=INV-123_1231||MerchantName' \
--data-urlencode 'buyer_type_business=1' \
--data-urlencode 'pg=UPI' \
--data-urlencode 'bankcode=UPI' \
--data-urlencode 'vpa=customer@upi' \
--data-urlencode 'api_version=7' \
--data-urlencode 'si=1' \
--data-urlencode 'si_details={"billingAmount":"10.00","billingCurrency":"INR","billingCycle":"MONTHLY","billingInterval":1,"paymentStartDate":"2025-06-05","paymentEndDate":"2025-12-01"}' \
--data-urlencode 'hash=YOUR_CALCULATED_HASH'UPI Intent - cURL
curl --location --request POST 'https://test.payu.in/_payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=JPM7Fg' \
--data-urlencode 'txnid=upiIntentTxn12345' \
--data-urlencode 'amount=10.00' \
--data-urlencode 'firstname=Ashish' \
--data-urlencode 'lastname=Kumar' \
--data-urlencode '[email protected]' \
--data-urlencode 'phone=9988776655' \
--data-urlencode 'productinfo=Monthly Subscription' \
--data-urlencode 'address1=34 Saikripa-Estate, Tilak Nagar' \
--data-urlencode 'city=Mumbai' \
--data-urlencode 'state=Maharashtra' \
--data-urlencode 'country=India' \
--data-urlencode 'zipcode=400004' \
--data-urlencode 'surl=https://example.com/success' \
--data-urlencode 'furl=https://example.com/failure' \
--data-urlencode 'udf1=AAAPZ1234C||22/08/1972' \
--data-urlencode 'udf3=INV-123_1231||MerchantName' \
--data-urlencode 'buyer_type_business=1' \
--data-urlencode 'pg=UPI' \
--data-urlencode 'bankcode=INTENT' \
--data-urlencode 'api_version=7' \
--data-urlencode 'si=1' \
--data-urlencode 'si_details={"billingAmount":"10.00","billingCurrency":"INR","billingCycle":"MONTHLY","billingInterval":1,"paymentStartDate":"2025-06-05","paymentEndDate":"2025-12-01"}' \
--data-urlencode 'txn_s2s_flow=4' \
--data-urlencode 's2s_client_ip=10.200.12.12' \
--data-urlencode 's2s_device_info=Mozilla/5.0 (Windows NT 10.0; Win64; x64)' \
--data-urlencode 'hash=YOUR_CALCULATED_HASH'import requests
import json
import hashlib
url = 'https://test.payu.in/_payment'
# SI Details
si_details = {
'billingAmount': '10.00',
'billingCurrency': 'INR',
'billingCycle': 'MONTHLY',
'billingInterval': 1,
'paymentStartDate': '2025-06-05',
'paymentEndDate': '2025-12-01'
}
si_details_json = json.dumps(si_details)
# UPI Intent Payload with S2S parameters
payload = {
'key': 'JPM7Fg',
'txnid': 'upiIntentTxn12345',
'amount': '10.00',
'productinfo': 'Monthly Subscription',
'firstname': 'Ashish',
'lastname': 'Kumar',
'email': '[email protected]',
'phone': '9988776655',
'address1': '34 Saikripa-Estate, Tilak Nagar',
'city': 'Mumbai',
'state': 'Maharashtra',
'country': 'India',
'zipcode': '400004',
'surl': 'https://example.com/success',
'furl': 'https://example.com/failure',
'udf1': 'AAAPZ1234C||22/08/1972',
'udf3': 'INV-123_1231||MerchantName',
'buyer_type_business': '1',
'pg': 'UPI',
'bankcode': 'INTENT',
'api_version': '7',
'si': '1',
'si_details': si_details_json,
'txn_s2s_flow': '4',
's2s_client_ip': '10.200.12.12',
's2s_device_info': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
'hash': hash_value # Generated hash
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.post(url, data=payload, headers=headers)
if response.status_code == 200:
response_data = response.json()
print('Response:', response_data)
# Process the response
else:
print(f'Error: {response.status_code}')<?php
$url = 'https://test.payu.in/_payment';
$si_details = json_encode([
'billingAmount' => '10.00',
'billingCurrency' => 'INR',
'billingCycle' => 'MONTHLY',
'billingInterval' => 1,
'paymentStartDate' => '2025-06-05',
'paymentEndDate' => '2025-12-01'
]);
// UPI Intent with S2S parameters
$data = [
'key' => 'JPM7Fg',
'txnid' => 'upiIntentTxn12345',
'amount' => '10.00',
'productinfo' => 'Monthly Subscription',
'firstname' => 'Ashish',
'lastname' => 'Kumar',
'email' => '[email protected]',
'phone' => '9988776655',
'address1' => '34 Saikripa-Estate, Tilak Nagar',
'city' => 'Mumbai',
'state' => 'Maharashtra',
'country' => 'India',
'zipcode' => '400004',
'surl' => 'https://example.com/success',
'furl' => 'https://example.com/failure',
'udf1' => 'AAAPZ1234C||22/08/1972',
'udf3' => 'INV-123_1231||MerchantName',
'buyer_type_business' => '1',
'pg' => 'UPI',
'bankcode' => 'INTENT',
'api_version' => '7',
'si' => '1',
'si_details' => $si_details,
'txn_s2s_flow' => '4',
's2s_client_ip' => $_SERVER['REMOTE_ADDR'],
's2s_device_info' => $_SERVER['HTTP_USER_AGENT'],
'hash' => $hash // Generated hash
];
$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, [
'Content-Type: application/x-www-form-urlencoded'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 200) {
$responseData = json_decode($response, true);
print_r($responseData);
} else {
echo "Error: " . $httpCode;
}
?>const axios = require('axios');
const qs = require('querystring');
const url = 'https://test.payu.in/_payment';
const siDetails = JSON.stringify({
billingAmount: '10.00',
billingCurrency: 'INR',
billingCycle: 'MONTHLY',
billingInterval: 1,
paymentStartDate: '2025-06-05',
paymentEndDate: '2025-12-01'
});
// UPI Intent with S2S parameters
const payload = {
key: 'JPM7Fg',
txnid: 'upiIntentTxn12345',
amount: '10.00',
productinfo: 'Monthly Subscription',
firstname: 'Ashish',
lastname: 'Kumar',
email: '[email protected]',
phone: '9988776655',
address1: '34 Saikripa-Estate, Tilak Nagar',
city: 'Mumbai',
state: 'Maharashtra',
country: 'India',
zipcode: '400004',
surl: 'https://example.com/success',
furl: 'https://example.com/failure',
udf1: 'AAAPZ1234C||22/08/1972',
udf3: 'INV-123_1231||MerchantName',
buyer_type_business: '1',
pg: 'UPI',
bankcode: 'INTENT',
api_version: '7',
si: '1',
si_details: siDetails,
txn_s2s_flow: '4',
s2s_client_ip: '10.200.12.12',
s2s_device_info: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
hash: hash // Generated hash
};
axios.post(url, qs.stringify(payload), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(response => {
console.log('Response:', response.data);
})
.catch(error => {
console.error('Error:', error);
});
NoteBefore you make payment request to PayU, it is recommended to validate the UPI handle provided by your customer is eligible for recurring payment using the validateVPA API. For more information, refer to Validate VPA API.
Step 2: Check the Response from PayU
The API returns different response structures for UPI Collect and UPI Intent flows.
UPI Collect Response
For UPI Collect, the response is returned in URL-encoded format (application/x-www-form-urlencoded):
eyJzdGF0dXMiOiJzdWNjZXNzIiwicmVzdWx0Ijp7Im1paHBheWlkIjoiNzYwMTI2NTU4NSIsIm1vZGUiOiJVUEkiLCJzdGF0dXMiOiJwZW5kaW5nIiwia2V5IjoiTWVyY2hhbnRLZXkiLCJ0eG5pZCI6IjZiMmYzZDY4NWVjMWJiYTdkZDRiIiwiYW1vdW50IjoiMTAuMDAiLCJhZGRlZG9uIjoiMjAxOC0xMS0wMSAxOTo1NjozMiIsInByb2R1Y3RpbmZvIjoiUHJvZHVjdCBJbmZvIiwiZmlyc3RuYW1lIjoiUGF5dS1Vc2VyIiwibGFzdG5hbWUiOiIiLCJhZGRyZXNzMSI6IiIsImFkZHJlc3MyIjoiIiwiY2l0eSI6IiIsInN0YXRlIjoiIiwiY291bnRyeSI6IiIsInppcGNvZGUiOiIiLCJlbWFpbCI6InRlc3RAZXhhbXBsZS5jb20iLCJwaG9uZSI6IjEyMzQ1Njc4OTAiLCJ1ZGYxIjoiIiwidWRmMiI6IiIsInVkZjMiOiIiLCJ1ZGY0IjoiIiwidWRmNSI6IiIsInVkZjYiOiIiLCJ1ZGY3IjoiIiwidWRmOCI6IiIsInVkZjkiOiIiLCJ1ZGYxMCI6IiIsImNhcmRfdG9rZW4iOiIiLCJjYXJkX25vIjoiIiwiZmllbGQwIjoiIiwiZmllbGQxIjoiYWJjZEB1cGkiLCJmaWVsZDIiOiIiLCJmaWVsZDMiOiIiLCJmaWVsZDQiOiIiLCJmaWVsZDUiOiIiLCJmaWVsZDYiOiIiLCJmaWVsZDciOiIiLCJmaWVsZDgiOiIiLCJmaWVsZDkiOiIiLCJwYXltZW50X3NvdXJjZSI6InBheXVQdXJlUzJTIiwiUEdfVFlQRSI6IkFYSVNVIiwiZXJyb3IiOiJFMDAwIiwiZXJyb3JfTWVzc2FnZSI6Ik5vIEVycm9yIiwibmV0X2Ftb3VudF9kZWJpdCI6IjAiLCJhZGRpdGlvbmFsQ2hhcmdlcyI6IjI5LjUiLCJ1bm1hcHBlZHN0YXR1cyI6ImluIHByb2dyZXNzIiwiaGFzaCI6IjU2NzQ3OGE5ZDUyMzhlZTIyZGFhMDM2ZWMwMjAxMzk0OGY2YjgwNGUzMWNhYzNkYmQyMDc1NmU5ZjFkNDFlMjI4ZTQxYzJkYjcwZmU4ZWRlZmMyNDBiOTQwODZlN2QzN2Y4ZDQ2OTA4MzU4Y2NjNzA4Y2JjNWVlNTJjMjlkYWEwIiwiYmFua19yZWZfbm8iOiJBWEk5MTEwMDAwMDAwMDQ5MTg0NzY2MTU0MTc5OTcwNTY5OCIsImJhbmtfcmVmX251bSI6IkFYSTkxMTAwMDAwMDAwNDkxODQ3NjYxNTQxNzk5NzA1Njk4IiwiYmFua2NvZGUiOiJVUEkiLCJzdXJsIjoiaHR0cHM6XC9cL2FkbWluLnBheXUuaW5cL3Rlc3RfcmVzcG9uc2UiLCJjdXJsIjoiaHR0cHM6XC9cL2FkbWluLnBheXUuaW5cL3Rlc3RfcmVzcG9uc2UiLCJmdXJsIjoiaHR0cHM6XC9cL2FkbWluLnBheXUuaW5cL3Rlc3RfcmVzcG9uc2UifX0Base64 decoded response:
{"status":"success","result":{"mihpayid":"7601265585","mode":"UPI","status":"pending","key":"MerchantKey","txnid":"6b2f3d685ec1bba7dd4b","amount":"10.00","addedon":"2018-11-01
19:56:32","productinfo":"ProductInfo","firstname":"PayuUser","lastname":"","address1":"","address2":"","city":"","state":"","country":"","zipcode":"","email":"[email protected]","phone":"1234567890","udf1":"","udf2":"","udf3":"","udf4":"","udf5":"","udf6":"","udf7":"","udf8":"","udf9":"","udf10":"","card_token":"","card_no":"","field0":"","field1":"abcd@upi","field2":"","field3":"","field4":"","field5":"","field6":"","field7":"","field8":"","field9":"","payment_source":"payuPureS2S","PG_TYPE":"AXISU","error":"E000","error_Message":"NoError","net_amount_debit":"0","additionalCharges":"29.5","unmappedstatus":"inprogress","hash":"567478a9d5238ee22daa036ec02013948f6b804e31cac3dbd20756e9f1d41e228e41c2db70fe8edefc240b94086e7d37f8d46908358ccc708cbc5ee52c29daa0","bank_ref_no":"AXI91100000000491847661541799705698","bank_ref_num":"AXI91100000000491847661541799705698","bankcode":"UPI","surl":"https:\/\/admin.payu.in\/test_response","curl":"https:\/\/admin.payu.in\/test_response","furl":"https:\/\/admin.payu.in\/test_response"}}UPI Intent Response
For UPI Intent with S2S flow, the response is a JSON object containing the intent URI:
{
"metaData": {
"message": null,
"referenceId": "5ae6e6d94b4b5f9dee282b95f6020c98",
"statusCode": null,
"txnId": "upiIntentTxn12345",
"txnStatus": "pending",
"unmappedStatus": "pending"
},
"result": {
"paymentId": "15257049438",
"merchantName": "Your Merchant Name",
"merchantVpa": "merchant@hdfcbank",
"amount": "10.00",
"intentURIData": "upi://mandate?pa=merchant@hdfcbank&pn=MERCHANT NAME&mn=&tid=upiIntentTxn12345&validitystart=05062025&validityend=01122025&am=10.00&amrule=MAX&recur=MONTHLY&recurvalue=30&recurtype=&tr=15257049438&cu=INR&mc=5411&tn=UPI Transaction for upiIntentTxn12345&mode=13&purpose=14&orgid=159240&rev=Y&block=N&txnType=CREATE",
"postToBank": {
"token": "C6ABAA6A-F0CE-432A-61C1-CFA48EDE847B",
"amount": "10.00",
"mihpayid": "5ae6e6d94b4b5f9dee282b95f6020c98",
"disableIntentSeamlessFailure": "0",
"payeeVpa": "merchant@hdfcbank",
"payeeName": "Your Merchant Name",
"additionalCharges": 0,
"transactionFee": "10.00"
},
"issuerUrl": "https://secure.payu.in/intentSeamlessHandler.php"
}
}Response Handling Logic
If you want to use PayU's timer page for UPI collect, you can use the result.acsTemplate and base64decode it to redirect the customer on given HTML.
Step 3: Configure Webhooks
Configure webhooks to receive real-time transaction status updates. PayU will send POST requests to your webhook URL.
Webhook Configuration
You can configure the webhook from Payu dashboard directly for payment success/failure events. For more information, refer to Create a New Webhook. Once configured, you will receive transaction updates via HTTP POST.
Webhook Payload Example
unmappedstatus=success&phone=9988776655&txnid=upiConsentTxn12345&hash=84e335094bbcb2ddaa0f9a488eb338e143b273765d89c9dfa502402562d0b6f3c7935e28194ca92f380be7c84c3695415b106dcf52cb016a15fcf6adc98d724&status=success&firstname=Ashish&productinfo=Monthly Subscription&mode=UPI&amount=10.00&[email protected]&mihpayid=403993715525317379&surl=https://example.com/success&payment_source=sistWebhook Validation
Always validate the webhook hash before processing:
function validateWebhookHash($response, $salt) {
$hashSequence = "status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key";
$hashVarsSeq = explode('|', $hashSequence);
$hashString = $salt . '|';
foreach(array_reverse($hashVarsSeq) as $hashVar) {
$hashString .= isset($response[$hashVar]) ? $response[$hashVar] : '';
$hashString .= '|';
}
$hashString = rtrim($hashString, '|');
$calculatedHash = strtolower(hash('sha512', $hashString));
$receivedHash = strtolower($response['hash']);
return $calculatedHash === $receivedHash;
}Expected Values for Successful Registration
| Response Parameter | Expected Value | Description |
|---|---|---|
| status | success | Indicates that the transaction is successful with the UPI provider |
| payment_source | sist | Indicates UPI details have been marked correctly for Standing Instruction |
| mihpayid | <mihpayid> | PayU's transaction acknowledgment for a Consent transaction |
Handling Mandate Status Updates
If the mandate is not confirmed by the customer or is rejected by the bank, the status is communicated as "failure" over webhook.
| Status | Description |
|---|---|
success | Mandate registered successfully |
failure | Mandate registration failed or rejected |
pending | Mandate registration is pending customer approval |
For more information, refer to Set up WebHook to Receive Cancellation or Modification Update from the Issuer Bank.
Step 4: Verify Mandate Registration
After successful registration, verify the mandate status:
Verification Checklist
-
Check Response Parameters:
statusshould besuccesspayment_sourceshould besistmihpayidshould not be null
-
Store Mandate Details:
- Save
mihpayidfor future recurring payments - Save mandate expiry dates from
si_details - Store customer's VPA for reference
- Save
-
Test Subsequent Payment:
- Use the stored mandate details to initiate a subsequent recurring payment
- Verify the payment processes successfully
Recurring Payments Flow
Step 1: Pre-Debit SI Notification
Use the Pre-Debit SI API to send pre-debit notifications for upcoming recurring debits with parallel sequencing support. This notification mandator for Cards and UPI recurring only and not required for ENACH recurring.
| Environment | URL |
|---|---|
| Test | https://test.payu.in/merchant/postservice.php?form=2 |
| Production | https://info.payu.in/merchant/postservice.php?form=2 |
Request Parameters
| Parameter | Description | Example |
|---|---|---|
key mandatory | String Your merchant key provided by PayU. | JP***g |
command mandatory | String The API command name. | pre_debit_SI |
hash mandatory | String The hash value generated using the hash logic. | abc0ada2e12 |
var1 mandatory | JSON String JSON object containing the pre-debit details. For more information refer to var1 Object Parameters table. | See var1 Object below |
Hash logic
The hash is generated using the following formula:
hash = sha512(key|command|var1|salt)
var1 Object Parameters
Parameter | Description | Example |
|---|---|---|
authpayuid |
| 999000000000826 |
requestid |
| RCS0123459PD |
debitdate |
| 2024-11-22 |
amount |
| 125 |
invoiceDisplayNumber |
| 12345678910 |
action | Pass "Retrieve" or "Delete" according to the action need to be performed. For more information, refer to Additional Information table.. | Retrieve |
Sample Request
curl --location 'https://test.info.payu.in/merchant/postservice.php?form=2' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'command=pre_debit_SI' \
--data-urlencode 'var1={"authpayuid":"999000000000826","requestid":"RCS0123459PD","debitdate":"2024-11-22","amount":"125","invoiceDisplayNumber":"12345678910"}' \
--data-urlencode 'key=JP***g' \
--data-urlencode 'hash=abc0ada2e12'import requests
url = "https://test.info.payu.in/merchant/postservice.php?form=2"
payload = {
"command": "pre_debit_SI",
"var1": '{"authpayuid":"999000000000826","requestid":"RCS0123459PD","debitdate":"2024-11-22","amount":"125","invoiceDisplayNumber":"12345678910"}',
"key": "JP***g",
"hash": "abc0ada2e12"
}
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
response = requests.post(url, data=payload, headers=headers)
print(response.json())using System;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var client = new HttpClient();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("command", "pre_debit_SI"),
new KeyValuePair<string, string>("var1", "{\"authpayuid\":\"999000000000826\",\"requestid\":\"RCS0123459PD\",\"debitdate\":\"2024-11-22\",\"amount\":\"125\",\"invoiceDisplayNumber\":\"12345678910\"}"),
new KeyValuePair<string, string>("key", "JP***g"),
new KeyValuePair<string, string>("hash", "abc0ada2e12")
});
var response = await client.PostAsync("https://test.info.payu.in/merchant/postservice.php?form=2", content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}const sendPreDebitRequest = async () => {
const url = "https://test.info.payu.in/merchant/postservice.php?form=2";
const params = new URLSearchParams();
params.append("command", "pre_debit_SI");
params.append("var1", JSON.stringify({
authpayuid: "999000000000826",
requestid: "RCS0123459PD",
debitdate: "2024-11-22",
amount: "125",
invoiceDisplayNumber: "12345678910"
}));
params.append("key", "JP***g");
params.append("hash", "abc0ada2e12");
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: params
});
const data = await response.json();
console.log(data);
};
sendPreDebitRequest();import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class PreDebitSI {
public static void main(String[] args) throws Exception {
String url = "https://test.info.payu.in/merchant/postservice.php?form=2";
String params = "command=pre_debit_SI" +
"&var1=" + URLEncoder.encode("{\"authpayuid\":\"999000000000826\",\"requestid\":\"RCS0123459PD\",\"debitdate\":\"2024-11-22\",\"amount\":\"125\",\"invoiceDisplayNumber\":\"12345678910\"}", StandardCharsets.UTF_8) +
"&key=JP***g" +
"&hash=abc0ada2e12";
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(params.getBytes(StandardCharsets.UTF_8));
}
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
}<?php
$url = "https://test.info.payu.in/merchant/postservice.php?form=2";
$data = array(
"command" => "pre_debit_SI",
"var1" => json_encode(array(
"authpayuid" => "999000000000826",
"requestid" => "RCS0123459PD",
"debitdate" => "2024-11-22",
"amount" => "125",
"invoiceDisplayNumber" => "12345678910"
)),
"key" => "JP***g",
"hash" => "abc0ada2e12"
);
$ch = curl_init($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("Content-Type: application/x-www-form-urlencoded"));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>Sample Response
Success Response
{
"status": "1",
"action": "MANDATE_PRE_DEBIT",
"message": "Request Processed Successfully"
}Error Responses
| Scenario | Response |
|---|---|
| Invalid mandateSeqNo | {"status":"0","message":"Invalid value for mandateSeqNo","action":"MANDATE_PRE_DEBIT"} |
| Pre-debit already sent for sequence | {"status":"E9254","action":"MANDATE_PRE_DEBIT","message":"Predebit notification already sent for the mandate sequence no. 2"} |
| Execution already exists for sequence | {"status":"E9256","action":"MANDATE_PRE_DEBIT","message":"Execution already sent for the mandate sequence no.:2"} |
| Debit date exceeds 30 days | {"status":"E9260","action":"MANDATE_PRE_DEBIT","message":"Predebit notification can only be sent for a maximum 30 days in advance."} |
| Pre-debit sent for past sequence | {"status":"E9263","action":"MANDATE_PRE_DEBIT","message":"Predebit for calculated sequence sent during incorrect period"} |
Response Parameters
| Parameter | Description | Example |
|---|---|---|
| status | String Status of the request. 1 indicates success, 0 or error code indicates failure. | 1 |
| action | String The action performed. | MANDATE_PRE_DEBIT |
| message | String Description of the response status. | Request Processed Successfully |
Step 2: Recurring Payment Transaction
Use the Recurring Payment Transaction API to execute recurring payment transactions for customers who have already completed a successful mandate/registration transaction with Net Banking, UPI, or Cards. For detailed API reference, refer to Recurring Payment Transaction API - PACB.
| Environment | URL |
|---|---|
| Production | https://info.payu.in/merchant/postservice?form=2 |
| Test | https://test.payu.in/merchant/postservice?form=2 |
Request Parameters
| Parameter | Description | Example |
|---|---|---|
key mandatory | String Merchant Key provided by PayU | JPM7Fg |
command mandatory | String API command. Must be si_transaction | si_transaction |
var1 mandatory | JSON Object Transaction details object containing mandatory and optional fields | Refer to var1 Object Fields below |
hash mandatory | String SHA512 hash: sha512(key|command|var1|salt) | 9f5faabedb... |
var1 Object Fields
| Parameter | Description | Example |
|---|---|---|
authpayuid mandatory | String The mihpayid returned in the payment response of the Registration/Consent transaction when transaction is successfully completed. | 6611192557 |
amount mandatory | String The transaction amount which will be deducted from the customer's payment instrument. | 10.00 |
txnid mandatory | String Unique Transaction ID (Order ID) generated by the merchant for this recurring transaction. | REC15113506209 |
firstname mandatory | String First name of the buyer/customer. | John |
lastname mandatory | String Last name of the buyer/customer. | Doe |
address1 mandatory | String Address line 1 of the buyer. | 123 Main Street |
city mandatory | String City of the buyer. | Mumbai |
state mandatory | String State of the buyer. | Maharashtra |
country mandatory | String Country of the buyer. Allowed values: IN or India only. | IN |
zipcode mandatory | String ZIP/PIN code of the buyer. Must be a valid 6-digit Indian PIN code. | 400001 |
phone optional | String The phone number of the customer. | 9999999999 |
email optional | String The email address of the customer. | [email protected] |
invoiceDisplayNumber mandatory for Cards SI | String A unique display number by merchant for every subsequent invoice/recurring charge. This must be the same value passed during pre_debit_si API call. | 12345678910 |
udf5 mandatory | String Invoice ID for every merchant. This field is mandatory during or after the transaction. | INV789012 |
Sample Request
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=JPM7Fg&command=si_transaction&var1={
\"authpayuid\": \"6611192557\",
\"amount\": \"100.00\",
\"txnid\": \"REC15113506209\",
\"phone\": \"9999999999\",
\"email\": \"[email protected]\",
\"firstname\": \"John\",
\"lastname\": \"Doe\",
\"address1\": \"123 Main Street\",
\"city\": \"Mumbai\",
\"state\": \"Maharashtra\",
\"country\": \"IN\",
\"zipcode\": \"400001\",
\"invoiceDisplayNumber\": \"12345678910\",
\"udf1\": \"ABCDE1234F\",
\"udf2\": \"\",
\"udf3\": \"15-08-1990\",
\"udf4\": \"\",
\"udf5\": \"INV789012\"
}&hash=jbUS07Og8BToVZ..."import requests
url = "https://test.payu.in/merchant/postservice?form=2"
payload = {
"key": "JPM7Fg",
"command": "si_transaction",
"var1": '{"authpayuid":"6611192557","amount":"100.00","txnid":"REC15113506209","phone":"9999999999","email":"[email protected]","firstname":"John","lastname":"Doe","address1":"123 Main Street","city":"Mumbai","state":"Maharashtra","country":"IN","zipcode":"400001","invoiceDisplayNumber":"12345678910","udf1":"ABCDE1234F","udf2":"","udf3":"15-08-1990","udf4":"","udf5":"INV789012"}',
"hash": "jbUS07Og8BToVZ..."
}
headers = {
"accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
response = requests.post(url, data=payload, headers=headers)
print(response.json())using System;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var client = new HttpClient();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("key", "JPM7Fg"),
new KeyValuePair<string, string>("command", "si_transaction"),
new KeyValuePair<string, string>("var1", "{\"authpayuid\":\"6611192557\",\"amount\":\"100.00\",\"txnid\":\"REC15113506209\",\"phone\":\"9999999999\",\"email\":\"[email protected]\",\"firstname\":\"John\",\"lastname\":\"Doe\",\"address1\":\"123 Main Street\",\"city\":\"Mumbai\",\"state\":\"Maharashtra\",\"country\":\"IN\",\"zipcode\":\"400001\",\"invoiceDisplayNumber\":\"12345678910\",\"udf1\":\"ABCDE1234F\",\"udf2\":\"\",\"udf3\":\"15-08-1990\",\"udf4\":\"\",\"udf5\":\"INV789012\"}"),
new KeyValuePair<string, string>("hash", "jbUS07Og8BToVZ...")
});
var response = await client.PostAsync("https://test.payu.in/merchant/postservice?form=2", content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}const executeRecurringPayment = async () => {
const url = "https://test.payu.in/merchant/postservice?form=2";
const params = new URLSearchParams();
params.append("key", "JPM7Fg");
params.append("command", "si_transaction");
params.append("var1", JSON.stringify({
authpayuid: "6611192557",
amount: "100.00",
txnid: "REC15113506209",
phone: "9999999999",
email: "[email protected]",
firstname: "John",
lastname: "Doe",
address1: "123 Main Street",
city: "Mumbai",
state: "Maharashtra",
country: "IN",
zipcode: "400001",
invoiceDisplayNumber: "12345678910",
udf1: "ABCDE1234F",
udf2: "",
udf3: "15-08-1990",
udf4: "",
udf5: "INV789012"
}));
params.append("hash", "jbUS07Og8BToVZ...");
const response = await fetch(url, {
method: "POST",
headers: {
"accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: params
});
const data = await response.json();
console.log(data);
};
executeRecurringPayment();import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class RecurringPaymentTransaction {
public static void main(String[] args) throws Exception {
String url = "https://test.payu.in/merchant/postservice?form=2";
String params = "key=JPM7Fg" +
"&command=si_transaction" +
"&var1=" + URLEncoder.encode("{\"authpayuid\":\"6611192557\",\"amount\":\"100.00\",\"txnid\":\"REC15113506209\",\"phone\":\"9999999999\",\"email\":\"[email protected]\",\"firstname\":\"John\",\"lastname\":\"Doe\",\"address1\":\"123 Main Street\",\"city\":\"Mumbai\",\"state\":\"Maharashtra\",\"country\":\"IN\",\"zipcode\":\"400001\",\"invoiceDisplayNumber\":\"12345678910\",\"udf1\":\"ABCDE1234F\",\"udf2\":\"\",\"udf3\":\"15-08-1990\",\"udf4\":\"\",\"udf5\":\"INV789012\"}", StandardCharsets.UTF_8) +
"&hash=jbUS07Og8BToVZ...";
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("accept", "application/json");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(params.getBytes(StandardCharsets.UTF_8));
}
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
}<?php
$url = "https://test.payu.in/merchant/postservice?form=2";
$data = array(
"key" => "JPM7Fg",
"command" => "si_transaction",
"var1" => json_encode(array(
"authpayuid" => "6611192557",
"amount" => "100.00",
"txnid" => "REC15113506209",
"phone" => "9999999999",
"email" => "[email protected]",
"firstname" => "John",
"lastname" => "Doe",
"address1" => "123 Main Street",
"city" => "Mumbai",
"state" => "Maharashtra",
"country" => "IN",
"zipcode" => "400001",
"invoiceDisplayNumber" => "12345678910",
"udf1" => "ABCDE1234F",
"udf2" => "",
"udf3" => "15-08-1990",
"udf4" => "",
"udf5" => "INV789012"
)),
"hash" => "jbUS07Og8BToVZ..."
);
$ch = curl_init($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);
curl_close($ch);
echo $response;
?>Sample Response
Success Response
{
"status": 1,
"message": "Transaction Processed successfully",
"details": {
"REC15113506209": {
"transactionid": "REC15113506209",
"amount": "100.00",
"payuid": "6611427463",
"status": "captured",
"field9": "Transaction Completed Successfully",
"phone": "9999999999",
"email": "[email protected]",
"udf1": "ABCDE1234F",
"udf2": "",
"udf3": "15-08-1990",
"udf4": "",
"udf5": "INV789012"
}
}
}Failure Responses
| Scenario | Response |
|---|---|
| Invalid Hash | {"status": 0, "msg": "Invalid Hash."} |
| Basic Authentication Failed | {"status": 1, "message": "Transaction Processed successfully", "details": {"REC9812123123": {"status": "failed", "field9": "Basic authentication check failed"}}} |
| Invalid Country | {"status": 0, "message": "Invalid country. Only 'IN' or 'India' is allowed."} |
| Missing Mandatory Fields | {"status": 0, "message": "Missing mandatory field: firstname/lastname/address1/city/state/country/zipcode"} |
Transaction Status Values
Status Description captured Transaction successful pending Payment initiated with bank/NPCI. Final status will be notified via webhook. failed Transaction failed in-progress Transaction is being processed
Step 3: Update Invoice ID [Optional]
If the Invoice ID value was unavailable when posting the transaction at Step 1, it can be updated using the UDF Update API by posting it in the UDF5 parameter.
Sample request other then UPI AutoPay
curl --location --globoff 'https://test.payu.in/merchant/postservice.php?form=2' \
--form 'key="PRiQvJ"' \
--form 'command="udf_update"' \
--form 'var1="my_order_642"' \
--form 'var2="AAAPZ1234C"' \
--form 'var4="22/08/1972"' \
--form 'var5="SellerName"' \
--form 'var6="INV000000005"' \
--form 'hash="{{hash}}"'Sample request for UPI AutoPay
curl --location 'https://test.payu.in/merchant/postservice.php?form=2' \
--form 'key="PRiQvJ"' \
--form 'command="udf_update"' \
--form 'var1="my_order_642"' \
--form 'var2="AAAPZ1234C||22-08-1972"' \
--form 'var4="INV_121312||SellerName"' \
--form 'hash="{{hash}}"'Sample response
Success Scenario
- If successfully updated for cards
{
"status": "UDF values updated",
"transaction_id": "my_order_64240",
"udf1": "AAAPZ1234C",
"udf2": "",
"udf3": "22/08/1972",
"udf4": "SellerName",
"udf5": "INV000000005"
}- If successfully updated for UPI autopay:
{
"status": "UDF values updated",
"transaction_id": "my_order_64240",
"udf1": "AAAPZ1234C||22-08-1972",
"udf2": "",
"udf3": "INV_121312||SellerName"
}Failure Scenarios
- If the transaction ID is empty
(
[status] => 0
[msg] => Parameter missing
) - If the transaction ID is invalid
(
[status] => 0
[msg] => Invalid TXN ID
) - If Hash is invalid:
{
"status": 0,
"msg": "Invalid Hash."
}- If the merchant is not enabled for UDF updates:
{
"status": "0",
"msg": "Update not allowed on provided Field"
}- If no data found in the transaction ID:
{
"status": "0",
"msg": "No Data Found for txnid: 3424"
}- If the merchant is inactive:
{
"msg": "Merchant is not authorized to use PayU API",
"status": 0
}Related Documentation
- UPI Consent Transaction API Reference
- SI Parameter JSON Details
- Manage UPI Recurring Transaction
- Validate VPA API
- Bank Codes - Recurring Payments
Updated about 2 hours ago
