Initiate UPI Intent payments using the Server-to-Server (S2S) flow. This endpoint returns intentURIData and acsTemplate that you can use to invoke the customer's UPI app directly without redirecting to PayU's hosted page.
Endpoint
HTTP Method: POST
Environment URLs:
| Environment | URL |
|---|---|
| Test | https://test-partnerapilayer.payu.in/apilayer/partner/payments |
| Production | https://api.payu.in/partner/payments |
Request Headers
Authorization: Bearer <FINAL_ACCESS_TOKEN>
Content-Type: application/json
Notes:
You must generate the token using the Reseller Client Credentials Token API before to be posted in header in the above APIs. For more information, refer to Reseller Client Credentials Token API
If you are old partner merchant or reseller, you must a set of APIs to generate the token that must be used in above APIs, so you must use the final access token obtained from [Step 3] Exchange Authorization Code API.
For more information, refer to Token Generation Flow used for Partner Payments.
>
Request Parameters
Mandatory Parameters
| Parameter | Type & Description | Example |
|---|---|---|
txnid | string — Unique transaction ID generated by partner | 28408067218883788 |
amount | string — Transaction amount | 518.02 |
productinfo | string — Product description | Payment for service |
phone | string — Customer phone number (10 digits) | 919820988398 |
merchant_id | integer — PayU merchant ID | 8739528 |
reseller_id | string — Partner/reseller UUID | 11ee-0e7e-5403fde2-9523-0a696b110fde |
txn_s2s_flow | string — Must be "4" for UPI Intent S2S | 4 |
s2s_client_ip | string — Customer IP address (mandatory when txn_s2s_flow=4) | 157.240.22.9 |
s2s_device_info | string — Device user-agent (mandatory when txn_s2s_flow=4) | Mozilla/5.0 (iPhone) AppleWebKit/602.4.6 |
hash | string — SHA-512 hash: merchant_id|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||client_secret | (computed hash value) |
Optional Parameters
| Parameter | Type & Description | Example |
|---|---|---|
firstname | string — Customer first name | John |
lastname | string — Customer last name | Doe |
email | string — Customer email address | [email protected] |
udf1 | string — User-defined field 1 | custom_value_1 |
udf2 | string — User-defined field 2 | 1370625260 |
udf3 | string — User-defined field 3 | r-hway-LDnTRBuFK8STTTeTEc2SuD |
udf4 | string — User-defined field 4 | custom_value_4 |
udf5 | string — User-defined field 5 (often used for partner source channel) |
Hash Generation Formula
Compute SHA-512 hash using this exact formula:
merchant_id|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||client_secret
Hash Generation Example (Java):
import java.security.MessageDigest;
public static String generatePaymentHash(
int merchantId, String txnid, String amount, String productinfo,
String firstname, String email, String udf1, String udf2, String udf3,
String udf4, String udf5, String clientSecret
) throws Exception {
String hashString = merchantId + "|" + txnid + "|" + amount + "|" + productinfo + "|" +
(firstname == null ? "" : firstname) + "|" +
(email == null ? "" : email) + "|" +
(udf1 == null ? "" : udf1) + "|" +
(udf2 == null ? "" : udf2) + "|" +
(udf3 == null ? "" : udf3) + "|" +
(udf4 == null ? "" : udf4) + "|" +
(udf5 == null ? "" : udf5) + "||||||" + clientSecret;
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] digest = md.digest(hashString.getBytes("UTF-8"));
StringBuilder hex = new StringBuilder();
for (byte b : digest) {
String h = Integer.toHexString(0xFF & b);
if (h.length() == 1) hex.append("0");
hex.append(h);
}
return hex.toString();
}Sample Request
curl --location 'https://test-partnerapilayer.payu.in/apilayer/partner/payments' \
--header 'Authorization: Bearer 039e0d1d70f467f946e2d73bd43868df856cfaa352ea54591a76bfc4a08d3487' \
--header 'Content-Type: application/json' \
--data '{
"txnid": "28471834809170981",
"amount": "518.02",
"productinfo": "28471834809170981",
"firstname": "",
"email": "",
"phone": "919820988398",
"merchant_id": 8739528,
"reseller_id": "11ee-0e7e-5403fde2-9523-0a696b110fde",
"udf1": "",
"udf2": "1370625260",
"udf3": "r-hway-LDnTRBuFK8STTTeTEc2SuD",
"udf4": "",
"udf5": "whatsapp",
"txn_s2s_flow": "4",
"s2s_client_ip": "157.240.22.9",
"s2s_device_info": "Mozilla/5.0 (iPhone) AppleWebKit/602.4.6",
"hash": "a3f5e8d2c1b4a6e9f7d3c8b2a1e4d6f9c3a5b7e2d1f4c6a8b3e5d2f7c1a9b4e6"
}'import requests
import hashlib
def generate_upi_intent_payment():
url = "https://test-partnerapilayer.payu.in/apilayer/partner/payments"
# Compute hash
hash_string = "8739528|28471834809170981|518.02|28471834809170981|||||||||||whatsapp||||||YOUR_CLIENT_SECRET"
payment_hash = hashlib.sha512(hash_string.encode('utf-8')).hexdigest()
headers = {
"Authorization": "Bearer 039e0d1d70f467f946e2d73bd43868df856cfaa352ea54591a76bfc4a08d3487",
"Content-Type": "application/json"
}
payload = {
"txnid": "28471834809170981",
"amount": "518.02",
"productinfo": "28471834809170981",
"firstname": "",
"email": "",
"phone": "919820988398",
"merchant_id": 8739528,
"reseller_id": "11ee-0e7e-5403fde2-9523-0a696b110fde",
"udf1": "",
"udf2": "1370625260",
"udf3": "r-hway-LDnTRBuFK8STTTeTEc2SuD",
"udf4": "",
"udf5": "whatsapp",
"txn_s2s_flow": "4",
"s2s_client_ip": "157.240.22.9",
"s2s_device_info": "Mozilla/5.0 (iPhone) AppleWebKit/602.4.6",
"hash": payment_hash
}
response = requests.post(url, headers=headers, json=payload)
return response.json()Sample Response
{
"metaData": {
"message": null,
"referenceId": "7a3060b7462bd2ce6d025c9997220e01",
"statusCode": null,
"txnId": "28471834809170981",
"txnStatus": "pending",
"unmappedStatus": "pending"
},
"result": {
"paymentId": "30478359671",
"merchantName": "HathwayCableAndDatacomLimited",
"merchantVpa": "hathway.payu@indus",
"amount": "518.02",
"intentURIData": "pa=hathway.payu@indus&pn=HATHWAY CABLE AND DATACOM LIMITED&tr=30478359671&tid=PPPL30478359671&am=518.02&cu=INR&tn=UPIIntent",
"acsTemplate": "PGh0bWw+PGhlYWQ+PHRpdGxlPlVQSSBJbnRlbnQ8L3RpdGxlPjwvaGVhZD48Ym9keT4uLi48L2JvZHk+PC9odG1sPg==",
"otpPostUrl": "https://secure.payu.in/ResponseHandler.php"
}
}Response Parameters
metaData Object
| Parameter | Type | Description |
|---|---|---|
message | string | Status message (null if successful) |
referenceId | string | PayU reference ID |
statusCode | string | HTTP status code (null if successful) |
txnId | string | Transaction ID (echoed from request) |
txnStatus | string | Transaction status (pending, success, failure) |
unmappedStatus | string | Internal PayU status |
result Object
| Parameter | Type | Description |
|---|---|---|
paymentId | string | PayU payment ID (use for verification and reconciliation) |
merchantName | string | Merchant display name |
merchantVpa | string | Merchant UPI VPA |
amount | string | Transaction amount |
intentURIData | string | UPI intent string — Use to invoke customer's UPI app |
acsTemplate | string | Base64-encoded HTML template for rendering UPI intent |
otpPostUrl | string | URL for OTP submission (if required) |
Using intentURIData
The intentURIData field contains the UPI intent URL that you can use to invoke the customer's UPI app.
Method 1: Direct Link (Mobile Web)
<a href="upi://pay?pa=hathway.payu@indus&pn=HATHWAY CABLE AND DATACOM LIMITED&tr=30478359671&tid=PPPL30478359671&am=518.02&cu=INR&tn=UPIIntent">
Pay with UPI
</a>Method 2: WhatsApp Integration
# Send UPI intent link via WhatsApp
def send_upi_link_whatsapp(phone, intent_data):
upi_link = f"upi://pay?{intent_data}"
message = f"Complete your payment: {upi_link}"
# Send via WhatsApp Business API
send_whatsapp_message(phone, message)Method 3: QR Code Generation
import qrcode
def generate_upi_qr(intent_data):
upi_string = f"upi://pay?{intent_data}"
qr = qrcode.make(upi_string)
qr.save("payment_qr.png")
return "payment_qr.png"Method 4: Using acsTemplate
Decode the base64 acsTemplate and render it in a webview:
// Decode and render acsTemplate
const decodedHtml = atob(response.result.acsTemplate);
document.getElementById('payment-container').innerHTML = decodedHtml;Error Codes
| HTTP Status | Error Message | Description | Resolution |
|---|---|---|---|
| 400 | Invalid hash | Hash validation failed | Verify hash formula and client_secret |
| 401 | Auth token is not valid | Access token expired or invalid | Regenerate OAuth token |
| 400 | s2s_client_ip or s2s_device_info mandatory | Missing S2S fields when txn_s2s_flow=4 | Include both s2s_client_ip and s2s_device_info |
| 400 | Invalid txn_s2s_flow value | txn_s2s_flow is not "4" | Set txn_s2s_flow to "4" for UPI Intent S2S |
Next Steps
After initiating UPI Intent S2S payment:
- Extract
result.intentURIDatafrom the response - Invoke customer's UPI app using one of the methods above
- Wait for webhook callback from PayU
- Verify payment using POST /partner/verifyPayment
