UPI Intent with S2S Integration
The following steps allow you to integrate the server-to-server UPI (United Payments Interface) intent:
Initiate the UPI Intent payment request with required parameters
Trigger the UPI Intent on the customer's mobile device to complete payment
Monitor and verify the UPI transaction status after intent invocation
Receive and process the server-to-server callback response from PayU
Verify the payment status and ensure successful transaction completion
Update the invoice ID associated with the transaction
Upload invoice documents related to the completed transaction
Before you begin:Register for an account with PayU before you start integration. For more information, refer to Register for a Merchant Account.
Important UPI Integration Changes as per NPCI Mandate on UPI Collect Disablement:
For Android Apps: Merchants must implement the Smart Intent implementation. Refer to UPI Smart Intent - Non SDK Flow for non-SDK implementation, or use PayU Android SDKs which have Smart Intent built-in.
For iOS Apps: Merchants can implement the specific deeplink handling and continue using the UPI flow as is. Refer to iOS UPI SDK for SDK-based implementation.
For Web: Use the deeplink returned in the API response to generate a QR code that customers can scan with their UPI app.
For easier integration with built-in Smart Intent support, use PayU SDKs:
Intent Flow Diagram
The following diagram depicts the UPI intent flow from server to server:

Step 1: Initiate payment
Environment
Environment
| Test Environment | https://test.payu.in/_payment |
| Production Environment | https://secure.payu.in/_payment |
The _payment API needs to be called with all the required parameters. For the complete list of parameters, refer to UPI Intent - Non SDK Flow.
This needs to be a server-to-server cURL request. This API is used for both Cards and UPI for generating a new transaction.
If specific intent has to be opened instead of Generic Intent, then the bankcode values will change accordingly:
- For Generic Intent, bankcode = INTENT
Notes:
- If you are using this for their application, then the Generic Intent, and Specific Intent, can be invoked.
- If you are using this for your Mobile Web, then only Generic Intent can be invoked. To invoke App specific intents on the mobile web, the libraries have to be added separately. PayU offers the same for GPay Intent through the Mobile web. Refer to the GPay Seamless Integration Document for the same.
- User VPA is not required for this flow.
Request parameters
For the complete list of parameters, refer to UPI Collection - S2S.
Parameter | Description | Example |
|---|---|---|
key
|
| |
txnid
|
| 1234_abcdedf |
amount
|
| 1000 |
phone
|
| 9876786756 |
productinfo
|
| iPhone 12 |
firstname
|
| Sundar |
email
|
| |
lastname
|
| Teja |
pg | String The payment method is specified in this field. For UPI INTENT, specify the parameter value as UPI. | UPI |
bankcode | String Each payment option is identified with a unique bank code at PayU. For UPI Intent, specify the value as INTENT. | INTENT |
surl | String Success URL(surl) – It must contain the URL on which PayU will redirect the final response if the transaction is successful. | |
furl |
| |
address1
|
| PayU, Bestech Business Tower, Gurgaon |
address2
|
| Sohna Road |
city
|
| Gurgaon |
country
|
| India |
state
| String This parameter must contain the customer state that is part of the address (max 50 characters). | Haryana |
zipcode
|
| 122018 |
udf1
|
| Website order |
udf2
|
| |
udf3
|
| |
udf4 optional |
| |
udf5
|
| |
txn_s2s_flow
|
| 4 |
s2s_client_ip
|
| |
s2s_device_info
|
| |
upiAppName
| For Specific Intent, merchant should share the app name which is selected by customer on the merchant check-out page. The following are the enum's expected for major apps:
| phonepe |
hash
|
|
Hashing Logic
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|tcs_amount
- 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_businesskey|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5|udf6|udf7|udf8|udf9|udf10|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|udf6|udf7|udf8|udf9|udf10|si_details|salt|udf_params|buyer_type_businessFor more information, refer to Generate Hash.
Sample Request
curl --location --request POST 'https://test.payu.in/_payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=JPM7Fg' \
--data-urlencode 'txnid=payuTestTransaction12345' \
--data-urlencode 'amount=100.00' \
--data-urlencode 'firstname=Ashish' \
--data-urlencode '[email protected]' \
--data-urlencode 'phone=9988776655' \
--data-urlencode 'productinfo=Product Info' \
--data-urlencode 'surl=https://test.payu.in/admin/test_response' \
--data-urlencode 'furl=https://test.payu.in/admin/test_response' \
--data-urlencode 'pg=UPI' \
--data-urlencode 'bankcode=INTENT' \
--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 'udf1=AELPR1234E' \
--data-urlencode 'udf3=02-02-1980' \
--data-urlencode 'udf4=XYZ Pvt. Ltd.' \
--data-urlencode 'udf5=INV123456' \
--data-urlencode 'buyer_type_business=1' \
--data-urlencode 'udf_params={"udf7":"0100000029","udf8":"99953729071"}' \
--data-urlencode 'hash=YOUR_CALCULATED_HASH'Response for S2S request
Collect the response in the UPI Collection - S2S. under API Reference. The response for the S2S payment request is not similar to Merchant Hosted or PayU Hosted Checkout. For description of response parameters, refer to Additional Info for Payment APIs.
Using the IntentURIData value in response
The IntentURIData parameter returns the URI in the response. For example, it contains the first debit amount .
Notes:
- Every time there is a change, you need to incorporate the changes to avoid breaking the transactions.
- The tid value which is passed in the intent URI acts as a validation check at NPCI's end which do not allow duplicate transaction.
- The tr value not necessary and it is a payU_id. It can be any reference id for PayU's internal reconciliation.
Step 2: Invoke UPI Intent on customer's device
Request parameters
You need to invoke intent in the customer's mobile device using the merchant VPA URL. Make sure that only this merchant VPA is embedded in the intent call since this helps to track the status of the transaction.
Open the UPI Intent as per the NPCI Guidelines. Merchants can also open any specific app instead of making the Generic Intent call. For example, Google Pay, PhonePe, etc. This URL can then be fired using an Intent or a hyperlink which would open an Intent tray with a list of available supporting apps on the user's mobile device. The following sample UPI Deep Link URL and the format used for creating the URL:
Sample URL (with values from the above sample JSON):
upi://pay?pa=payu@axisbank&pn=SMSPLUS&tr=8312916361&am=10.17Format for UPI Deep Linking URL (as per NPCI guidelines):
"upi://pay?pa=" + merchantVpa + "&pn=" + merchantName + "&tr=" + referenceId + "&am=" + amount Where the description of the parameters used in the URL is as described in the following table:
| Parameter | Description |
|---|---|
| merchantVpa | As received in JSON response in key merchantVPA' |
| merchantName | As received in JSON response in key merchantName. |
| referenceId | As received in JSON response in key referenceId. |
| amount | Amount of transaction. This must be the same as the amount passed to the initiatePayment API. |
Sample request
curl --location 'https://test.payu.in/_payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=PRiQvJ' \
--data-urlencode 'txnid=my_order_991' \
--data-urlencode 'amount=1' \
--data-urlencode 'productinfo=my_order_991' \
--data-urlencode 'email=' \
--data-urlencode 'phone=9368252248' \
--data-urlencode 'txn_s2s_flow=4' \
--data-urlencode 'hash=||||||ABCDE1234F||1990-01-01||INV123456||||||' \
--data-urlencode 'surl=https://test.payu.in/admin/test_response' \
--data-urlencode 'furl=https://test.payu.in/admin/test_response' \
--data-urlencode 'udf1=buyer'\''s DOB' \
--data-urlencode 'udf2=' \
--data-urlencode 'udf3=buyer'\''s PAN' \
--data-urlencode 'udf4=' \
--data-urlencode 'udf5=invoice number' \
--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 'firstname=' \
--data-urlencode 'lastname=kr' \
--data-urlencode 'address1=308,third floor' \
--data-urlencode 'address2=testing' \
--data-urlencode 'city=Gurugram' \
--data-urlencode 'state=UP' \
--data-urlencode 'country=India' \
--data-urlencode 'zipcode=122018' \
--data-urlencode 'pg=UPI' \
--data-urlencode 'bankcode=INTENT' \
--data-urlencode 'upiAppName=gpay/phonepe/paytm/qr/amazonpay' \
--data-urlencode 'udf_params={"udf7":"asdf","udf8":"12"}' \
--data-urlencode 'buyer_type_business=1'Sample respose
If metaData.unmappedStatus = pending, then get the result.intentURIData and add the prefix upi://pay?to make it to create a fully qualified deeplink to trigger the UPI App.
{
"metaData": {
"message": null,
"referenceId": "c99a6455b3e0dc5cd7167ab8c8cc10d2fa153cb509e3f64c6cd0ed9c5b64a8c9",
"statusCode": null,
"txnId": "my_order_26075",
"txnStatus": "pending",
"unmappedStatus": "pending"
},
"result": {
"paymentId": "403993715535965242",
"merchantName": "Sudhanshu",
"merchantVpa": "payutest@hdfcbank",
"amount": "1.00",
"intentURIData": "pa=payutest@hdfcbank&pn=Kumar&tr=403993715535965242&tid=PPPL403993715535965242080126220900&am=1.00&cu=INR&tn=UPIIntent",
"acsTemplate": "PGh0bWw+PGJvZHk+PGZvcm0gbmFtZT0icGF5bWVudF9wb3N0IiBpZD0icGF5bWVudF9wb3N0IiBhY3Rpb249Imh0dHBzOi8vdGVzdC5wYXl1LmluL2M5OWE2NDU1YjNlMGRjNWNkNzE2N2FiOGM4Y2MxMGQyYzgzYTk5NmFhNDhiYTk4MmZjMGQ4MTI1MGY1ODgxZjMvaW50ZW50U2VhbWxlc3NIYW5kbGVyLnBocCIgbWV0aG9kPSJwb3N0Ij48aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJ0b2tlbiIgdmFsdWU9IjhERDNFRUFFLUI5NTktQzY1RS03MDczLTYzQTNGQUUxMjZGRiI+PGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0iYW1vdW50IiB2YWx1ZT0iMS4wMCI+PGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0ibWlocGF5aWQiIHZhbHVlPSJjOTlhNjQ1NWIzZTBkYzVjZDcxNjdhYjhjOGNjMTBkMmZhMTUzY2I1MDllM2Y2NGM2Y2QwZWQ5YzViNjRhOGM5Ij48aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJkaXNhYmxlSW50ZW50U2VhbWxlc3NGYWlsdXJlIiB2YWx1ZT0iMCI+PGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0icGF5ZWVWcGEiIHZhbHVlPSJwYXl1dGVzdEBoZGZjYmFuayI+PGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0icGF5ZWVOYW1lIiB2YWx1ZT0iU3VkaGFuc2h1Ij48aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJhZGRpdGlvbmFsQ2hhcmdlcyIgdmFsdWU9IjAiPjxpbnB1dCB0eXBlPSJoaWRkZW4iIG5hbWU9InRyYW5zYWN0aW9uRmVlIiB2YWx1ZT0iMS4wMCI+PC9mb3JtPjxzY3JpcHQgdHlwZT0ndGV4dC9qYXZhc2NyaXB0Jz4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5vbmxvYWQ9ZnVuY3Rpb24oKXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5mb3Jtc1sncGF5bWVudF9wb3N0J10uc3VibWl0KCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIDwvc2NyaXB0PjwvYm9keT48L2h0bWw+",
"otpPostUrl": "https://test.payu.in/ResponseHandler.php"
}
}Step 3: Check UPI transaction status
Check the UPI transaction status using the Verify Payment API (verify_payment) API. For more information, refer to Verify Payment API.
Step 4: PayU sends Server-to-Server callback response
PayU can also send a server-to-server callback response whenever the transaction status gets updated.
Implementation
The server-to-server response would be sent by PayU on a pre-set URL, which has to be provided by you. PayU will configure it at your back end. This response would be sent in key/value pair separated by the ampersand (&) character. In case any parameter is not used, we would send it back to you with an empty string. The sample response is similar to the following:
unmappedstatus=success&phone=9999999999&txnid=FCDA1R100870163781&hash=84e3 35094bbcb2ddaa0f9a488eb338e143b273765d89c9dfa502402562d0b6f3c7935e28194ca92f7 380be7c84c3695415b106dcf52cb016a15fcf6adc98d724&status=success&curl=https://www. abc.in/payment/handlepayuresposne&firstname=NA&card_no=519619XXXXXX5049&furl= https://www.abc.in/payment/handlepayuresposne&productinfo=2&mode=DC&amount=800. 00&field4=6807112311042810&field3=6807112311042810&field2=838264&field9=SUCC ESS&email=NA&mihpayid=175477248&surl=https://www.ABC.in/payment/handlepayuresp osne&card_hash=9e88cb0573d4a826b61d808c0a870ed4a990682459b0ec9e95ea421e8e47b e8c&field1=42812The parameter list format is similar to the following:
mihpayid,mode,status,key,txnid,amount,productinfo,firstname,lastname,address1,address2,city,state,country,zipcode,email,phone,udf1,udf2,udf3,udf4,udf5,udf6,udf7,udf8,udf9,udf10,card_token,card_no,field0,field1,field2,field3,field4,field5,field6,field7,field8,field9,offer,discou nt,offer_availed,unmappedstatus,hash,bank_ref_no,surl,curl,furl,card_hashStep 5. Verify the payment
Use the webhooks to verify the payment. The following is the sample webhook payload in response. For more information, refer to Webhook Events and Sample Payloads.
Sample Webhook Response
mihpayid=27553369917
&mode=SBQR
&status=success
&key=rZ1fX4
&txnid=T2603041446091822117753
&amount=40.00
&addedon=2026-03-04+14%3A46%3A14
&productinfo=Static+QR
&firstname=
&lastname=
&address1=
&address2=
&city=Gurgaon
&state=
&country=
&zipcode=122001
&email=
&phone=##########
&udf1=
&udf2=
&udf3=
&udf4=SoftQR
&udf5=BFL0000006601446
&udf6=
&udf7=
&udf8=
&udf9=
&udf10=
&card_token=
&card_no=
&field0=STQ9IUFeqlafg78815827
&field1=PRIYA+SHANKAR+PUSNAKE
&field2=995486
&field3=_mobilenum_%40axl
&field4=bajajpay.6879729.d2m9cckd%40indus
&field5=AXLd36cfcd317f243b5b3a2d62bc71caf78
&field6=00000038683323284%7C_mobilenum_%7CSBIN0011418
&field7=APPROVED+OR+COMPLETED+SUCCESSFULLY%7C00
&field8=Payment+from+PhonePe
&field9=Transaction+is+Successful.+Bank+Sent%3ATransaction+success
&payment_source=payu
&cardToken=
&authenticaticationMethod=
&PG_TYPE=SBQR-PG
&error=E000
&error_Message=No+Error
&net_amount_debit=40
&discount=0.00
&offer_key=
&offer_availed=
&unmappedstatus=captured
&hash=aefe0213c4299c7ee2039d5430f7bee63711ee627e1b47d2605d0384abbbf828f3641dae3cb126c8b2f761084cbb0bebad27bb325696cc44ce3061157d7cd9ff
&bank_ref_no=793887773815
&bank_ref_num=793887773815
&bankcode=UPISBQR
&surl=
&curl=
&furl=
&psp_name=CARDHOLDERXXXXXXXXNAMECallback Response Parameters
| Parameter | Description |
|---|---|
| status | Transaction status: success or failure |
| txnid | Your transaction ID |
| mihpayid | PayU transaction ID |
| amount | Transaction amount |
| productinfo | Product information |
| hash | Response hash for verification |
Step 6: Update Invoice ID [Conditional]
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.
Environment
| Test Environment | <https://test.payu.in/merchant/postservice.php?form=2> |
| Production Environment | <https://info.payu.in/merchant/postservice.php?form=2> |
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 or Net Banking
{
"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
}Step 7: Upload the Invoices [Optional]
The invoices / Airway Bill can be uploaded using the Invoice Upload API API. AWB details are mandatory for Goods transactions. Invoice copies can be uploaded optionally.
Environment
| Test Environment | <https://test.payu.in/merchant/postservice.php?form=2> |
| Production Environment | <https://info.payu.in/merchant/postservice.php?form=2> |
Sample request
curl --location -g --request POST '{{baseUrl}}/merchant/postservice?form=2' \
--form 'key="{{merchantKey}}"' \
--form 'command="opgsp_upload_invoice_awb"' \
--form 'var1="403993715525825059"' \ - PayuId
--form 'var2="TestInv0001234568"' \ - invoice Id
--form 'var3="Invoice"' \ - type of upload - Invoice/AWB
--form 'file=@"/path/to/file"' \ - file
--form 'hash="{{hash}}"' Sample response
Success Scenario
- When a file is uploaded successfully:
{
"responseCode":"00",
"responseMsg":"File Uploaded Successfully"
}Failure Scenarios
- When there is an error in uploading the file:
{
"responseCode": "103",
"responseMsg": "Failed to Upload"
} - When the file format is not supported:
{
"responseCode": "105",
"responseMsg": "Not an PACB merchant, contact KAM"
} - When the payuid is invalid:
{
"responseCode":"107",
"responseMsg":"The PayuID in request is invalid"
}- When a mandatory field is missing:
{
"responseCode":"109",
"responseMsg":"All fields are mandatory, please check!"
} Response Code and Description
Updated about 2 hours ago
