PayU allows you to collect payments using Unified Payments Interface (UPI). You can integrate UPI via UPI Collect (customer enters their VPA handle and approves a collect request in their UPI app) or UPI Intent / QR (customer taps an intent link to open an installed UPI app on mobile, or scans a dynamic QR code).
For the list of supported UPI providers and handles, refer to UPI Handles.
Recommended prerequisite before initiating payment
When your customer makes a payment through UPI Collect, validate the customer's Virtual Payment Address (VPA) using the validateVpa API before initiating the payment to minimize transaction drops.
For more information, refer to Validate VPA Handle API.
Environment
| Test Environment | https://apitest.payu.in/v2/payments |
| Production Environment | https://api.payu.in/v2/payments |
Request header
| Parameter | Description |
|---|---|
| date | The current date and time. For example, format of the date is Wed, 28 Jun 2023 11:25:19 GMT. |
| authorization | The actual HMAC signature generated using the specified algorithm (sha512) and includes the hashed data. For more information, refer to authorization fields description. |
authorization fields description
| Field | Description |
|---|---|
| username | Represents the username or identifier for the client or merchant, for example smsplus. |
| algorithm | Use SHA512 algorithm for hashing and send this as header value. |
| headers | Specifies which headers have been used in generating the hash, for example date. |
| signature | The HMAC signature generated using the specified algorithm. For more information, refer to hashing algorithm. |
hashing algorithm
You must hash the request parameters using the following hash logic:
Hash logic: sha512(`<Body data>` + '|' + date + '|' + merchant_secret)
Where <Body data> contains the request body posted with the request.
Sample header code
var merchant_key = '<YOUR_TEST_KEY>';
var merchant_secret = 'YOUR_TEST_SALT';
// date
var date = new Date();
date = date.toUTCString();
// authorization
var authorization = getAuthHeader(date);
function getAuthHeader(date) {
var AUTH_TYPE = 'sha512';
var data = isEmpty(request['data']) ? "" : request['data'];
var hash_string = data + '|' + date + '|' + merchant_secret;
var hash = CryptoJS.SHA512(hash_string).toString(CryptoJS.enc.Hex);
return `hmac username="${merchant_key}", algorithm="${AUTH_TYPE}", headers="date", signature="${hash}"`;
}Request body
Mandatory parameters
| Parameter | Description | Example |
|---|---|---|
| accountId | String The merchant key provided by PayU. |
MERCHANT123 |
| txnId | String Unique transaction identifier generated by merchant. Character limit: 50. |
TXN_UPI_20261005 |
| currency | String Currency code. Must be "INR". |
INR |
| paymentMethod | Object Details about UPI payment method:• name: "UPI" • bankCode: "UPI" |
{"name": "UPI", "bankCode": "UPI"} |
| order | Object Order information and amount specification. |
Refer to order section |
| additionalInfo | Object UPI configuration including VPA for collect flow. See additionalInfo object. |
Refer to additionalInfo section |
| callBackActions | Object Callback URLs for redirection. |
Refer to callBackActions section |
| billingDetails | Object Customer contact and address details. |
Refer to billingDetails section |
paymentMethod object
| Parameter | Description | Example |
|---|---|---|
namemandatory |
Payment mode identifier. Set to "UPI". |
UPI |
bankCodemandatory |
Payment instrument code. Set to "UPI". |
UPI |
order object fields description
| Parameter | Description | Example |
|---|---|---|
productInfomandatory | Product details. Type: String | Product details |
orderedItemoptional | Details about the items ordered. Type: Array of Objects | |
userDefinedFieldsoptional | Custom fields for additional information. Type: Object. Fields: udf1, udf2, udf3, udf4, udf5, udf6, udf7, udf8, udf9, udf10. | |
paymentChargeSpecificationmandatory | Includes amount and charges. Type: Object. For more information, refer to paymentChargeSpecification object fields description |
paymentChargeSpecification object fields description
| Parameter | Description | Example |
|---|---|---|
pricemandatory | The transaction amount. Type: Number | 1000 |
netAmountDebitoptional | Net amount to be debited. Type: Number | 1000 |
taxSpecificationoptional | Tax details of the product/order. Type: Object | |
convenienceFeeoptional | Fees format. Type: String | CC:12 |
offersoptional | Offers applied or available for the payment. Type: Object |
userDefinedFields object fields description
| Field | Description |
|---|---|
| udf1 | User defined field. |
| udf2 | User defined field. |
| udf3 | User defined field. |
| udf4 | User defined field. |
| udf5 | User defined field. |
| udf6 | User defined field. |
| udf7 | User defined field. |
| udf8 | User defined field. |
| udf9 | User defined field. |
| udf10 | User defined field. |
additionalInfo object fields description
| Parameter | Description | Example |
|---|---|---|
txnS2sFlowmandatory |
S2S payment flow indicator. Set to "4". |
4 |
vpaconditional |
The customer's Virtual Payment Address (UPI handle). • Mandatory for UPI Collect: PayU sends a collect request to this VPA. • Omit for UPI Intent / QR: PayU will return an intent link / dynamic QR code in the response. |
success@payu |
createOrderoptional |
Flag to store order details in PayU (true / false). |
true |
enforcePaymethodoptional |
Restricts payment mode to UPI. Set to "UPI". |
UPI |
callBackActions object fields description
| Parameter | Description | Example |
|---|---|---|
successActionmandatory |
URL to be called on payment success. | https://example.com/success |
failureActionmandatory |
URL to be called on payment failure. | https://example.com/failure |
cancelActionmandatory |
URL to be called if user cancels the payment. | https://example.com/cancel |
codActionoptional |
URL for Cash on Delivery (COD) action. | https://example.com/cod |
billingDetails object fields description
| Parameter | Description | Example |
|---|---|---|
firstNamemandatory |
First name of the billing contact. | Ashish |
lastNameoptional |
Last name of the billing contact. | Kumar |
address1mandatory |
Primary billing address. | 123 Main Street |
address2optional |
Secondary billing address. | Apt 4B |
phoneoptional |
Phone number of the billing contact. | 9123456789 |
emailmandatory |
Email address of the billing contact. | [email protected] |
cityoptional |
City of the billing address. | Bharatpur |
stateoptional |
State of the billing address. | Rajasthan |
countryoptional |
Country of the billing address. | India |
zipCodeoptional |
Postal/Zip code of the billing address. | 321028 |
Sample request (UPI Collect)
curl -X POST 'https://apitest.payu.in/v2/payments' \
-H 'date: Mon, 05 Oct 2026 10:00:00 GMT' \
-H 'authorization: hmac username="<YOUR_TEST_KEY>", algorithm="sha512", headers="date", signature="<SIGNATURE>"' \
-H 'content-type: application/json' \
-d '{
"accountId": "<YOUR_TEST_KEY>",
"txnId": "TXN_UPI_20261005",
"currency": "INR",
"paymentMethod": {
"name": "UPI",
"bankCode": "UPI"
},
"order": {
"productInfo": "UPI Collect Order",
"paymentChargeSpecification": {
"price": 499.00
},
"userDefinedFields": {
"udf1": "upi_collect_flow"
}
},
"additionalInfo": {
"txnS2sFlow": "4",
"createOrder": true,
"vpa": "success@payu"
},
"callBackActions": {
"successAction": "<redacted URL>",
"failureAction": "<redacted URL>",
"cancelAction": "<redacted URL>"
},
"billingDetails": {
"firstName": "John",
"lastName": "Doe",
"phone": "9876543210",
"email": "[email protected]",
"address1": "123 Main Street",
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"zipCode": "400001"
}
}'import requests
import json
url = "https://apitest.payu.in/v2/payments"
headers = {
"date": "Mon, 05 Oct 2026 10:00:00 GMT",
"authorization": 'hmac username="<YOUR_TEST_KEY>", algorithm="sha512", headers="date", signature="<SIGNATURE>"',
"content-type": "application/json"
}
payload = {
"accountId": "<YOUR_TEST_KEY>",
"txnId": "TXN_UPI_20261005",
"currency": "INR",
"paymentMethod": {
"name": "UPI",
"bankCode": "UPI"
},
"order": {
"productInfo": "UPI Collect Order",
"paymentChargeSpecification": {
"price": 499.00
},
"userDefinedFields": {
"udf1": "upi_collect_flow"
}
},
"additionalInfo": {
"txnS2sFlow": "4",
"createOrder": True,
"vpa": "success@payu"
},
"callBackActions": {
"successAction": "<redacted URL>",
"failureAction": "<redacted URL>",
"cancelAction": "<redacted URL>"
},
"billingDetails": {
"firstName": "John",
"lastName": "Doe",
"phone": "9876543210",
"email": "[email protected]",
"address1": "123 Main Street",
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"zipCode": "400001"
}
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())<?php
$url = "https://apitest.payu.in/v2/payments";
$payload = json_encode([
"accountId" => "<YOUR_TEST_KEY>",
"txnId" => "TXN_UPI_20261005",
"currency" => "INR",
"paymentMethod" => [
"name" => "UPI",
"bankCode" => "UPI"
],
"order" => [
"productInfo" => "UPI Collect Order",
"paymentChargeSpecification" => [
"price" => 499.00
]
],
"additionalInfo" => [
"txnS2sFlow" => "4",
"createOrder" => true,
"vpa" => "success@payu"
],
"callBackActions" => [
"successAction" => "<redacted URL>",
"failureAction" => "<redacted URL>",
"cancelAction" => "<redacted URL>"
],
"billingDetails" => [
"firstName" => "John",
"lastName" => "Doe",
"phone" => "9876543210",
"email" => "[email protected]",
"address1" => "123 Main Street",
"city" => "Mumbai",
"state" => "Maharashtra",
"country" => "India",
"zipCode" => "400001"
]
]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"date: Mon, 05 Oct 2026 10:00:00 GMT",
"authorization: hmac username=\"<YOUR_TEST_KEY>\", algorithm=\"sha512\", headers=\"date\", signature=\"<SIGNATURE>\"",
"content-type: application/json"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class PayUUPIRefRequest {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
String payload = """
{
"accountId": "<YOUR_TEST_KEY>",
"txnId": "TXN_UPI_20261005",
"currency": "INR",
"paymentMethod": {
"name": "UPI",
"bankCode": "UPI"
},
"order": {
"productInfo": "UPI Collect Order",
"paymentChargeSpecification": {
"price": 499.00
}
},
"additionalInfo": {
"txnS2sFlow": "4",
"createOrder": true,
"vpa": "success@payu"
},
"callBackActions": {
"successAction": "<redacted URL>",
"failureAction": "<redacted URL>",
"cancelAction": "<redacted URL>"
},
"billingDetails": {
"firstName": "John",
"lastName": "Doe",
"phone": "9876543210",
"email": "[email protected]",
"address1": "123 Main Street",
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"zipCode": "400001"
}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://apitest.payu.in/v2/payments"))
.header("date", "Mon, 05 Oct 2026 10:00:00 GMT")
.header("authorization", "hmac username=\"<YOUR_TEST_KEY>\", algorithm=\"sha512\", headers=\"date\", signature=\"<SIGNATURE>\"")
.header("content-type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}const url = "https://apitest.payu.in/v2/payments";
const payload = {
accountId: "<YOUR_TEST_KEY>",
txnId: "TXN_UPI_20261005",
currency: "INR",
paymentMethod: {
name: "UPI",
bankCode: "UPI"
},
order: {
productInfo: "UPI Collect Order",
paymentChargeSpecification: {
price: 499.00
}
},
additionalInfo: {
txnS2sFlow: "4",
createOrder: true,
vpa: "success@payu"
},
callBackActions: {
successAction: "<redacted URL>",
failureAction: "<redacted URL>",
cancelAction: "<redacted URL>"
},
billingDetails: {
firstName: "John",
lastName: "Doe",
phone: "9876543210",
email: "[email protected]",
address1: "123 Main Street",
city: "Mumbai",
state: "Maharashtra",
country: "India",
zipCode: "400001"
}
};
fetch(url, {
method: "POST",
headers: {
"date": "Mon, 05 Oct 2026 10:00:00 GMT",
"authorization": 'hmac username="<YOUR_TEST_KEY>", algorithm="sha512", headers="date", signature="<SIGNATURE>"',
"content-type": "application/json"
},
body: JSON.stringify(payload)
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error("Error:", err));Sample response
For UPI Collect, the collect request is dispatched to the customer's UPI mobile app:
{
"status": "PENDING",
"txnId": "TXN_UPI_20261005",
"paymentId": "1999110000001769",
"message": "Collect request sent to customer UPI handle. Poll Verify Payment API or await webhook."
}Response parameters
| Parameter | Description |
|---|---|
| message | This parameter contains the status message of the transaction. |
| status | This parameter returns the status of web service call. The status can be any of the following: `0` - If web service call failed. `1` - If web service call succeeded. |
| result | This parameter contains the payment status details in a JSON format including payment ID of the transaction. For more detailes, refer to the result JSON Object fields description table (next accordion) |
Reference:While awaiting customer approval in their UPI application, poll the Verify Payment API every few seconds or rely on PayU server-to-server webhooks for instant notifications.
Error Codes
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
INVALID_VPA | 400 | Invalid UPI handle format | Validate VPA with validateVpa API before payment |
INVALID_AMOUNT | 400 | Amount invalid | Ensure price is positive number |
INVALID_CURRENCY | 400 | Unsupported currency | Set currency: "INR" |
AUTHENTICATION_FAILED | 401 | Invalid signature | Verify HMAC SHA512 signature |
DUPLICATE_REFERENCE | 409 | txnId already used | Use unique transaction ID |
PAYMENT_DECLINED | 422 | Collect request expired or rejected by user | Ask customer to re-initiate |
Next Steps
- Monitor Real-time Payment Status:
- For UPI Collect: Show a countdown timer (typically 5–8 minutes) on your checkout screen while the customer approves the collect request on their UPI app. Implement polling against your server to check approval.
- For UPI Intent: Launch the requested UPI app using the returned intent URI or display the QR code.
- Consume Webhooks:
- Configure a webhook endpoint on your server to capture PayU's asynchronous notification as soon as the customer authorizes the payment.
- Verify Payment:
- Always call the Verify Payment API using the
txnIdto ensure the payment status issuccessprior to updating customer order records.
- Always call the Verify Payment API using the
