Split by Percentage During Transaction Integration
Use this integration when you want to distribute a payment by percentage among multiple merchants at transaction time.
In this mode, set type as percentage and ensure that the total percentage across all split entries is exactly 100.
Prerequisites
Before you start, ensure the following:
- Your parent merchant account is activated for Split Settlements.
- Child merchants have completed onboarding process and are marked Completed/Active .
- You have your parent merchant
keyandsalt, along with the child merchant(s) key. - You have server-side logic to generate hash and process webhooks/You have the
payuIdof the already completed parent transaction.
Steps to integrate:
Construct the splitRequest object with the required parameters to configure a percentage-based split payment
Generate a secure request hash to authenticate and validate the payment request before submission
Submit the constructed payment request along with the percentage split details to the PayU _payment endpoint
Validate the redirect response returned by PayU using a reverse hash to ensure the integrity of the transaction data
Confirm the final payment status and transaction outcome by listening to and processing PayU webhook notifications
Step 1: Build splitRequest for percentage split
Use type: "percentage" and assign percentage values in aggregatorSubAmt.
{
"type": "percentage",
"splitInfo": {
"P41sCY": {
"aggregatorSubTxnId": "subtxn-per-001",
"aggregatorSubAmt": "55.00",
"aggregatorCharges": "5.00"
},
"P41sCK": {
"aggregatorSubTxnId": "subtxn-per-002",
"aggregatorSubAmt": "40.00"
}
}
}Important: Ensure the total split percentage equals
100.00.
Step 2: Generate request hash
Hash pattern with split request:
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||SALT|splitRequest)Example hash input string:
Ax4j7J|txn-per-1001|1000.00|Order #2001|Aman|[email protected]|||||||||||t5atu4TyCvrJDPxAYrmfJfzd90kbXMfL|{"type":"percentage","splitInfo":{"P41sCY":{"aggregatorSubTxnId":"subtxn-per-001","aggregatorSubAmt":"55.00","aggregatorCharges":"5.00"},"P41sCK":{"aggregatorSubTxnId":"subtxn-per-002","aggregatorSubAmt":"40.00"}}}Step 3: Submit payment request to _payment
_paymentUse:
- Test:
https://test.payu.in/_payment - Production:
https://secure.payu.in/_payment
Sample request:
curl -X POST "https://test.payu.in/_payment" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "key=Ax4j7J" \
-d "txnid=txn-per-1001" \
-d "amount=1000.00" \
-d "productinfo=Order #2001" \
-d "firstname=Aman" \
-d "[email protected]" \
-d "phone=9999999999" \
-d "api_version=7" \
-d "surl=https://merchant.example.com/payu/success" \
-d "furl=https://merchant.example.com/payu/failure" \
-d 'splitRequest={"type":"percentage","splitInfo":{"P41sCY":{"aggregatorSubTxnId":"subtxn-per-001","aggregatorSubAmt":"55.00","aggregatorCharges":"5.00"},"P41sCK":{"aggregatorSubTxnId":"subtxn-per-002","aggregatorSubAmt":"40.00"}}}' \
-d "hash=<generated_hash>"Step 4: Validate redirect response using reverse hash
When PayU posts data to your surl or furl, validate reverse hash before finalizing state:
sha512(SALT|status|splitInfo||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key)After payment completion, PayU redirects to your success or failure URL with transaction details:
Response Parameters:
| Parameter | Description |
|---|---|
status | Payment status (success, failure, pending) |
txnid | Transaction ID sent in the request |
amount | Transaction amount |
mihpayid | PayU payment ID |
splitInfo.splitStatus | Status of the split operation |
splitInfo.splitSegments | Array of split details |
Example Response:
{
"status": "success",
"txnid": "payment-txnid-1",
"amount": "10.00",
"mihpayid": "403993715519672950",
"error_code": "E000",
"splitInfo": {
"splitStatus": "success",
"splitSegments": [
{
"merchantKey": "P41sCY",
"amount": 3,
"txnId": "0e7411799c9f0e96620c11"
},
{
"merchantKey": "P41sCK",
"amount": 5,
"txnId": "0e7411799c9f0e96620c22"
}
]
}
}
Step 5: Confirm payment via webhooks
Use webhook notifications as your final payment confirmation mechanism.
- Configure webhook URL in PayU Dashboard.
- Subscribe to relevant payment events.
- Verify webhook signature and ignore duplicate deliveries using idempotency checks.
- Mark order paid only after a successful webhook event.
- Store split metadata from webhook payload for reconciliation and settlement tracking.
Sample webhook payload (illustrative)
{
"event": "payment.success",
"txnid": "txn-per-1001",
"mihpayid": "403993715519672951",
"status": "success",
"amount": "1000.00",
"splitInfo": {
"splitStatus": "success",
"splitSegments": [
{
"merchantKey": "P41sCY",
"amount": 550,
"txnId": "subtxn-per-001"
},
{
"merchantKey": "P41sCK",
"amount": 400,
"txnId": "subtxn-per-002"
}
]
}
}[Optional] Check the Transaction Info
Always verify the transaction info using the Get Aggregator/Parent Transaction Info API to ensure data integrity. For more information, refer to Get Aggregator/Parent Transaction Info API.
Sample request
curl -X POST "https://info.payu.in/merchant/postservice?form=2" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "key=Ax4j7J" \
-d "command=get_aggregator_transactions" \
-d "var1=2024-01-15 10:00" \
-d "var2=2024-01-15 23:59" \
-d "var3=1" \
-d "var4=100" \
-d "var5=1" \
-d "hash=586e3379b3d9f90682329cf7efd27273aeb290936d9edf98686370bc59fdc67b8c0a15c9b6d5c48a24f66a8834b4b75e7e1a9c8d2e3f4a5b6c7d8e9f0a1b2c3d4e5"
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.net.URLEncoder;
public class PayUGetAggregatorTransactionInfo {
public static void main(String[] args) throws Exception {
// API parameters
String key = "Ax4j7J";
String salt = "t5atu4TyCvrJDPxAYrmfJfzd90kbXMfL";
String command = "get_aggregator_transactions";
String startDate = "2024-01-15 10:00"; // var1
String endDate = "2024-01-15 23:59"; // var2
String pageNumber = "1"; // var3
String pageLimit = "100"; // var4
String splitFlag = "1"; // var5 (1 = split created, 0 = split not created)
// Generate hash: sha512(key|command|var1|salt)
String hashString = key + "|" + command + "|" + startDate + "|" + salt;
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] digest = md.digest(hashString.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : digest) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
String hash = hexString.toString();
// Create form parameters
Map<String, String> formParams = new HashMap<>();
formParams.put("key", key);
formParams.put("command", command);
formParams.put("var1", startDate);
formParams.put("var2", endDate);
formParams.put("var3", pageNumber);
formParams.put("var4", pageLimit);
formParams.put("var5", splitFlag);
formParams.put("hash", hash);
// Convert to form-urlencoded format
String formData = formParams.entrySet()
.stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "=" +
URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
// Create HTTP client and request
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://info.payu.in/merchant/postservice?form=2"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
// Send request and get response
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Response Status: " + response.statusCode());
System.out.println("Response Body: " + response.body());
}
}
<?php
// API parameters
$key = "Ax4j7J";
$salt = "t5atu4TyCvrJDPxAYrmfJfzd90kbXMfL";
$command = "get_aggregator_transactions";
$startDate = "2024-01-15 10:00"; // var1
$endDate = "2024-01-15 23:59"; // var2
$pageNumber = "1"; // var3
$pageLimit = "100"; // var4
$splitFlag = "1"; // var5 (1 = split created, 0 = split not created)
// Generate hash: sha512(key|command|var1|salt)
$hashString = "{$key}|{$command}|{$startDate}|{$salt}";
$hash = hash("sha512", $hashString);
// Create form data
$postData = [
'key' => $key,
'command' => $command,
'var1' => $startDate,
'var2' => $endDate,
'var3' => $pageNumber,
'var4' => $pageLimit,
'var5' => $splitFlag,
'hash' => $hash
];
// Initialize cURL session
$ch = curl_init("https://info.payu.in/merchant/postservice?form=2");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/x-www-form-urlencoded'
]);
// Execute request and get response
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// Parse and display response
echo "HTTP Status Code: " . $httpCode . "\n";
echo "Response: " . $response . "\n";
// Parse JSON response
$responseData = json_decode($response, true);
if ($responseData && $responseData['status'] == 1) {
echo "Transaction fetch successful!\n";
echo "Total transactions: " . count($responseData['Transaction_details']) . "\n";
} else {
echo "Error: " . ($responseData['msg'] ?? 'Unknown error') . "\n";
}
?>
const crypto = require('crypto');
const axios = require('axios');
const querystring = require('querystring');
// API parameters
const key = "Ax4j7J";
const salt = "t5atu4TyCvrJDPxAYrmfJfzd90kbXMfL";
const command = "get_aggregator_transactions";
const startDate = "2024-01-15 10:00"; // var1
const endDate = "2024-01-15 23:59"; // var2
const pageNumber = "1"; // var3
const pageLimit = "100"; // var4
const splitFlag = "1"; // var5 (1 = split created, 0 = split not created)
// Generate hash: sha512(key|command|var1|salt)
const hashString = `${key}|${command}|${startDate}|${salt}`;
const hash = crypto.createHash('sha512').update(hashString).digest('hex');
// Create form data
const formData = {
key,
command,
var1: startDate,
var2: endDate,
var3: pageNumber,
var4: pageLimit,
var5: splitFlag,
hash
};
// Make the API request
async function getAggregatorTransactionInfo() {
try {
const response = await axios.post(
'https://info.payu.in/merchant/postservice?form=2',
querystring.stringify(formData),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
console.log('Status Code:', response.status);
console.log('Response:', JSON.stringify(response.data, null, 2));
if (response.data.status === 1) {
console.log('Transaction fetch successful!');
console.log('Total transactions:', response.data.Transaction_details.length);
// Display transaction details
response.data.Transaction_details.forEach((transaction, index) => {
console.log(`\nTransaction ${index + 1}:`);
console.log(` ID: ${transaction.id}`);
console.log(` Status: ${transaction.status}`);
console.log(` Amount: ${transaction.amount}`);
console.log(` TxnID: ${transaction.txnid}`);
console.log(` Is Parent: ${transaction.is_parent_transaction}`);
if (transaction.splitInfo && transaction.splitInfo.length > 0) {
console.log(` Split Info:`);
transaction.splitInfo.forEach((split, splitIndex) => {
console.log(` Split ${splitIndex + 1}: ${split.amount} to ${split.key}`);
});
}
});
} else {
console.log('Error:', response.data.msg);
}
return response.data;
} catch (error) {
console.error('Error making request:', error.message);
if (error.response) {
console.error('Response status:', error.response.status);
console.error('Response data:', error.response.data);
}
throw error;
}
}
// Execute the request
getAggregatorTransactionInfo()
.then(data => console.log('API call successful'))
.catch(err => console.error('API call failed'));
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
class PayUGetAggregatorTransactionInfo
{
static async Task Main(string[] args)
{
// API parameters
string key = "Ax4j7J";
string salt = "t5atu4TyCvrJDPxAYrmfJfzd90kbXMfL";
string command = "get_aggregator_transactions";
string startDate = "2024-01-15 10:00"; // var1
string endDate = "2024-01-15 23:59"; // var2
string pageNumber = "1"; // var3
string pageLimit = "100"; // var4
string splitFlag = "1"; // var5 (1 = split created, 0 = split not created)
// Generate hash: sha512(key|command|var1|salt)
string hashString = $"{key}|{command}|{startDate}|{salt}";
string hash = ComputeSHA512Hash(hashString);
// Create form data
var formData = new Dictionary<string, string>
{
["key"] = key,
["command"] = command,
["var1"] = startDate,
["var2"] = endDate,
["var3"] = pageNumber,
["var4"] = pageLimit,
["var5"] = splitFlag,
["hash"] = hash
};
await SendRequest(formData);
}
static string ComputeSHA512Hash(string input)
{
using (SHA512 sha512 = SHA512.Create())
{
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
byte[] hashBytes = sha512.ComputeHash(inputBytes);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("x2"));
}
return sb.ToString();
}
}
static async Task SendRequest(Dictionary<string, string> formData)
{
try
{
using (HttpClient client = new HttpClient())
{
var content = new FormUrlEncodedContent(formData);
HttpResponseMessage response = await client.PostAsync(
"https://info.payu.in/merchant/postservice?form=2",
content
);
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {response.StatusCode}");
Console.WriteLine($"Response: {responseContent}");
// Parse JSON response
try
{
var jsonDoc = JsonDocument.Parse(responseContent);
var root = jsonDoc.RootElement;
if (root.TryGetProperty("status", out var status) && status.GetInt32() == 1)
{
Console.WriteLine("Transaction fetch successful!");
if (root.TryGetProperty("Transaction_details", out var transactions))
{
Console.WriteLine($"Total transactions: {transactions.GetArrayLength()}");
}
}
else
{
if (root.TryGetProperty("msg", out var msg))
{
Console.WriteLine($"Error: {msg.GetString()}");
}
}
}
catch (JsonException ex)
{
Console.WriteLine($"JSON parsing error: {ex.Message}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
Sample response
{
"status": 1,
"msg": "Transaction Fetched Successfully",
"Transaction_details": [
{
"id": "412345678912384148",
"status": "captured",
"key": "Ax4j7J",
"merchantname": "Aggregator-Parent",
"txnid": "payment-txnid-1",
"base_id": null,
"firstname": "Payu-Admin",
"lastname": "",
"addedon": "2024-01-15 10:11:08",
"bank_name": "Credit Cards",
"payment_gateway": "AxisCYBER",
"phone": "1234567890",
"email": "[email protected]",
"transaction_fee": "10.00",
"amount": "10.00",
"discount": "0.00",
"additional_charges": "0.00",
"productinfo": "Product Info",
"error_code": "E000",
"bank_ref_no": "5192296867061049177385",
"ibibo_code": "CC",
"mode": "CC",
"is_parent_transaction": true,
"splitInfo": [
{
"id": "412345678912384152",
"status": "captured",
"merchantId": "39032915",
"key": "P41sCY",
"txnid": "0e7411799c9f0e96620c11",
"transaction_fee": "3.00",
"amount": "3.00",
"aggregatorCharges": "2.00"
},
{
"id": "412345678912384153",
"status": "captured",
"merchantId": "39032916",
"key": "P41sCK",
"txnid": "0e7411799c9f0e96620c22",
"transaction_fee": "5.00",
"amount": "5.00"
}
]
}
]
}
Go-live checklist
- Ensure split percentages sum to
100.00. - Use unique
txnidandaggregatorSubTxnIdvalues per attempt. - Validate reverse hash in redirect handler.
- Validate webhook signature and implement idempotent webhook processing.
- Move from test endpoint to production endpoint only after complete UAT.
Updated about 1 hour ago
