PayU Hosted Wallet Checkout Integration
With the PayU Hosted Checkout integration, the entire payment experience is controlled by PayU. The following sections describe how to use the PayU Hosted Integration to collect payments
Customer journey
- Customer will click on Pay on Merchant website and Application
- Merchant will redirect the customer to PayU Checkout using _payment API. Correct Mobile Number has to be passed by the Merchant in the API
Note: Wallet URN can also be passed (Optional).
- Customer is displayed the Closed Loop wallet as the primary option (For first time customer, OTP authentication is required to display balance)
- Basis comparison between transaction amount and balance amount, further journey will be initiated
- Sufficient Balance: This will trigger a one-click payment to debit the customer’s wallet
- Insufficient Balance: This will ask customer to add money (minimum residual amount) on the fly in the wallet and then debit the transaction amount. (For cases where wallet is being used just for cashback posting, configuration to disable load and pay is also there)
- Addition of Money can be done using any of the payment instrument configured on the Merchant (Cards/NB/Wallet). Also, merchant will have the flexibility to restrict the customer for any payment instrument for only loading of the wallet (not allow CC etc)
For more information on PayU Hosted Checkout integration, refer to PayU Hosted Checkout
Transaction Flow
- Initiate Transaction: Send a POST request with all required parameters
- User Redirection: User is redirected to PayU's payment interface for authorization
- User Authorization: User confirms the transaction on the payment page
- Callback: PayU sends the result to either
ws_online_responseorws_failure_response - Verification: Use the response hash to verify the authenticity of the callback
How it is different from Seamless Debit
| Feature | Non-Seamless | Seamless |
|---|---|---|
| User Interaction | Requires redirection and user authorization | No user interaction required |
| Flow | Manual redirection through PayU interface | Direct server-to-server communication |
| Callback URLs | Uses ws_online_response and ws_failure_response | Uses different callback mechanism |
| User Experience | More friction due to redirection | Smoother, no redirection |
| Use Case | Consumer-facing transactions requiring authorization | Backend transactions or auto-debit scenarios |
_payment API Integration
Environment
| Environment | URL |
|---|---|
| Test | https://test.payu.in/_payment |
| Production | https://secure.payu.in/_payment |
HTTP Method: POST
Request Headers
| Parameter | Description |
|---|---|
Content-Typemandatory | String application/x-www-form-urlencoded |
Request Parameters
Body Parameters
The request body is sent as form-encoded parameters.
| Parameter | Description | Example |
|---|---|---|
txnIdmandatory |
String Unique transaction ID generated by the merchant |
RAM1234 |
keymandatory |
String Merchant's identifier key provided by PayU |
KOEfPI |
productinfomandatory |
String Information about the product or service |
iPhone |
customer_idoptional |
Numeric Unique customer ID from merchant's system |
89342546 |
walleturnoptional |
Numeric Wallet reference number (URN) |
70000000008 |
firstNamemandatory |
String Customer's first name |
Ravi |
lastNameoptional |
String Customer's last name |
Kumar |
phonemandatory |
Numeric Customer's mobile number with country code |
919988776655 |
emailmandatory |
String Customer's email address |
[email protected] |
ws_online_responsemandatory |
String Callback URL for successful transactions |
https://merchant.com/success |
ws_failure_responsemandatory |
String Callback URL for failed transactions |
https://merchant.com/failure |
amountmandatory |
Numeric Amount to debit in implied decimals (₹41.00 → 4100) |
4100 |
pgmandatory |
String Payment gateway constant (set to 'CLW') |
CLW |
hashmandatory |
String SHA512 hash for request validation |
6e640b... |
Note: Either
customer_idorwalleturnmust be provided to identify the wallet.
Hash Calculation
The hash is calculated using SHA512 with the following string:
key|txnId|amount|productinfo|firstName|email|||||||||||||{salt}
Response Parameters
| Parameter | Description | Example |
|---|---|---|
| mihpayid | Unique PayU-generated transaction reference number | 1735903830180094 |
| mode | Payment method used | CLW |
| status | Transaction status (success, failure, pending) | success |
| key | Merchant's key (echoed back) | KOEfPI |
| txnid | Transaction ID (echoed back) | RAM1234 |
| amount | Transaction amount | 41.00 |
| net_amount_debit | Net amount debited from the wallet | 41.00 |
| productinfo | Product information (echoed back) | iPhone |
| firstname | Customer's first name | Ravi |
| lastname | Customer's last name | Kumar |
| Customer's email | [email protected] | |
| phone | Customer's phone number | 919988776655 |
| addedon | Transaction date and time | 2025-01-13 18:24:06 |
| hash | Response hash for verification | abc123... |
| PG_TYPE | Payment gateway type | CLW |
| error | Error message (if transaction failed) | Insufficient balance |
| error_Message | Detailed error description | Wallet balance is insufficient |
Sample Request
curl --location --request POST 'https://test.payu.in/_payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=KOEfPI' \
--data-urlencode 'txnid=RAM1234' \
--data-urlencode 'amount=41.00' \
--data-urlencode 'productinfo=iPhone' \
--data-urlencode 'firstname=Ravi' \
--data-urlencode '[email protected]' \
--data-urlencode 'phone=919988776655' \
--data-urlencode 'ws_online_response=https://merchant.com/success' \
--data-urlencode 'ws_failure_response=https://merchant.com/failure' \
--data-urlencode 'pg=CLW' \
--data-urlencode 'walleturn=70000000008' \
--data-urlencode 'hash=6e640b...'import requests
url = "https://test.payu.in/_payment"
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
data = {
'key': 'KOEfPI',
'txnid': 'RAM1234',
'amount': '41.00',
'productinfo': 'iPhone',
'firstname': 'Ravi',
'email': '[email protected]',
'phone': '919988776655',
'ws_online_response': 'https://merchant.com/success',
'ws_failure_response': 'https://merchant.com/failure',
'pg': 'CLW',
'walleturn': '70000000008',
'hash': '6e640b...'
}
response = requests.post(url, headers=headers, data=data)
print(f"Status Code: {response.status_code}")
print(f"Response: {response.text}")using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
string url = "https://test.payu.in/_payment";
using (HttpClient client = new HttpClient())
{
var formParams = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("key", "KOEfPI"),
new KeyValuePair<string, string>("txnid", "RAM1234"),
new KeyValuePair<string, string>("amount", "41.00"),
new KeyValuePair<string, string>("productinfo", "iPhone"),
new KeyValuePair<string, string>("firstname", "Ravi"),
new KeyValuePair<string, string>("email", "[email protected]"),
new KeyValuePair<string, string>("phone", "919988776655"),
new KeyValuePair<string, string>("ws_online_response", "https://merchant.com/success"),
new KeyValuePair<string, string>("ws_failure_response", "https://merchant.com/failure"),
new KeyValuePair<string, string>("pg", "CLW"),
new KeyValuePair<string, string>("walleturn", "70000000008"),
new KeyValuePair<string, string>("hash", "6e640b...")
};
FormUrlEncodedContent content = new FormUrlEncodedContent(formParams);
HttpResponseMessage response = await client.PostAsync(url, content);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {response.StatusCode}");
Console.WriteLine($"Response: {responseBody}");
}
}
}async function makePaymentRequest() {
const url = 'https://test.payu.in/_payment';
const formData = new URLSearchParams();
formData.append('key', 'KOEfPI');
formData.append('txnid', 'RAM1234');
formData.append('amount', '41.00');
formData.append('productinfo', 'iPhone');
formData.append('firstname', 'Ravi');
formData.append('email', '[email protected]');
formData.append('phone', '919988776655');
formData.append('ws_online_response', 'https://merchant.com/success');
formData.append('ws_failure_response', 'https://merchant.com/failure');
formData.append('pg', 'CLW');
formData.append('walleturn', '70000000008');
formData.append('hash', '6e640b...');
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData
});
const responseText = await response.text();
console.log(`Status: ${response.status}`);
console.log(`Response: ${responseText}`);
return responseText;
} catch (error) {
console.error('Error:', error);
throw error;
}
}
// Call the function
makePaymentRequest();import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class PaymentRequest {
public static void main(String[] args) throws IOException, InterruptedException {
String url = "https://test.payu.in/_payment";
Map<String, String> parameters = new HashMap<>();
parameters.put("key", "KOEfPI");
parameters.put("txnid", "RAM1234");
parameters.put("amount", "41.00");
parameters.put("productinfo", "iPhone");
parameters.put("firstname", "Ravi");
parameters.put("email", "[email protected]");
parameters.put("phone", "919988776655");
parameters.put("ws_online_response", "https://merchant.com/success");
parameters.put("ws_failure_response", "https://merchant.com/failure");
parameters.put("pg", "CLW");
parameters.put("walleturn", "70000000008");
parameters.put("hash", "6e640b...");
String form = parameters.entrySet()
.stream()
.map(entry -> URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + "=" +
URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(form))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status Code: " + response.statusCode());
System.out.println("Response: " + response.body());
}
}<?php
$url = 'https://test.payu.in/_payment';
$data = array(
'key' => 'KOEfPI',
'txnid' => 'RAM1234',
'amount' => '41.00',
'productinfo' => 'iPhone',
'firstname' => 'Ravi',
'email' => '[email protected]',
'phone' => '919988776655',
'ws_online_response' => 'https://merchant.com/success',
'ws_failure_response' => 'https://merchant.com/failure',
'pg' => 'CLW',
'walleturn' => '70000000008',
'hash' => '6e640b...'
);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) {
echo "Error occurred while making the request\n";
} else {
echo "Response: " . $result . "\n";
}
// Alternative using cURL
/*
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data),
CURLOPT_HTTPHEADER => array(
'Content-Type: application/x-www-form-urlencoded'
),
));
$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
echo "Status Code: " . $httpCode . "\n";
echo "Response: " . $response . "\n";
*/
?>Sample Response
Successful Transaction
{
"mihpayid": "1735903830180094",
"mode": "CLW",
"status": "success",
"key": "KOEfPI",
"txnid": "RAM1234",
"amount": "41.00",
"net_amount_debit": "41.00",
"productinfo": "iPhone",
"firstname": "Ravi",
"lastname": "Kumar",
"email": "[email protected]",
"phone": "919988776655",
"addedon": "2025-01-13 18:24:06",
"hash": "def456ghi789...",
"PG_TYPE": "CLW"
}Failed Transaction
{
"mihpayid": "1735903830180095",
"mode": "CLW",
"status": "failure",
"key": "KOEfPI",
"txnid": "RAM1235",
"amount": "41.00",
"productinfo": "iPhone",
"firstname": "Ravi",
"lastname": "Kumar",
"email": "[email protected]",
"phone": "919988776655",
"error": "Insufficient balance",
"error_Message": "Wallet balance is insufficient for this transaction",
"hash": "xyz789abc123..."
}Updated 14 days ago
