[S2S] Cards Consent Transaction - Cross-Border
This section describes the Registration consent transaction for recurring card payments using PayU's Server-to-Server (S2S) integration with PACB (Payment Aggregator Cross Border) flow.
Prerequisites
Before starting the integration, ensure you have:
- Active PayU merchant account with PACB enabled
- Merchant Key and Salt from PayU dashboard
- Test environment access for development
Payment consent flow
Send the ENACH consent transaction request with S2S parameters.
Handle the response for Net Banking flow.
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 Flow
Step 1: Post the Request
Before implementing, familiarize yourself with the required parameters.
Key Parameters for Mandate Registration
- Mandatory Parameters: key, txnid, amount, productinfo, firstname, email, phone, surl, furl, hash, pg, bankcode, card details (ccnum, ccvv, ccname, ccexpmon, ccexpyr), si, si_details, api_version, udf1-udf5
- S2S Flow Parameters: txn_s2s_flow, s2s_client_ip, s2s_device_info
- SI Details: JSON object containing billing cycle, amounts, and dates
Construct the request payload with all required parameters. Ensure si_details is properly formatted as a JSON string.
Reference: For the API reference, refer to Registration Mandate for Cards - CB.
| Parameter | Description | Example |
|---|---|---|
keymandatory | StringMerchant key provided by PayU during onboarding. | JPM7Fg |
txnidmandatory | StringThe transaction ID is a reference number for a specific order generated by the merchant. Must be unique. | payuTestTxn12345 |
amountmandatory | StringThe payment amount for the transaction. | 100.00 |
productinfomandatory | StringA brief description of the product. Character Limit: 100 | iPhone |
firstnamemandatory | StringThe first name of the customer. Character Limit: 60 | Ashish |
emailmandatory | StringThe email address of the customer. Character Limit: 50 | [email protected] |
phonemandatory | StringThe phone number of the customer. | 9876543210 |
surlmandatory | StringThe Success URL - page PayU will redirect to if the transaction is successful. | https://example.com/success |
furlmandatory | StringThe Failure URL - page PayU will redirect to if the transaction fails. | https://example.com/failure |
pgmandatory | StringPayment gateway type. For cards, use CC. | CC |
bankcodemandatory | StringBank code for the payment option. Use CC for credit cards, DC for debit cards. | CC |
ccnummandatory | String13-19 digit card number (15 for AMEX, 13-19 for Maestro). Validate with LUHN algorithm. | 5506900480000008 |
ccvvmandatory | String3-digit CVV (4 digits for AMEX). | 123 |
ccnamemandatory | StringCardholder name as entered by the customer. | Test User |
ccexpmonmandatory | StringCard expiry month in MM format (01-12). | 09 |
ccexpyrmandatory | StringCard expiry year in YYYY format. | 2026 |
address1optional but recommended for higher approval rate | varchar The customer's primary billing address line. This field is required for billing and fraud prevention purposes. Character limit: 255. | 123 Main Street |
cityoptional but recommended for higher approval rate | varchar The customer's billing city. This field is required for billing and fraud prevention purposes. Character limit: 50. | New York |
stateoptional but recommended for higher approval rate | varchar The customer's billing state or province. This field is required for billing and fraud prevention purposes. Character limit: 50. | NY |
countryoptional but recommended for higher approval rate | varchar The customer's billing country code. This field is required for billing and fraud prevention purposes. Use ISO 3166-1 alpha-2 country codes. Character limit: 2. | US |
zipcodemandatory | varchar The customer's billing postal/zip code. This field is required for billing and fraud prevention purposes. Character limit: 20. | 10001 |
surlmandatory | URL The success URL to which PayU redirects after a successful transaction. | https://example.com/success |
furlmandatory | URL The failure URL to which PayU redirects after a failed transaction. | https://example.com/failure |
api_versionmandatory | int Constant value to indicate the API version. Always pass as 7. | 7 |
simandatory | int Signifies user consent for subscriptions. Must be 1 for a valid subscription setup. | 1 |
free_trialoptional | int Enables free trials (adjusts transaction amount to INR 0.00 for Net Banking, INR 2.00 for others). | 1 |
si_detailsmandatory | JSON Details required for subscription registration as per RBI guidelines. Must include billingAmount, billingCurrency, billingCycle, billingInterval, paymentStartDate, and paymentEndDate. | {"billingAmount": "100.00", "billingCurrency": "INR", "billingCycle": "MONTHLY", "billingInterval": 1, "paymentStartDate": "2019-09-01", "paymentEndDate": "2019-12-01"} |
udf1optional but recommended for higher approval rate | String If needed, contains the buyer's PAN. For UPI recurring, format is "Buyer's PAN||Buyer's DOB". Character limit: 255. | AELPR1234E or AELPR1234E||02-02-1980 |
udf2optional | String User-defined field for storing transaction-specific data. Character limit: 255. | Additional transaction data |
udf3optional but recommended for higher approval rate | String Date of Birth (DOB) of buyer in DD-MM-YYYY | 02-02-1980 |
udf4mandatory for payment aggregators | String End merchant legal entity name. For UPI, this field should not be passed. Character limit: 255. | XYZ Pvt. Ltd. |
udf5mandatory for cross-border payments | String Contains invoice ID for the merchant. Character limit: 255. | INV123456 |
buyer_type_businessoptional 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 |
udf_paramsoptional | String JSONUDF7 value to capture "Import or Export Code" of the buyer UDF8 value to capture Airway Bill Number / Consignment Number (in case of goods imports) | {"udf7":"0100000029", "udf8":"99953729071"} |
hashmandatory | String Crucial security parameter using SHA512 hash encryption. Formula incorporates key, txnid, amount, productinfo, firstname, email, udf fields, si_details, and merchant salt. | <Generated Hash> |
txn_s2s_flowmandatory | IntegerParameter to enable S2S flow. Set to 4 for S2S4 flow. | 4 |
s2s_client_ipmandatory | StringClient IP captured by merchant in S2S flow. Required for fraud detection. | 10.200.12.12 |
s2s_device_infomandatory | StringUser Agent captured by merchant in S2S flow. | Mozilla/5.0 (Windows NT 10.0; Win64; x64) PayU-API-Test/1.0 |
user_credentialsmandatory | StringFormat: merchant_key:customer_id. Required for token provisioning. | JPM7Fg:customer_1112 |
store_cardmandatory | IntegerSet to 1 to store the card token. | 1 |
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_businessRequest Payload Structure
{
"key": "JPM7Fg",
"txnid": "payuTestMandate12345",
"amount": "100.00",
"productinfo": "Subscription Plan",
"firstname": "Ashish",
"lastname": "Kumar",
"email": "[email protected]",
"phone": "9988776655",
"surl": "https://example.com/success",
"furl": "https://example.com/failure",
"pg": "CC",
"bankcode": "CC",
"ccnum": "5506900480000008",
"ccname": "Test User",
"ccvv": "123",
"ccexpmon": "09",
"ccexpyr": "2026",
"api_version": "7",
"si": "1",
"si_details": "{\"billingAmount\":\"200.00\",\"billingCurrency\":\"INR\",\"billingCycle\":\"ADHOC\",\"billingInterval\":1,\"paymentStartDate\":\"2025-06-05\",\"paymentEndDate\":\"2025-12-01\",\"siTokenRequestor\":\"2\"}",
"udf1": "AELPR****E",
"udf2": "",
"udf3": "02-02-1980",
"udf4": "XYZ Pvt. Ltd.",
"udf5": "098450845",
"buyer_type_business": "1",
"udf_params": "{\"udf7\":\"0100000029\",\"udf8\":\"99953729071\"}",
"txn_s2s_flow": "4",
"s2s_client_ip": "10.200.12.12",
"s2s_device_info": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) PayU-API-Test/1.0",
"hash": "generated_hash_value"Sample Request
Send a POST request to PayU's API endpoint with the payload.
curl --location --request POST 'https://test.payu.in/_payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=JPM7Fg' \
--data-urlencode 'txnid=payuTestMandate12345' \
--data-urlencode 'amount=100.00' \
--data-urlencode 'firstname=Ashish' \
--data-urlencode 'lastname=Kumar' \
--data-urlencode '[email protected]' \
--data-urlencode 'phone=9988776655' \
--data-urlencode 'productinfo=Subscription Plan' \
--data-urlencode 'surl=https://test.payu.in/admin/test_response' \
--data-urlencode 'furl=https://test.payu.in/admin/test_response' \
--data-urlencode 'pg=CC' \
--data-urlencode 'bankcode=CC' \
--data-urlencode 'ccnum=5506900480000008' \
--data-urlencode 'ccname=Test User' \
--data-urlencode 'ccvv=123' \
--data-urlencode 'ccexpmon=09' \
--data-urlencode 'ccexpyr=2026' \
--data-urlencode 'api_version=7' \
--data-urlencode 'si=1' \
--data-urlencode 'si_details={"billingAmount":"200.00","billingCurrency":"INR","billingCycle":"ADHOC","billingInterval":1,"paymentStartDate":"2025-06-05","paymentEndDate":"2025-12-01","siTokenRequestor":"2"}' \
--data-urlencode 'udf1=AELPR****E' \
--data-urlencode 'udf2=' \
--data-urlencode 'udf3=02-02-1980' \
--data-urlencode 'udf4=XYZ Pvt. Ltd.' \
--data-urlencode 'udf5=098450845' \
--data-urlencode 'buyer_type_business=1' \
--data-urlencode 'udf_params={"udf7":"0100000029","udf8":"99953729071"}' \
--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) PayU-API-Test/1.0' \
--data-urlencode 'hash=YOUR_CALCULATED_HASH'import requests
url = "https://test.payu.in/_payment"
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
data = {
'key': 'JPM7Fg',
'txnid': 'payuTestMandate12345',
'amount': '100.00',
'firstname': 'Ashish',
'lastname': 'Kumar',
'email': '[email protected]',
'phone': '9988776655',
'productinfo': 'Subscription Plan',
'surl': 'https://test.payu.in/admin/test_response',
'furl': 'https://test.payu.in/admin/test_response',
'pg': 'CC',
'bankcode': 'CC',
'ccnum': '5506900480000008',
'ccname': 'Test User',
'ccvv': '123',
'ccexpmon': '09',
'ccexpyr': '2026',
'api_version': '7',
'si': '1',
'si_details': '{"billingAmount":"200.00","billingCurrency":"INR","billingCycle":"ADHOC","billingInterval":1,"paymentStartDate":"2025-06-05","paymentEndDate":"2025-12-01","siTokenRequestor":"2"}',
'udf1': 'AELPR****E',
'udf2': '',
'udf3': '02-02-1980',
'udf4': 'XYZ Pvt. Ltd.',
'udf5': '098450845',
'buyer_type_business': '1',
'udf_params': '{"udf7":"0100000029","udf8":"99953729071"}',
'txn_s2s_flow': '4',
's2s_client_ip': '10.200.12.12',
's2s_device_info': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) PayU-API-Test/1.0',
'hash': 'YOUR_CALCULATED_HASH'
}
try:
response = requests.post(url, headers=headers, data=data)
print("Status Code:", response.status_code)
print("Response:", response.text)
except requests.exceptions.RequestException as e:
print("Error:", e)using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
string url = "https://test.payu.in/_payment";
using HttpClient client = new HttpClient();
List<KeyValuePair<string, string>> postData = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("key", "JPM7Fg"),
new KeyValuePair<string, string>("txnid", "payuTestMandate12345"),
new KeyValuePair<string, string>("amount", "100.00"),
new KeyValuePair<string, string>("firstname", "Ashish"),
new KeyValuePair<string, string>("lastname", "Kumar"),
new KeyValuePair<string, string>("email", "[email protected]"),
new KeyValuePair<string, string>("phone", "9988776655"),
new KeyValuePair<string, string>("productinfo", "Subscription Plan"),
new KeyValuePair<string, string>("surl", "https://test.payu.in/admin/test_response"),
new KeyValuePair<string, string>("furl", "https://test.payu.in/admin/test_response"),
new KeyValuePair<string, string>("pg", "CC"),
new KeyValuePair<string, string>("bankcode", "CC"),
new KeyValuePair<string, string>("ccnum", "5506900480000008"),
new KeyValuePair<string, string>("ccname", "Test User"),
new KeyValuePair<string, string>("ccvv", "123"),
new KeyValuePair<string, string>("ccexpmon", "09"),
new KeyValuePair<string, string>("ccexpyr", "2026"),
new KeyValuePair<string, string>("api_version", "7"),
new KeyValuePair<string, string>("si", "1"),
new KeyValuePair<string, string>("si_details", "{\"billingAmount\":\"200.00\",\"billingCurrency\":\"INR\",\"billingCycle\":\"ADHOC\",\"billingInterval\":1,\"paymentStartDate\":\"2025-06-05\",\"paymentEndDate\":\"2025-12-01\",\"siTokenRequestor\":\"2\"}"),
new KeyValuePair<string, string>("udf1", "AELPR****E"),
new KeyValuePair<string, string>("udf2", ""),
new KeyValuePair<string, string>("udf3", "02-02-1980"),
new KeyValuePair<string, string>("udf4", "XYZ Pvt. Ltd."),
new KeyValuePair<string, string>("udf5", "098450845"),
new KeyValuePair<string, string>("buyer_type_business", "1"),
new KeyValuePair<string, string>("udf_params", "{\"udf7\":\"0100000029\",\"udf8\":\"99953729071\"}"),
new KeyValuePair<string, string>("txn_s2s_flow", "4"),
new KeyValuePair<string, string>("s2s_client_ip", "10.200.12.12"),
new KeyValuePair<string, string>("s2s_device_info", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) PayU-API-Test/1.0"),
new KeyValuePair<string, string>("hash", "YOUR_CALCULATED_HASH")
};
FormUrlEncodedContent content = new FormUrlEncodedContent(postData);
try
{
HttpResponseMessage response = await client.PostAsync(url, content);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine($"Response: {responseBody}");
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
}async function makePayment() {
const url = "https://test.payu.in/_payment";
const formData = new URLSearchParams();
formData.append('key', 'JPM7Fg');
formData.append('txnid', 'payuTestMandate12345');
formData.append('amount', '100.00');
formData.append('firstname', 'Ashish');
formData.append('lastname', 'Kumar');
formData.append('email', '[email protected]');
formData.append('phone', '9988776655');
formData.append('productinfo', 'Subscription Plan');
formData.append('surl', 'https://test.payu.in/admin/test_response');
formData.append('furl', 'https://test.payu.in/admin/test_response');
formData.append('pg', 'CC');
formData.append('bankcode', 'CC');
formData.append('ccnum', '5506900480000008');
formData.append('ccname', 'Test User');
formData.append('ccvv', '123');
formData.append('ccexpmon', '09');
formData.append('ccexpyr', '2026');
formData.append('api_version', '7');
formData.append('si', '1');
formData.append('si_details', '{"billingAmount":"200.00","billingCurrency":"INR","billingCycle":"ADHOC","billingInterval":1,"paymentStartDate":"2025-06-05","paymentEndDate":"2025-12-01","siTokenRequestor":"2"}');
formData.append('udf1', 'AELPR****E');
formData.append('udf2', '');
formData.append('udf3', '02-02-1980');
formData.append('udf4', 'XYZ Pvt. Ltd.');
formData.append('udf5', '098450845');
formData.append('buyer_type_business', '1');
formData.append('udf_params', '{"udf7":"0100000029","udf8":"99953729071"}');
formData.append('txn_s2s_flow', '4');
formData.append('s2s_client_ip', '10.200.12.12');
formData.append('s2s_device_info', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) PayU-API-Test/1.0');
formData.append('hash', 'YOUR_CALCULATED_HASH');
const requestOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData
};
try {
const response = await fetch(url, requestOptions);
const responseText = await response.text();
console.log('Status Code:', response.status);
console.log('Response:', responseText);
} catch (error) {
console.error('Error:', error);
}
}
makePayment();import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class PayUPayment {
public static void main(String[] args) {
try {
String url = "https://test.payu.in/_payment";
URL obj = new URL(url);
HttpURLConnection connection = (HttpURLConnection) obj.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setDoOutput(true);
StringBuilder postData = new StringBuilder();
postData.append("key=").append(URLEncoder.encode("JPM7Fg", StandardCharsets.UTF_8));
postData.append("&txnid=").append(URLEncoder.encode("payuTestMandate12345", StandardCharsets.UTF_8));
postData.append("&amount=").append(URLEncoder.encode("100.00", StandardCharsets.UTF_8));
postData.append("&firstname=").append(URLEncoder.encode("Ashish", StandardCharsets.UTF_8));
postData.append("&lastname=").append(URLEncoder.encode("Kumar", StandardCharsets.UTF_8));
postData.append("&email=").append(URLEncoder.encode("[email protected]", StandardCharsets.UTF_8));
postData.append("&phone=").append(URLEncoder.encode("9988776655", StandardCharsets.UTF_8));
postData.append("&productinfo=").append(URLEncoder.encode("Subscription Plan", StandardCharsets.UTF_8));
postData.append("&surl=").append(URLEncoder.encode("https://test.payu.in/admin/test_response", StandardCharsets.UTF_8));
postData.append("&furl=").append(URLEncoder.encode("https://test.payu.in/admin/test_response", StandardCharsets.UTF_8));
postData.append("&pg=").append(URLEncoder.encode("CC", StandardCharsets.UTF_8));
postData.append("&bankcode=").append(URLEncoder.encode("CC", StandardCharsets.UTF_8));
postData.append("&ccnum=").append(URLEncoder.encode("5506900480000008", StandardCharsets.UTF_8));
postData.append("&ccname=").append(URLEncoder.encode("Test User", StandardCharsets.UTF_8));
postData.append("&ccvv=").append(URLEncoder.encode("123", StandardCharsets.UTF_8));
postData.append("&ccexpmon=").append(URLEncoder.encode("09", StandardCharsets.UTF_8));
postData.append("&ccexpyr=").append(URLEncoder.encode("2026", StandardCharsets.UTF_8));
postData.append("&api_version=").append(URLEncoder.encode("7", StandardCharsets.UTF_8));
postData.append("&si=").append(URLEncoder.encode("1", StandardCharsets.UTF_8));
postData.append("&si_details=").append(URLEncoder.encode("{\"billingAmount\":\"200.00\",\"billingCurrency\":\"INR\",\"billingCycle\":\"ADHOC\",\"billingInterval\":1,\"paymentStartDate\":\"2025-06-05\",\"paymentEndDate\":\"2025-12-01\",\"siTokenRequestor\":\"2\"}", StandardCharsets.UTF_8));
postData.append("&udf1=").append(URLEncoder.encode("AELPR****E", StandardCharsets.UTF_8));
postData.append("&udf2=").append(URLEncoder.encode("", StandardCharsets.UTF_8));
postData.append("&udf3=").append(URLEncoder.encode("02-02-1980", StandardCharsets.UTF_8));
postData.append("&udf4=").append(URLEncoder.encode("XYZ Pvt. Ltd.", StandardCharsets.UTF_8));
postData.append("&udf5=").append(URLEncoder.encode("098450845", StandardCharsets.UTF_8));
postData.append("&buyer_type_business=").append(URLEncoder.encode("1", StandardCharsets.UTF_8));
postData.append("&udf_params=").append(URLEncoder.encode("{\"udf7\":\"0100000029\",\"udf8\":\"99953729071\"}", StandardCharsets.UTF_8));
postData.append("&txn_s2s_flow=").append(URLEncoder.encode("4", StandardCharsets.UTF_8));
postData.append("&s2s_client_ip=").append(URLEncoder.encode("10.200.12.12", StandardCharsets.UTF_8));
postData.append("&s2s_device_info=").append(URLEncoder.encode("Mozilla/5.0 (Windows NT 10.0; Win64; x64) PayU-API-Test/1.0", StandardCharsets.UTF_8));
postData.append("&hash=").append(URLEncoder.encode("YOUR_CALCULATED_HASH", StandardCharsets.UTF_8));
try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
wr.writeBytes(postData.toString());
wr.flush();
}
int responseCode = connection.getResponseCode();
System.out.println("Status Code: " + responseCode);
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println("Response: " + response.toString());
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}<?php
$url = "https://test.payu.in/_payment";
$postData = array(
'key' => 'JPM7Fg',
'txnid' => 'payuTestMandate12345',
'amount' => '100.00',
'firstname' => 'Ashish',
'lastname' => 'Kumar',
'email' => '[email protected]',
'phone' => '9988776655',
'productinfo' => 'Subscription Plan',
'surl' => 'https://test.payu.in/admin/test_response',
'furl' => 'https://test.payu.in/admin/test_response',
'pg' => 'CC',
'bankcode' => 'CC',
'ccnum' => '5506900480000008',
'ccname' => 'Test User',
'ccvv' => '123',
'ccexpmon' => '09',
'ccexpyr' => '2026',
'api_version' => '7',
'si' => '1',
'si_details' => '{"billingAmount":"200.00","billingCurrency":"INR","billingCycle":"ADHOC","billingInterval":1,"paymentStartDate":"2025-06-05","paymentEndDate":"2025-12-01","siTokenRequestor":"2"}',
'udf1' => 'AELPR****E',
'udf2' => '',
'udf3' => '02-02-1980',
'udf4' => 'XYZ Pvt. Ltd.',
'udf5' => '098450845',
'buyer_type_business' => '1',
'udf_params' => '{"udf7":"0100000029","udf8":"99953729071"}',
'txn_s2s_flow' => '4',
's2s_client_ip' => '10.200.12.12',
's2s_device_info' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) PayU-API-Test/1.0',
'hash' => 'YOUR_CALCULATED_HASH'
);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($postData)
)
);
$context = stream_context_create($options);
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) {
echo "Error: Failed to make request\n";
} else {
$http_response_header = $http_response_header ?? [];
echo "Status: " . (isset($http_response_header[0]) ? $http_response_header[0] : 'Unknown') . "\n";
echo "Response: " . $result . "\n";
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>Step 2: Check the Response from PayU
The API returns a JSON response. For S2S4 flow, you'll receive an OTP enrollment response if the card requires OTP authentication.
Successful Response Structure
{
"metaData": {
"message": null,
"referenceId": "5a3e7cb9884e003dce1f28f965478a9a12fb9244fc15be91b0b3de48763a12e7",
"statusCode": null,
"txnId": "payuTestMandate12345",
"txnStatus": "Enrolled",
"unmappedStatus": "pending",
"resendOtp": {
"isSupported": true,
"attemptsLeft": 2
},
"submitOtp": {
"attemptsLeft": 3
}
},
"result": {
"otpPostUrl": "https://test.payu.in/ResponseHandler.php",
"acsTemplate": "PGh0bWw+PGJvZHk+PGZvcm0gbmFtZT0icGF5bWVudF9wb3N0IiBpZD0i..."
},
"binData": {
"pureS2SSupported": true,
"issuingBank": "AXIS",
"category": "creditcard",
"cardType": "MAST",
"isDomestic": true
}
}Response Handling Logic
- Check Transaction Status: Verify
metaData.txnStatusandmetaData.unmappedStatus - Store Mandate Details: On successful registration, store
mihpayidand mandate details for future recurring payments - Error Handling: Check for error codes and handle accordingly
Step 3: Configure Webhooks
Configure webhooks to receive real-time transaction status updates. PayU will send POST requests to your webhook URL.
Webhook Payload Example
status=success&mihpayid=403993715525316543&txnid=payuTestMandate12345&amount=100.00&productinfo=Subscription Plan&firstname=Ashish&[email protected]&phone=9988776655&hash=generated_hash&payment_source=sist&cardToken=stored_token_valueWebhook Validation
Always validate the webhook hash before processing:
function validateWebhookHash($response, $salt) {
$hashString = '';
$hashSequence = "status|mihpayid|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||||||";
$hashVarsSeq = explode('|', $hashSequence);
foreach($hashVarsSeq as $hashVar) {
$hashString .= isset($response[$hashVar]) ? $response[$hashVar] : '';
$hashString .= '|';
}
$hashString .= $salt;
$calculatedHash = strtolower(hash('sha512', $hashString));
$receivedHash = strtolower($response['hash']);
return $calculatedHash === $receivedHash;
}For detailed webhook handling, refer to S2S Webhook Handling.
Step 4: Verify Mandate Registration
After successful registration, verify the mandate status:
- Check Response Parameters:
| Response Parameter | Expected Value | Description |
|---|---|---|
| status | success | Indicates that the transaction is successful with the UPI provider |
| payment_source | SIST | Indicates that UPI details have been marked correctly for Standing Instruction |
| mihpayid | <mihpayid number> sent by PayU | Indicates PayU’s transaction acknowledgment for a Consent transaction |
| cardToken | Alphanumeric string | Mandatory to be validated if mode is CC or DC returned in response. Should not be empty |
-
Store Mandate Details:
- Save
mihpayidfor future recurring payments - Store
cardTokenif tokenization is enabled - Save mandate expiry dates from
si_details
- Save
-
Test Recurring Payment:
- Use the stored
mihpayidto initiate a recurring payment - Verify the payment processes successfully
- Use the stored
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
}Updated about 2 hours ago
