Accelerate your integration with instant code generation, visual flow mapping, and debugging.
If you don't have an account, create one. If you already have one, log in.
Sign up for a test/sandbox account or log in to your existing account.
Open PayU Login →After logging in, navigate to the Manage Checkout section in the left sidebar.
Manage Checkout
Inside Manage Checkout, click on the Payment Gateway option to see your integration credentials.
Payment Gateway
You'll see your credentials displayed. Copy the Merchant Key and Salt (v1).
a4vGC2 (sample)eCwWELxi... (sample)Choose a payment integration flow to get started
PayU Hosted Checkout with redirect-based payment flow
Enhanced checkout experience with advanced features
Recurring payments with eNACH and card subscriptions
Third Party Verification for secure transactions
UPI One Time Mandate for recurring payments
Split payments across multiple merchants
International payment transactions with multi-currency support
Payment with bank offers and discounts
Pre-authorization for card payments
Single transaction payment
Recurring payment setup
udf_params parameter: {"udf7":"value", "udf8":"value"}
udf_params parameter: {"udf7":"value", "udf8":"value"}
Total Items: 0
Calculated Amount: ₹0.00
Choose a payment method to integrate via S2S (Server-to-Server)
Intent, QR, Collect — one-time, mandates, subscriptions, cross-border & split
Credit & debit card payments with 3DS authentication and tokenization
Direct bank transfers via online banking for all major banks
Select the UPI product you want to integrate. Each card walks you through the complete flow — from initiation to verification.
Accept single UPI payments via Intent, QR, or Collect. The most common UPI integration.
Pre-authorize a UPI amount, then capture later. Supports single and multi-capture.
Register a UPI mandate for recurring debits. Verify, check status, modify, pre-debit notification and SI execution.
Cancel a pending UPI transaction, initiate refunds for completed payments, and check the status of any action.
Common issues developers face during UPI seamless integration — causes, detection, and step-by-step fixes.
Install the PayU UPI Intent Simulator APK on your Android device to test UPI Intent flows and complete transactions in the sandbox.
Ensure you have the following ready before starting the integration.
Test Payment URL: https://test.payu.in/_payment
Production URL: https://secure.payu.in/_payment
Test Merchant Key: Your test key from PayU Dashboard
Test Merchant Salt: Your test salt v1 from PayU Dashboard
Callback Test URL: https://test.payu.in/admin/test_response
Understanding the complete UPI payment flow between all parties involved.
Customer selects UPI on merchant's checkout page and optionally enters VPA or selects UPI app.
Server computes SHA-512 hash using key|txnid|amount|productinfo|firstname|email|udf1-5||||||salt
Merchant server sends payment request with pg=UPI, bankcode=INTENT, and txn_s2s_flow=4.
PayU responds with a UPI deeplink URL. Merchant generates QR code from this deeplink or redirects to UPI app.
Customer scans QR or opens UPI app, enters PIN and approves the payment.
PayU sends S2S callback to surl/furl. Merchant should also poll verify API for confirmation.
To test UPI Intent or complete UPI transactions in the sandbox environment, install the PayU UPI Simulator app on your Android device.
PayU supports three types of UPI Intent flows for initiating payments. All three use the same _payment API with pg=UPI and txn_s2s_flow=4 — the difference lies in the bankcode and how you handle the response deeplink on the customer's device.
_payment API, bankcode options, deeplink handling & response parameters.Decide between Generic (QR), Specific (target app), or Smart (auto-detect). This determines the bankcode you send.
POST to _payment with pg=UPI, txn_s2s_flow=4, and your chosen bankcode. Use the Initiate Payment form (next step) to test.
PayU returns intentURIData (a upi://pay?... URL) or acsTemplate (base64 HTML). Extract the deeplink URI.
Web: Convert deeplink to QR code. Android: Fire an ACTION_VIEW intent. iOS: Open the URL scheme for the target app.
Poll check_payment while waiting. PayU posts the final result to your surl (success) or furl (failure).
POST to _payment with these key parameters for Generic Intent:
pg=UPI
bankcode=INTENT
txn_s2s_flow=4
s2s_client_ip=10.200.12.12
s2s_device_info=Mozilla/5.0 (Windows NT 10.0; Win64; x64)Use the Initiate Payment form (next step) to test this — select bankcode=INTENT.
If metaData.unmappedStatus = "pending", extract result.intentURIData from the response.
{
"metaData": {
"txnId": "my_order_26075",
"unmappedStatus": "pending"
},
"result": {
"paymentId": "403993715535965242",
"intentURIData": "pa=payutest@hdfcbank&pn=Kumar&tr=...&am=1.00&cu=INR",
"acsTemplate": "PGh0bWw+PGJvZHk+Li4u..."
}
}Add the upi://pay? prefix to intentURIData to create a fully qualified UPI deeplink.
const intentURIData = response.result.intentURIData;
const deeplink = "upi://pay?" + intentURIData;Convert the deeplink into a QR code and display it to the customer.
const QRCode = require('qrcode');
const deeplink = "upi://pay?" + response.result.intentURIData;
const qrDataURL = await QRCode.toDataURL(deeplink);
document.getElementById('qr-img').src = qrDataURL;<script src="https://cdn.jsdelivr.net/npm/qrcode/build/qrcode.min.js"></script>
<canvas id="qr-canvas"></canvas>
<script>
QRCode.toCanvas(document.getElementById('qr-canvas'), deeplink, { width: 280 });
</script>The customer opens any UPI app, scans the QR code, and completes the payment. While waiting, poll the transaction status.
async function pollPaymentStatus(txnId, interval = 5000) {
const poll = setInterval(async () => {
const status = await checkPaymentStatus(txnId);
if (status !== 'pending') {
clearInterval(poll);
handlePaymentResult(status);
}
}, interval);
setTimeout(() => clearInterval(poll), 300000);
}Always call verify_payment to confirm the final transaction status. Configure webhooks for server-to-server notifications.
Query the device for installed UPI apps to display on your checkout page.
fun getUPIApps(context: Context): List<Map<String, String>> {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("upi://pay"))
val activities = context.packageManager
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
return activities.map { info ->
val name = context.packageManager
.getApplicationLabel(info.activityInfo.applicationInfo).toString()
mapOf("appName" to name, "packageName" to info.activityInfo.packageName)
}
}POST to _payment with pg=UPI, txn_s2s_flow=4, and the specific bankcode for the chosen app.
| UPI App | Bank Code | Package Name (Android) |
|---|---|---|
| Google Pay | TEZ | com.google.android.apps.nbu.paisa.user |
| PhonePe | PHONEPE | com.phonepe.app |
| Paytm | PAYTM | net.one97.paytm |
| BHIM | BHIM | in.org.npci.upiapp |
| Amazon Pay | AMAZONPAY | in.amazon.mShop.android.shopping |
| CRED | CRED | com.dreamplug.androidapp |
If metaData.unmappedStatus = "pending", extract result.intentURIData. This is not a complete deeplink — you must add a platform-specific prefix.
Prepend a platform-specific prefix to intentURIData to build the final deeplink.
| Platform | Prefix Format |
|---|---|
| Android (Specific) | intent://pay?{data}#Intent;scheme=upi;package=<pkg>;end |
| iOS — PhonePe | phonepe://upi/pay? + intentURIData |
| iOS — Google Pay | gpay://upi/pay? + intentURIData |
| iOS — Paytm | paytm://upi/pay? + intentURIData |
| iOS — BHIM | bhim://upi/pay? + intentURIData |
| iOS — CRED | credpay://upi/pay? + intentURIData |
fun launchUPIApp(activity: Activity, packageName: String, intentUri: String) {
val intent = Intent(Intent.ACTION_VIEW)
intent.setPackage(packageName)
intent.data = Uri.parse("upi://pay?$intentUri")
activity.startActivityForResult(intent, 101)
}let deeplink = "phonepe://upi/pay?" + intentURIData
if let url = URL(string: deeplink), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}After the customer completes payment, handle the result in onActivityResult.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 101) {
val status = data?.getStringExtra("Status") ?: "unknown"
verifyPayment(txnId) // Always verify regardless of status
}
}Always call verify_payment to confirm the final transaction status. Do not rely solely on the UPI app callback.
Add UPI app package IDs to your AndroidManifest.xml so your app can detect installed UPI apps.
<queries>
<package android:name="com.google.android.apps.nbu.paisa.user"/> <!-- Google Pay -->
<package android:name="com.phonepe.app"/> <!-- PhonePe -->
<package android:name="net.one97.paytm"/> <!-- Paytm -->
<package android:name="in.org.npci.upiapp"/> <!-- BHIM -->
<package android:name="in.amazon.mShop.android.shopping"/> <!-- Amazon Pay -->
<package android:name="com.dreamplug.androidapp"/> <!-- CRED -->
</queries>Query the device for installed UPI apps to display on your checkout page or use the OS app chooser.
fun getUPIApps(context: Context): List<Map<String, String>> {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("upi://pay"))
val activities = context.packageManager
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
return activities.map { info ->
val name = context.packageManager
.getApplicationLabel(info.activityInfo.applicationInfo).toString()
mapOf("appName" to name, "packageName" to info.activityInfo.packageName)
}
}POST to _payment with pg=UPI, bankcode=INTENT, txn_s2s_flow=4. Extract result.intentURIData when unmappedStatus = "pending".
The intentURIData is not a complete deeplink. Prepend a platform-specific prefix:
| Platform | Prefix Format |
|---|---|
| Generic / QR / Web | upi://pay? + intentURIData |
| Android (App Chooser) | intent://pay?{data}#Intent;scheme=upi;end |
| Android (Specific) | intent://pay?{data}#Intent;scheme=upi;package=<pkg>;end |
// "Pay by any UPI App" - no package set, OS shows app chooser
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("upi://pay?$intentUri")
activity.startActivityForResult(intent, 101)After the customer completes payment, handle the result in onActivityResult.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 101) {
val status = data?.getStringExtra("Status") ?: "unknown"
verifyPayment(txnId) // Always verify regardless of status
}
}Always call verify_payment to confirm the transaction status. Do not rely solely on the UPI app callback.
Use the Initiate Payment form (next step) to test Intent flows — select the appropriate bankcode (INTENT, TEZ, PHONEPE, or PAYTM) from the dropdown. All intent types use the same _payment API.
The UPI One-Time Payment API lets you initiate a single UPI payment via PayU's Server-to-Server (S2S) flow. You POST payment details to the _payment endpoint with pg=UPI, and PayU returns a deeplink or redirect for the customer to authorize the payment in their UPI app.
Gather the transaction amount, product info, and customer details (name, email, phone). Generate a unique txnid (max 25 chars).
Compute sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt) on your server. Never expose salt client-side.
Send all parameters including pg=UPI, bankcode (INTENT/TEZ/PHONEPE/PAYTM), and txn_s2s_flow=4 to https://test.payu.in/_payment.
If unmappedStatus=pending with intentURIData, generate a QR code from the deeplink. If acsTemplate is returned, decode the base64 HTML and render it.
Use check_payment API to poll until the transaction moves to success or failure. PayU also sends a callback to your surl/furl.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | String — Merchant key provided by PayU during onboarding | JPg****f |
txnid | Mandatory | String — The transaction ID is a reference number for a specific order generated by the merchant | ypl938459435 |
amount | Mandatory | String — The payment amount for the transaction | 10.00 |
productinfo | Mandatory | String — A brief description of the product | iPhone |
firstname | Mandatory | String — The first name of the customer | Ashish |
lastname | Mandatory | String — The last name of the customer | Kumar |
email | Mandatory | String — The email address of the customer | test@gmail.com |
phone | Mandatory | String — The phone number of the customer | 9876543210 |
zipcode | Mandatory | String — Billing address zip code. Character Limit–20 | 400004 |
surl | Mandatory | String — Success URL; PayU redirects here if the transaction is successful | https://test.payu.in/admin/test_response |
furl | Mandatory | String — Failure URL; PayU redirects here if the transaction fails | https://test.payu.in/admin/test_response |
hash | Mandatory | String — SHA-512 payment hash (auto-computed) | (computed) |
pg | Mandatory (S2S) | String — Defines the payment category. Post UPI | UPI |
bankcode | Mandatory (S2S) | String — Unique bank code for UPI payment option: INTENT (generic/QR), TEZ (Google Pay), PHONEPE, PAYTM, BHIM, AMAZONPAY, CRED | INTENT |
txn_s2s_flow | Conditional | Integer — Parameter to enable S2S flow. Must be 4 for Legacy Decoupled flow (UPI Intent) | 4 |
s2s_client_ip | Mandatory | String — Source IP of the customer. Required for UPI Intent flow | 10.200.12.12 |
s2s_device_info | Mandatory | String — Customer agent's device information. Required for UPI Intent flow | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
vpa | Conditional | String — Customer's VPA handle. Mandatory for UPI Collect flow | customer@upi |
udf1 | Conditional | String — Mandatory if AD bank requests this detail. Must contain Buyer's PAN and DOB: PAN||DOB | AAAPZ1234C||22/08/1972 |
udf2 | Optional | String — User-defined field 2 | |
udf3 | Conditional | String — Mandatory if AD bank requests this detail. Must contain Invoice ID and Merchant Name: InvoiceID||MerchantName | INV-123_1231||MerchantName |
udf4 | Optional | String — User-defined field 4 | |
udf5 | Optional | String — User-defined field 5 | |
address1 | Optional (recommended) | String — Billing address line 1. Helpful for fraud detection and chargebacks | 34 Saikripa-Estate, Tilak Nagar |
address2 | Optional (recommended) | String — Billing address line 2 | |
city | Optional (recommended) | String — Billing city. Recommended for higher approval rate | Mumbai |
state | Optional (recommended) | String — Billing state. Recommended for higher approval rate | Maharashtra |
country | Optional (recommended) | String — Billing country. Recommended for higher approval rate | India |
upiAppName | Optional | String — Name of the UPI app selected by the customer on checkout | gpay/phonepe/paytm/qr/amazonpay |
udf_params | Optional | JSON String — Additional UDF parameters (udf6–udf10) | {"udf7":"asdf","udf8":"12"} |
buyer_type_business | Optional | Binary — Send 1 if the buyer is a business (B2B cross-border). Default is 0. Included in hash if posted | 1 |
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
Example: sha512(a4vGC2|TXN_123|10.00|iPhone|Ashish|test@gmail.com|ABCDE1234F||1990-01-01||INV123456||MerchantName||||||||hKvGJP28d2ZUuCRz5BnDag58QBdCxBli)
Generated from intentURIData in the response. Scan with any UPI app to complete the payment.
UPI Mandate (Standing Instruction / Autopay) allows merchants to register a recurring payment mandate via UPI. The customer approves the mandate once, and subsequent payments can be auto-debited within the approved limits. This uses the _payment endpoint with si=1 and api_version=7.
si_details parameters, verify, modify, pre-debit & SI execution APIs.si_details JSON is included in the hashBuild the si_details JSON with mandatory fields: billingAmount, billingCurrency (INR), billingCycle (ONCE / ADHOC / DAILY / WEEKLY / MONTHLY / YEARLY), billingInterval, paymentStartDate, and paymentEndDate. Optionally include UPI-specific fields: remarks (PSP display text, max 50 chars), billingLimit (ON/BEFORE/AFTER), billingRule (MAX/EXACT), and billingDate (day number).
Set udf1 = PAN||DOB (e.g. ABCDE1234F||1990-01-01) and udf3 = InvoiceID||MerchantName.
Compute sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details_json|salt). The si_details JSON string is appended before the salt.
Send all parameters with si=1, pg=UPI, bankcode=INTENT, txn_s2s_flow=4, and api_version=7.
The customer receives a mandate approval request on their UPI app. Once approved, the mandate becomes active and recurring debits can be triggered.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key — unique identifier for your PayU account | BmTY3G |
txnid | Mandatory | Unique transaction ID generated by the merchant. PayU rejects duplicates. | my_order_29327 |
amount | Mandatory | Payment amount. Auto-debit limit: ₹15,000. With PIN: ₹1,00,000. | 1000.00 |
productinfo | Mandatory | Brief product description (max 100 chars) | MonthlySubscription |
firstname | Mandatory | Customer first name (max 60 chars) | Payu-Admin |
email | Mandatory | Customer email (max 50 chars) | test@example.com |
phone | Mandatory | Customer phone number | 1234567890 |
lastname | Mandatory | Customer last name (max 60 chars) | Verma |
surl | Mandatory | Success URL — redirect after successful transaction | https://test.payu.in/admin/test_response/ |
furl | Mandatory | Failure URL — redirect after failed transaction | https://test.payu.in/admin/test_response |
hash | Mandatory | SHA-512 hash for tamper prevention (api_version=7 formula) | (auto-computed) |
pg | Mandatory | Payment gateway type — must be UPI | UPI |
bankcode | Mandatory | UPI for UPI Collect, INTENT for UPI Intent | INTENT |
si | Mandatory | Must be 1 to enable Standing Instruction / Autopay | 1 |
si_details | Mandatory | JSON with billing cycle details (see si_details breakdown below) | (see below) |
vpa | Conditional | Customer VPA handle. Required when bankcode=UPI (UPI Collect). | customer@upi |
txn_s2s_flow | Conditional | Must be 4 for UPI Intent flow | 4 |
api_version | Optional | API version. Pass 7 so si_details is included in hash. | 7 |
address1 | Optional | Billing address line 1 (max 100 chars) | H.No-17, Block C |
address2 | Optional | Billing address line 2 (max 100 chars) | 34 Saikripa-Estate |
city | Optional | Customer city | Mumbai |
state | Optional | Customer state | Maharashtra |
country | Optional | Customer country (max 50 chars) | India |
zipcode | Optional | Billing zipcode (max 20 chars) | 400004 |
free_trial | Optional | Enable free trial. When set to 1, PayU adjusts the amount to ₹2.00 for UPI regardless of the amount passed. | 1 |
udf1 | Conditional | PAN||Date of Birth — Mandatory if AD bank requests this detail | ABCDE1234F||1990-01-01 |
udf3 | Conditional | Invoice ID||Merchant Name — Mandatory if AD bank requests this detail | INV123456||MerchantName |
| Field | Required | Description | Example |
|---|---|---|---|
billingAmount | Mandatory | Maximum amount for recurring debit. For UPI, must not exceed INR 15,000. | 1000.00 |
billingCurrency | Mandatory | Currency — must be INR | INR |
billingCycle | Mandatory | Defines the billing frequency: DAILY, WEEKLY, MONTHLY, YEARLY, ONCE, or ADHOC | MONTHLY |
billingInterval | Mandatory | Coupled with billingCycle. e.g. billingCycle=MONTHLY & billingInterval=3 means charge every 3 months (quarterly). | 1 |
paymentStartDate | Mandatory | Start date in YYYY-MM-DD. For UPI, send the current date (other values are ignored). | 2026-04-10 |
paymentEndDate | Mandatory | End date in YYYY-MM-DD. Number of payment iterations is calculated from start & end dates. | 2027-04-10 |
remarks | Optional (UPI only) | Remarks shown on PSP app during mandate registration. Max 50 characters. | Subscription for a year |
billingLimit | Optional (UPI only) | Period relative to mandate date for debit: ON (specific date), BEFORE (before & on), AFTER (after & on, default). | ON=2026-04-20 |
billingRule | Optional (UPI only) | Limitation on recurring debit amount: MAX (debit up to amount, default) or EXACT (exact amount only). | MAX=1000 |
billingDate | Optional (UPI only) | Day on which recurring debit should happen. For WEEKLY: 1=Mon…7=Sun. For MONTHLY: 1–31. | 1 |
| Cycle | Description | Example (billingInterval) |
|---|---|---|
ONCE | One-time — for split/partial payment use cases | 1 |
DAILY | Daily billing — every N days | 3 (every 3 days) |
WEEKLY | Weekly billing — every N weeks | 1 (every week) |
MONTHLY | Monthly billing — every N months | 1 (every month) |
YEARLY | Yearly billing — every N years | 1 (every year) |
ADHOC | No definite cycle — for post-paid bills where cycle/amount varies | 1 |
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details_json|salt)
Example: sha512(a4vGC2|MAND_123|2.00|MonthlySubscription|sudhanshu|test@test.com|ABCDE1234F||1990-01-01||INV123456||MerchantName|||||||||{"billingAmount":"200.00","billingCurrency":"INR","billingCycle":"MONTHLY","billingInterval":1,"paymentStartDate":"2025-12-24","paymentEndDate":"2026-12-01"}|YourSalt)
In the PayU Test Environment, the mandate registration amount determines the simulated outcome. Use these ranges to test different scenarios.
test.payu.in
UPI Autopay (Standing Instruction) mandate registration requires the amount to be greater than ₹2 INR. Requests with amount ≤ ₹2 will fail. The default sample amount is set to ₹1,000.
The recurring transaction amount (si_transaction) cannot be greater than the billing amount (billingAmount) set during mandate registration. If the transaction amount exceeds the billing amount, the debit will be rejected by the UPI switch.
unmappedStatus = pending → Customer approves via UPI
After registering a UPI mandate, use the verify_payment command to check the transaction status and get the mihpayid (authPayuId). This ID is required for all subsequent mandate operations: status check, modification, pre-debit notification, and recurring payment execution.
Use the same transaction ID (txnid) that was used during mandate registration.
Compute sha512(key|command|var1|salt) where command is verify_payment and var1 is the txnid.
Send key, command (verify_payment), var1 (txnid), and hash.
The mihpayid in the response is the authPayuId needed for mandate status, modify, pre-debit, and SI transaction.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Yes | Merchant key from PayU dashboard | a4vGC2 |
command | Yes | API command | verify_payment |
var1 | Yes | Transaction ID (txnid) from mandate registration | txn-4039971553710 |
hash | Yes | SHA-512 hash | (computed) |
sha512(key|command|var1|salt)
sha512(merchantKey|verify_payment|txnid|merchantSalt)
mihpayid from the verify response is the authPayuId you need for all subsequent steps: Mandate Status, Modify Mandate, Pre-Debit Notification, and SI Transaction.
After registering a UPI mandate, use the upi_mandate_status command to check the current status of the mandate. This API returns the mandate's approval status, active/inactive state, and other details. It uses POST to postservice.php with SHA-512 hash authentication.
From your mandate registration response, get the mihpayid (this is your authPayuId).
Create a JSON object with authPayuId and a unique requestId.
Compute sha512(key|command|var1|salt) where command is upi_mandate_status.
Send key, command, var1 (JSON string), and hash to the postservice endpoint.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Yes | Merchant key from PayU dashboard | a4vGC2 |
command | Yes | API command | upi_mandate_status |
var1 | Yes | JSON with authPayuId and requestId | {"authPayuId":"...","requestId":"..."} |
hash | Yes | SHA-512 hash | (computed) |
{
"authPayuId": "403993715535364356",
"requestId": "1892432asds15g6"
}
sha512(key|command|var1|salt)
sha512(merchantKey|upi_mandate_status|{"authPayuId":"...","requestId":"..."}|merchantSalt)
Use the upi_mandate_modify command to modify an existing UPI mandate. You can update the billing amount and/or the end date of the mandate. The customer will receive a modification request on their UPI app which they must approve. This uses POST to postservice.php with SHA-512 hash authentication.
Use the mihpayid from your mandate registration or verify payment response.
Create a JSON object with authPayuId, requestId, and the fields to modify: amount and/or endDate.
Compute sha512(key|command|var1|salt) where command is upi_mandate_modify.
Send key, command, var1 (JSON string), and hash. The customer will receive a modification approval request on their UPI app.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Yes | Merchant key from PayU dashboard | a4vGC2 |
command | Yes | API command | upi_mandate_modify |
var1 | Yes | JSON with modify details | {"authPayuId":"...","requestId":"...","amount":"...","endDate":"..."} |
hash | Yes | SHA-512 hash | (computed) |
{
"authPayuId": "403993715535437921",
"requestId": "403993715921",
"amount": "3500",
"endDate": "2028-11-15"
}
sha512(key|command|var1|salt)
sha512(merchantKey|upi_mandate_modify|{"authPayuId":"...","requestId":"...","amount":"...","endDate":"..."}|merchantSalt)
UPI One Time Mandate (OTM) allows pre-authorization of a payment. The amount is blocked in the customer's account and can be captured (fully or partially) later. This uses the _payment endpoint with pre_authorize=1 and api_version=7. Supports both Normal Capture (single capture) and Multi Capture (multiple partial captures).
si_details JSON is included in the hashmultiCapture: "Y"Decide between Normal Capture (single full/partial capture) or Multi Capture (multiple partial captures). For multi capture, include "multiCapture": "Y" in si_details.
Build the JSON with paymentStartDate and paymentEndDate. Add "multiCapture": "Y" if using multi capture mode.
Compute sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details_json|salt). The si_details JSON string is appended before the salt.
Send all parameters with pre_authorize=1, pg=UPI, bankcode=INTENT, txn_s2s_flow=4, api_version=7, plus s2s_client_ip and s2s_device_info.
Once the customer authorizes, the amount is blocked. Use capture_transaction API to capture the full or partial amount within the validity window.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | Merchant salt for hash generation (never sent in request) | mGHSxpD2iB… |
txnid | Mandatory | Unique transaction/order ID (auto-generated if empty) | OTM_17345678 |
amount | Mandatory | Block amount for the pre-authorization | 18000 |
productinfo | Mandatory | Brief product description | iPhone |
firstname | Mandatory | Customer's first name | Payu-Admin |
email | Mandatory | Customer's email address | test@example.com |
phone | Mandatory | Customer's phone number | 9876543210 |
surl | Mandatory | Success redirect URL | https://test.payu.in/admin/test_response |
furl | Mandatory | Failure redirect URL | https://test.payu.in/admin/test_response |
pg | Mandatory | Payment gateway category — fixed UPI | UPI |
bankcode | Mandatory | Bank code for UPI Intent — fixed INTENT | INTENT |
txn_s2s_flow | Mandatory | S2S flow type — fixed 4 for UPI Intent | 4 |
pre_authorize | Mandatory | Enable pre-authorization — fixed 1 | 1 |
api_version | Mandatory | API version — fixed 7 (includes si_details in hash) | 7 |
si_details | Mandatory | JSON with paymentStartDate, paymentEndDate, and optionally multiCapture: "Y" | {"paymentStartDate":"2026-03-28","paymentEndDate":"2026-05-27"} |
hash | Mandatory | SHA-512 hash (auto-computed) | (computed) |
s2s_client_ip | Mandatory | Source IP of the customer — required for UPI Intent flow | 10.200.12.12 |
s2s_device_info | Mandatory | Customer's device user agent — required for UPI Intent flow | Mozilla/5.0 |
lastname | Optional | Customer's last name | Kumar |
udf1 | Optional | User-defined field 1 (included in hash) | udf1 |
udf2 | Optional | User-defined field 2 (included in hash) | udf2 |
udf3 | Optional | User-defined field 3 (included in hash) | udf3 |
udf4 | Optional | User-defined field 4 (included in hash) | udf4 |
udf5 | Optional | User-defined field 5 (included in hash) | udf5 |
| Feature | Normal Capture | Multi Capture |
|---|---|---|
| Captures allowed | 1 (full or partial) | Multiple partial captures |
multiCapture in si_details | Not required | "Y" |
| Cancel remaining | Yes (cancel_transaction) | Yes (cancel_transaction) |
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details_json|salt)
sha512(a4vGC2|OTM_123|18000|iPhone|Payu-Admin|test@example.com|udf1|udf2|udf3|udf4|udf5||||||{"paymentStartDate":"2026-03-28","paymentEndDate":"2026-05-27"}|hKvGJP28d2ZUuCRz5BnDag58QBdCxBli)
In the PayU Test Environment, the amount you send determines the simulated transaction outcome. Use these ranges to test different scenarios.
test.payu.in
UPI OTM (One-Time Mandate) supports a maximum pre-authorization amount of ₹5,00,000 (5 Lakh) in production. In the test environment, use amount > ₹5,000 for a successful flow.
capture_transaction succeeds
E000
capture_transaction & verify_payment = in progress
After a successful pre-authorized (OTM) transaction, use the capture_transaction command to capture (debit) the blocked amount. You can capture the full amount or a partial amount. This API is called via postservice.php with a SHA-512 hash for authentication.
verify_payment to retrieve the mihpayid for the auth transactionUse the UPI OTM flow to create a pre-authorized transaction. The amount will be blocked in the customer's account.
Call verify_payment with the transaction ID to retrieve the mihpayid (PayU's internal transaction reference).
Compute sha512(key|command|var1|salt) where command=capture_transaction and var1=mihpayid.
Send key, command, var1 (mihpayid), var2 (unique capture order ID), var3 (capture amount), and hash to postservice.php.
Call verify_payment again to confirm the capture was successful and the amount has been debited.
sha512(key|command|var1|salt)
sha512(merchantKey|capture_transaction|mihpayid|merchantSalt)
Callback URLs can be spoofed. Always verify the payment status with PayU's server using the verify_payment command before fulfilling the order. This API is the single source of truth for payment status and is called via postservice.php.
Use the txnid you sent when creating the payment. This is your merchant-side unique reference.
Compute sha512(key|command|var1|salt) where command=verify_payment and var1=txnid.
Send key, command, var1 (txnid), and hash to postservice.php.
Extract mihpayid, status, mode, and payment_source from the response to determine payment outcome.
Based on the verified status, fulfill the order (if success) or show an error (if failure/pending).
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | Merchant salt used for hash generation (never sent in request) | mGHSxpD2iB… |
command | Mandatory | API command — fixed verify_payment | verify_payment |
var1 | Mandatory | Transaction ID (txnid) used during payment initiation | TXN_1234567890 |
hash | Mandatory | SHA-512 hash (auto-computed from key, command, var1, salt) | (computed) |
sha512(key|command|var1|salt)
sha512(a4vGC2|verify_payment|TXN_1234567890|hKvGJP28d2ZUuCRz5BnDag58QBdCxBli)
Use cancel_refund_transaction to cancel or refund a UPI One-Time Payment. Called via postservice.php with SHA-512 hash authentication.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | Merchant salt for hash generation (never sent in request) | mGHSxpD2iB… |
command | Mandatory | API command — fixed cancel_refund_transaction | cancel_refund_transaction |
var1 (mihpayid) | Mandatory | PayU transaction ID from Verify Payment response | 403993715537142566 |
var2 (token id) | Mandatory | Unique cancel/refund token ID (auto-generated if empty) | cnl_12345 |
var3 (amount) | Mandatory | Amount to cancel/refund | 2.00 |
hash | Mandatory | SHA-512 hash (auto-computed) | (computed) |
sha512(key|cancel_refund_transaction|mihpayid|salt)
sha512(a4vGC2|cancel_refund_transaction|403993715537142566|hKvGJP28d2ZUuCRz5BnDag58QBdCxBli)
Use check_action_status to track the status of a cancel/refund request. After initiating a cancel or refund via cancel_refund_transaction, this API lets you check whether the refund has been processed, is pending, or has failed. Called via postservice.php with SHA-512 hash authentication.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | Merchant salt for hash generation (never sent in request) | mGHSxpD2iB… |
command | Mandatory | API command — fixed check_action_status | check_action_status |
var1 | Mandatory | PayU ID (mihpayid) for which action status is to be fetched | 139210626 |
hash | Mandatory | SHA-512 hash (auto-computed from key, command, var1, salt) | (computed) |
sha512(key|command|var1|salt)
sha512(a4vGC2|check_action_status|139210626|hKvGJP28d2ZUuCRz5BnDag58QBdCxBli)
Cancel a pre-authorized (OTM) transaction using cancel_transaction to release the blocked amount back to the customer. Called via postservice.php with SHA-512 hash authentication.
verify_payment to retrieve the mihpayid for the auth transactioncancel_transaction — releases the blocked amountUse verify_payment to get the mihpayid of the auth transaction you want to cancel or refund.
Use cancel_transaction to release the blocked amount. The command is the same for both Normal and Multi Capture.
Compute sha512(key|command|var1|salt) where var1=mihpayid.
Send the request to postservice.php with all required parameters including a unique cancel token ID.
Use check_action_status with the request_id to track the refund progress.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Yes | Merchant key from PayU dashboard | a4vGC2 |
command | Yes | Fixed cancel_transaction | cancel_transaction |
var1 | Yes | mihpayid of auth transaction | 403993715536064861 |
var2 | Yes | Unique cancel token ID | cancel_txn_12345 |
hash | Yes | SHA-512 hash | (computed) |
sha512(key|cancel_transaction|var1|salt)
sha512(merchantKey|cancel_transaction|mihpayid|merchantSalt)
curl -X POST "https://test.payu.in/merchant/postservice.php?form=2" \
--data-urlencode "key={{merchantKey}}" \
--data-urlencode "command=check_action_status" \
--data-urlencode "var1={{request_id}}" \
--data-urlencode "hash={{hash}}"
This API checks the status of a UPI OTM (One Time Mandate) transaction. Unlike other PayU APIs, it uses HMAC-SHA256 signature-based authentication (not the standard SHA-512 hash). It is a GET request to the PayU API endpoint. The proxy handles HMAC header generation server-side, so you only need to provide key, salt, and payuId.
verify_paymentUse verify_payment or extract from the auth response to get the PayU transaction ID (mihpayid/payuId).
The proxy handles this server-side. Headers include: Date (UTC), Digest (SHA-256 of empty body, base64), and Authorization (HMAC signature).
Call https://apitest.payu.in/v1/transaction/upi_otm_status_check?payuId={{payuid}} with the HMAC headers.
The response contains the mandate/OTM status, amount, validity, and transaction details.
| Property | Required | Description | Example |
|---|---|---|---|
Method | — | HTTP method | GET |
URL | — | API endpoint | https://apitest.payu.in/v1/transaction/upi_otm_status_check?payuId={{payuid}} |
Auth | — | Authentication type | HMAC-SHA256 signature |
Date | Yes | UTC date header | Tue, 23 Sep 2025 06:58:08 GMT |
Digest | Yes | SHA-256 of request body (empty for GET), base64 | 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= |
Authorization | Yes | HMAC signature header | hmac username="key", algorithm="hmac-sha256", ... |
Digest = base64(sha256("")) // empty body for GET
SignatureString = "date: {utcDate}\ndigest: {digest}"
Signature = base64(hmac-sha256(salt, signatureString))
Authorization = 'hmac username="{key}", algorithm="hmac-sha256", headers="date digest", signature="{signature}"'
const crypto = require('crypto');
const merchant_key = "your_merchant_key";
const merchant_secret = "your_merchant_salt";
const requestBody = ""; // empty for GET
const bodyHash = crypto.createHash('sha256').update(requestBody).digest('base64');
const date = new Date().toUTCString();
const signatureString = `date: ${date}\ndigest: ${bodyHash}`;
const signature = crypto.createHmac('sha256', merchant_secret)
.update(signatureString).digest('base64');
const auth = `hmac username="${merchant_key}", algorithm="hmac-sha256", ` +
`headers="date digest", signature="${signature}"`;
// Headers:
// Date: <date>
// Digest: <bodyHash>
// Authorization: <auth>
// Content-Type: application/json
After the UPI OTM Transaction is authorized, call verify_payment with the original txnid to confirm the auth status and retrieve the mihpayid needed for capture.
sha512(key|verify_payment|txnid|salt)
After verifying auth, you can either capture the blocked amount or cancel the pre-authorization.
Capture the blocked amount (full or partial) to complete the payment.
Capture → Verify CaptureRelease the blocked amount back to the customer's account.
Cancel → OTM Status CheckAfter calling capture_transaction, verify the capture using the capture_order_id (var2 from the capture request) to confirm the amount was debited successfully.
sha512(key|verify_payment|capture_order_id|salt)
After a successful UPI Mandate Registration (and optionally checking/modifying the mandate), you must send a pre-debit notification using the pre_debit_SI command at least 24 hours before the scheduled debit. This is an NPCI mandate requirement. The API uses POST to postservice.php with SHA-512 hash authentication, where var1 is a JSON string.
Use the mihpayid from the Verify Payment response (auto-filled if you followed the flow).
The debit date must be at least 24 hours in the future. Amount should be within the mandate limits.
Click “Send to PayU” to send the pre_debit_SI command. The customer will be notified of the upcoming debit.
After the pre-debit notification is acknowledged, proceed to execute the actual recurring payment.
NPCI mandates sending a pre-debit notification to the customer at least 24 hours before the scheduled debit.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Yes | Merchant key from PayU dashboard | a4vGC2 |
command | Yes | API command | pre_debit_SI |
var1 | Yes | JSON with pre-debit details: authPayuId, requestId, debitDate (YYYY-MM-DD), amount | {"authPayuId":"...","requestId":"...","debitDate":"...","amount":"..."} |
hash | Yes | SHA-512 hash (var1 is the JSON string) | (computed) |
{
"authPayuId": "403993715534484661",
"requestId": "403993715534484661_1",
"debitDate": "2025-09-06",
"amount": "2.00"
}
sha512(key|command|var1|salt)
sha512(merchantKey|pre_debit_SI|{"authPayuId":"...","requestId":"...","debitDate":"...","amount":"..."}|merchantSalt)
After sending the pre-debit notification, execute the actual recurring payment using the si_transaction command. This API debits the customer’s account based on the registered UPI mandate. It uses POST to postservice.php with SHA-512 hash authentication, where var1 is a JSON string containing transaction details.
Use the mihpayid from the Verify Payment response (auto-filled if you followed the flow).
Enter the recurring amount, a unique transaction ID, and customer details (name, email, address).
Click “Send to PayU” to execute the si_transaction command and debit the customer.
Use verify_payment with the SI txnid to confirm the payment was successful.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Yes | Merchant key from PayU dashboard | a4vGC2 |
command | Yes | API command — fixed si_transaction | si_transaction |
var1 | Yes | JSON object with transaction details (see var1 fields below) | (see below) |
hash | Yes | SHA-512 hash: sha512(key|command|var1|salt) | (computed) |
| Field | Required | Description | Example |
|---|---|---|---|
authpayuid | Yes | Unique authentication payment ID from the registration transaction | 403993715534484661 |
amount | Yes | Monetary value of the recurring transaction | 100.00 |
txnid | Yes | Merchant-generated unique transaction ID | SI_1234567890 |
firstname | Yes | Customer’s first name | Sudhanshu |
email | Yes | Customer’s email for communication and receipts | test@example.com |
phone | Yes | Customer’s contact number (echoed back in response) | 9999999999 |
udf1 | Yes | PAN and DOB separated by ||: PAN||DOB | ABCDE1234F||1990-01-01 |
udf3 | Yes | Invoice ID and seller name separated by ||: invoiceId||sellerName | INV789||SellerName |
lastname | No | Customer’s last name | Kumar |
address1 | No | Customer’s address line 1 | 308 third floor |
address2 | No | Customer’s address line 2 | my lane |
city | No | Customer’s city | Delhi |
state | No | Customer’s state | Delhi |
country | No | Customer’s country | India |
zipcode | No | Customer’s zipcode | 110092 |
invoiceDisplayNumber | No | User-friendly invoice number displayed to the customer | INV-2024-001 |
udf2 | No | Custom user-defined field (echoed back) | |
udf4 | No | Custom user-defined field (echoed back) | |
udf5 | No | Custom user-defined field (echoed back) |
NULL||<VALUE>. If the second value is absent, it will be sent as <VALUE>.
{
"authpayuid": "403993715534484661",
"amount": "100",
"txnid": "Rec_403993715534484661_1",
"firstname": "Sudhanshu",
"lastname": "Kr",
"email": "test@example.com",
"phone": "9999999999",
"address1": "address",
"address2": "my lane",
"city": "my city",
"state": "my state",
"country": "India",
"zipcode": "110092",
"udf1": "ABCDE1234F||1990-01-01",
"udf3": "INV123456||MerchantName",
"invoiceDisplayNumber": "SI_1236"
}
sha512(key|command|var1|salt)
sha512(merchantKey|si_transaction|{"authpayuid":"...","amount":"...","txnid":"...",...}|merchantSalt)
After executing a recurring SI Transaction, use the verify_payment command to confirm the debit status. This verifies whether the customer's account was successfully debited for the recurring payment.
Use the same transaction ID (txnid) that was used in the si_transaction request.
Compute sha512(key|command|var1|salt) where command is verify_payment and var1 is the SI txnid.
Send key, command (verify_payment), var1 (txnid), and hash.
Look for status = success or failure to confirm whether the recurring debit was completed.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Yes | Merchant key from PayU dashboard | a4vGC2 |
command | Yes | API command | verify_payment |
var1 | Yes | Transaction ID (txnid) from SI Transaction | Rec_40399715537_1 |
hash | Yes | SHA-512 hash | (computed) |
sha512(key|command|var1|salt)
sha512(merchantKey|verify_payment|si_txnid|merchantSalt)
Common issues developers face during UPI seamless integration and how to fix them.
Common issues developers encounter during PayU UPI seamless integration. Each issue includes causes, detection methods, and step-by-step fixes.
||||||)PayU returns error message "Hash validation failed" or "Sorry, Some Problem Occurred".
// Print the hash string before hashing to verify:
const hashString = `${key}|${txnid}|${amount}|${productinfo}|${firstname}|${email}|${udf1}|${udf2}|${udf3}|${udf4}|${udf5}||||||${salt}`;
console.log('Hash Input:', hashString); // Verify each component
console.log('Pipe count:', (hashString.match(/\|/g)||[]).length); // Should be 17
username@handle)Payment API returns error with invalid VPA message.
Verify the VPA format is correct (username@handle) before initiating payment. Show user-friendly error if VPA is invalid.
Verify API returns status: "pending" or unmappedstatus: "pending".
expiryTime parameterINTENT) for web to let any UPI app scantxn_s2s_flow=4 in the request4 for UPI Intent S2S)PayU redirects to its payment page instead of returning a deeplink, or returns an error.
Always include txn_s2s_flow=4 in your payment request for UPI Intent S2S flow.
| Error | Meaning | Fix |
|---|---|---|
Hash validation failed |
Incorrect hash | Check salt version, parameter order |
Invalid VPA |
VPA doesn't exist | Verify VPA format before payment |
Transaction pending |
Awaiting customer action | Poll verify_payment API |
txn_s2s_flow missing |
Not in S2S mode | Add txn_s2s_flow=4 |
Invalid amount |
Amount format wrong | Use decimal format (e.g. 10.00) |
Select the card payment product you want to integrate. Each card walks you through the complete flow — from initiation to verification.
Standard server-to-server card payment with 3DS authentication. The most common card integration.
Hold funds first, capture later. Ideal for hotels, rentals, and e-commerce.
Save cards securely, pay with tokens — PayU, Network & Issuer tokens.
ACS template decoder and debugging tools for Cards S2S integration.
You must be PCI DSS compliant before handling raw card data in any seamless S2S card flow. Use the Merchant Config bar above to set your key & salt once.
This flow walks you through every API call needed for a standard server-to-server credit/debit card payment — from BIN validation to final verification.
Prerequisite: You must be PCI DSS compliant (or use a PCI-compliant vault/tokenization solution) before handling raw card data in this seamless cards flow.
3 phases: Pre-Payment (BIN checks + payment hash), Payment (initiate 3DS + optional OTP submission), and Post-Payment (verify final status and reconcile).
Validate BIN capabilities, check domestic/international applicability, and keep the correct SHA-512 payment hash ready for _payment.
Retrieve card BIN details — issuing bank, card type (credit/debit), network (Visa/Mastercard/Rupay), and capabilities (ATM PIN, OTP, Zero Redirect, SI support). Supports three modes: single BIN lookup, feature-based filtering, and bulk retrieval with pagination.
https://test.payu.in/merchant/postservice.php?form=2 | Command: getBinInfosha512(key|command|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | getBinInfo | getBinInfo |
var1 | Mandatory | Request type: 1 = single BIN lookup, 2 = feature-based BIN list, 3 = all BIN information | 1 |
var2 | Conditional | If var1=1: BIN number (e.g. 512345). If var1=2: 1 (ATM PIN support) or 2 (OTP-on-the-fly). If var1=3: leave empty. | 512345 |
var3 | Optional | Start index for pagination (default: 0). Used when var1=2 or var1=3. | 0 |
var4 | Optional | Records per page / offset (default: 100, range: 1–1000). Used when var1=2 or var1=3. | 100 |
var5 | Optional | Set to 1 to get enhanced features: is_zero_redirect_supported, is_si_supported. | 1 |
hash | Mandatory | sha512(key|getBinInfo|var1|salt) | (computed) |
| Use Case | var1 | var2 | var3 | var4 | var5 | Description |
|---|---|---|---|---|---|---|
| Single BIN Query | 1 | 512345 | 0 | 0 | 0 | Get info for a specific BIN |
| Single BIN + Enhanced | 1 | 512345 | 0 | 0 | 1 | Single BIN with zero redirect & SI support |
| ATM PIN Support Cards | 2 | 1 | 1 | 20 | 0 | Get BINs with ATM PIN support |
| OTP Support Cards | 2 | 2 | 1 | 20 | 0 | Get BINs with OTP-on-the-fly support |
| All Cards – Page 1 | 3 | 1 | 20 | 0 | First 20 cards (records 1–20) | |
| All Cards – Page 2 | 3 | 21 | 20 | 0 | Next 20 cards (records 21–40) | |
| All Cards – Page 3 | 3 | 41 | 20 | 0 | Next 20 cards (records 41–60) | |
| Large Batch Query | 3 | 1 | 100 | 0 | Get 100 cards at once | |
| Custom Range | 3 | 501 | 50 | 0 | Cards 501–550 |
| Parameter | Values | Use Case in Normal S2S Flow |
|---|---|---|
issuing_bank | e.g. HDFC, ICICI | Identify the issuing bank for display and routing decisions |
bin | BIN number | The matched BIN (6–9 digits). Use to confirm which BIN PayU resolved |
category | creditcard / debitcard | Determine card type for surcharge rules or payment restrictions |
card_type | VISA, MAST, AMEX, MAES, DINR | Set bankcode parameter in _payment API (e.g. CC for credit, DC for debit) |
is_domestic | 1 = Domestic, 0 = International | Domestic cards can use Native OTP. International cards typically redirect to 3DS. Also used by check_isDomestic step |
is_otp_on_the_fly | 1 = Supported, 0 = Not | Critical: If 1, card supports Native OTP (pureS2S). You can use submit_otp API in Step 5 instead of 3DS redirect. If 0, only Bank Page (3DS Redirect) is available |
is_atmpin_card | 1 / 0 | If 1, card supports ATM PIN authentication as alternative to OTP |
is_zero_redirect_supported | 1 / 0 | If 1, zero redirect (headless) payment is possible. Returned only when var5=1 |
is_si_supported | 1 / 0 | If 1, card supports Standing Instructions (recurring mandates). Returned only when var5=1 |
Determines whether a card BIN is domestic (Indian) or international, along with the issuing bank, card type (credit/debit), and card category. This is an optional pre-payment check — use it when you need to:
getBinInfo API in Step 1 already returns card type and bank information.
https://test.payu.in/merchant/postservice.php?form=2 | Command: check_isDomesticsha512(key|command|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU for authentication | JPg****f |
command | Mandatory | check_isDomestic — fixed value for this API | check_isDomestic |
var1 | Mandatory | First 6 digits of the card number (BIN). Must be exactly 6 digits. | 512345 |
hash | Mandatory | sha512(key|check_isDomestic|var1|salt) | (computed) |
| Field | Example | Description |
|---|---|---|
isDomestic | Y / N | Y = Domestic (Indian) card, N = International card |
issuingBank | HDFC | Name of the card issuing bank |
cardType | VISA | Card network (VISA, Mastercard, Rupay, etc.) |
cardCategory | CC | CC = Credit Card, DC = Debit Card |
Send the card payment request to _payment and handle 3DS via acsTemplate and optional OTP submission.
Before calling the _payment API, you must generate a SHA-512 hash. This hash ensures that no one has tampered with the payment request parameters. It acts as a digital signature between your server and PayU.
_payment API
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
| Field | Description | Example |
|---|---|---|
key | Merchant Key provided by PayU | a4vGC2 |
txnid | Your unique transaction ID | TXN_1234567890 |
amount | Transaction amount | 10.00 |
productinfo | Product description | Test Product |
firstname | Customer first name | Test |
email | Customer email | test@example.com |
udf1–udf5 | User-defined fields — pass empty string if not used | (empty) |
|||||| | Six pipes for empty udf6–udf10 (always required) | |||||| |
salt | Merchant Salt — never expose to client | hKvGJP28d2... |
|||||| (six pipes) between udf5 and salt are for empty udf6–udf10 and are always requiredccnum, ccvv, ccexpmon, ccexpyr, pg, bankcode, surl, furl, txn_s2s_flow — these are sent as separate parameters but are not part of the hash computation.
_payment)
Submit the card payment request with all card details, S2S flow parameters, and the generated hash. The txn_s2s_flow=4 parameter enables the Cards Decoupled (S2S) flow.
https://test.payu.in/_paymentapplication/x-www-form-urlencoded| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | JPg****f |
txnid | Mandatory | Unique transaction ID generated by the merchant. PayU rejects duplicate txnids. | ypl938459435 |
amount | Mandatory | Payment amount for the transaction | 10.00 |
productinfo | Mandatory | Brief description of the product | iPhone |
firstname | Mandatory | Customer first name | Ashish |
email | Mandatory | Customer email address | test@gmail.com |
phone | Mandatory | Customer phone number | 9876543210 |
pg | Mandatory | Payment gateway type. CC for Credit Card, DC for Debit Card | CC |
bankcode | Mandatory | Bank code for the card type (e.g. CC, DC, AMEX) | CC |
ccnum | Mandatory | 13–19 digit card number (15 for AMEX, 13–19 for Maestro). Validated with LUHN algorithm. | 5123456789012346 |
ccname | Mandatory | Name on card as entered by the customer | Test User |
ccvv | Mandatory | 3-digit CVV (4-digit CID for AMEX) | 123 |
ccexpmon | Mandatory | Card expiry month in MM format (e.g. 01, 12) | 05 |
ccexpyr | Mandatory | Card expiry year in YYYY format (e.g. 2030) | 2030 |
surl | Mandatory | Success URL — PayU redirects here on successful transaction | https://test.payu.in/admin/test_response |
furl | Mandatory | Failure URL — PayU redirects here on failed transaction | https://test.payu.in/admin/test_response |
hash | Mandatory | SHA-512 hash: sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||SALT) | (computed) |
txn_s2s_flow | Mandatory | Must be 4 for Cards Decoupled (S2S) flow | 4 |
s2s_client_ip | Mandatory | The source IP of the customer | 10.200.12.12 |
s2s_device_info | Mandatory | The customer agent’s device information (User-Agent string) | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
zipcode | Optional | Customer’s PIN code (6 digits) | 400004 |
address1 | Optional | Billing address line 1 (up to 100 characters). Recommended for higher approval rate. | 123 Main Street |
address2 | Optional | Billing address line 2 (up to 100 characters) | Suite 100 |
city | Optional | Customer city (max 50 characters). Recommended for higher approval rate. | Mumbai |
state | Optional | Customer state (max 50 characters) | Maharashtra |
country | Optional | Customer country (max 50 characters). Recommended for higher approval rate. | India |
lastname | Optional | Customer last name (alphabets only) | Kumar |
udf1 | Optional | User-defined field 1 (up to 255 characters) | — |
udf2 | Optional | User-defined field 2 (up to 255 characters) | — |
udf3 | Optional | Date of Birth (DOB) of buyer in DD-MM-YYYY. Recommended for higher approval rate. | 22-08-1990 |
udf4 | Optional | User-defined field 4 (up to 255 characters) | — |
udf5 | Optional | User-defined field 5 (up to 255 characters) | — |
store_card | Optional | Set to 1 to tokenize the card for future use | 1 |
user_credentials | Conditional | Required if store_card=1. Format: merchantKey:uniqueCustomerId | JPg****f:customer1 |
store_card=1. Format: merchantKey:uniqueCustomerId
After the payment API call, check binData.pureS2SSupported in the response to determine how the customer completes 3DS authentication:
This card supports Native OTP. You have two choices below to complete authentication. Pick whichever method you prefer.
This card/bank does not support native OTP. Only Pay on Bank Page (3DS Redirect) is available. The bank’s 3DS page will load below.
Choose how to complete 3DS authentication:
⏳ Waiting for payment response… Send a card payment request in the previous step. The authentication options will appear here automatically.
ResponseHandler.php endpoint. The customer stays on your checkout page throughout — no redirects.
https://test.payu.in/ResponseHandler.php | Submit OTP| Parameter | Description | Value |
|---|---|---|
referenceId | Unique reference from payment response — auto-filled from metaData.referenceId | Auto-filled |
otp | OTP entered by the customer on your page | Test: 123456 |
data | Must include payuPureS2S flag | {"payuPureS2S":"1"} |
metaData.referenceId in the payment response123456
acsTemplate (base64-encoded HTML). When decoded and rendered, it auto-submits a form that redirects the customer to the bank’s 3DS page. After authentication, the bank redirects back to your surl/furl.
The bank’s 3DS authentication page is ready. Click the button below to open it in a new tab. After completing OTP on the bank page, you will be redirected to the callback page.
⚠ No ACS template received yet. This will load automatically after you send the payment request in the previous step.
The acsTemplate is a Base64-encoded HTML string. Decode it to get the bank redirect form.
// JavaScript – Decode Base64 acsTemplate
const acsTemplate = response.result.acsTemplate;
const decodedHtml = atob(acsTemplate);
// Open decoded HTML in popup window
const bankWindow = window.open('', 'BankAuth', 'width=800,height=600');
bankWindow.document.write(decodedHtml);
bankWindow.document.close();
Decoded HTML Structure:
<html><body>
<form name="payment_post" action="https://pgsim01.payu.in/initiate" method="post">
<input type="hidden" name="merchantName" value="PAYU">
<input type="hidden" name="txnAmount" value="1.00">
<input type="hidden" name="txnRefId" value="MANDATE_xxx">
<input type="hidden" name="ibibo_code" value="ICICENCC">
<!-- ... more hidden fields ... -->
</form>
<script>
window.onload = function() {
document.forms['payment_post'].submit(); // Auto-submits to bank
}
</script>
</body></html>
Verify via verify_payment, then reconcile status and validate callback integrity using reverse hash.
Always verify the transaction server-side using verify_payment command. Do not rely solely on callback — network issues can cause missed callbacks. You can verify multiple transaction IDs in a single request by separating them with a pipe (|).
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|command|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | verify_payment — fixed value for this API | verify_payment |
var1 | Mandatory | Transaction ID(s) to verify. Multiple txnids can be separated by pipe (|), e.g. TXN_001|TXN_002 | TXN_001 |
hash | Mandatory | sha512(key|verify_payment|var1|salt) | (computed) |
PayU sends a POST callback to your surl (success) or furl (failure). Verify the response hash before updating your order status.
sha512(SALT|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key)
verify_payment API for double confirmationstatus, amount, and txnid match your recordsPre-authorization holds funds on the customer's card without immediately capturing them. Ideal for hotels, car rentals, and e-commerce where the final amount may change. You capture the actual amount later.
Prerequisite: You must be PCI DSS compliant (or use a PCI-compliant vault/tokenization solution) before handling raw card data in this seamless cards flow.
| Authorization Hold | Checks fund availability and holds the required amount on the payer’s card for up to 7 days. Funds are not debited at this stage. |
| Capture | A capture_transaction request debits the funds from the payer’s card. You can capture the full amount or a partial amount (partial capture). After partial capture, the remaining balance is cancelled immediately. |
| Auto Capture | PayU automatically captures the authorized amount on the 7th day if no capture or cancel request is received. Merchants can opt for Auto Cancel or set a custom auto-capture window. |
| Cancel | Cancel applies only to authorized (uncaptured) transactions. Once captured, the transaction can only be refunded, not cancelled. |
| Supported Cards | Pre-auth is supported on Visa, Mastercard, and Amex Credit Cards. |
Phase 1: BIN + payment hash prep. Phase 2: _payment with pre_authorize=1. Phase 3: verify hold and capture (or cancel hold).
Same as normal S2S: generate the correct payment hash first. The pre_authorize=1 flag is included only in the payment request.
Retrieve card BIN details before initiating a pre-authorized payment — issuing bank, card type, network, and capabilities (ATM PIN, OTP, Zero Redirect, SI). Supports single BIN lookup, feature-based filtering, and bulk retrieval.
https://test.payu.in/merchant/postservice.php?form=2 | Command: getBinInfosha512(key|command|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | getBinInfo | getBinInfo |
var1 | Mandatory | Request type: 1 = single BIN, 2 = feature-based list, 3 = all BINs | 1 |
var2 | Conditional | If var1=1: BIN number. If var1=2: 1 (ATM PIN) or 2 (OTP). If var1=3: leave empty. | 512345 |
var3 | Optional | Start index for pagination (default: 0) | 0 |
var4 | Optional | Records per page (default: 100, range: 1–1000) | 100 |
var5 | Optional | Set to 1 for enhanced features (zero redirect, SI support) | 1 |
hash | Mandatory | sha512(key|getBinInfo|var1|salt) | (computed) |
| Use Case | var1 | var2 | var3 | var4 | var5 | Description |
|---|---|---|---|---|---|---|
| Single BIN Query | 1 | 512345 | 0 | 0 | 0 | Get info for a specific BIN |
| Single BIN + Enhanced | 1 | 512345 | 0 | 0 | 1 | Single BIN with zero redirect & SI support |
| ATM PIN Support Cards | 2 | 1 | 1 | 20 | 0 | Get BINs with ATM PIN support |
| OTP Support Cards | 2 | 2 | 1 | 20 | 0 | Get BINs with OTP-on-the-fly support |
| All Cards – Page 1 | 3 | 1 | 20 | 0 | First 20 cards (records 1–20) | |
| All Cards – Page 2 | 3 | 21 | 20 | 0 | Next 20 cards (records 21–40) | |
| Large Batch Query | 3 | 1 | 100 | 0 | Get 100 cards at once | |
| Custom Range | 3 | 501 | 50 | 0 | Cards 501–550 |
| Parameter | Values | Use Case in Pre-Auth Flow |
|---|---|---|
issuing_bank | e.g. HDFC, ICICI | Identify the issuing bank. Some banks may have pre-auth limits or restrictions |
bin | BIN number | The matched BIN (6–9 digits). Confirms the BIN PayU resolved for this card |
category | creditcard / debitcard | Important: Pre-auth is primarily supported on credit cards. Some debit cards may not support pre-auth — check before proceeding |
card_type | VISA, MAST, AMEX, MAES, DINR | Determine card network. Pre-auth support varies by network. Set bankcode as CC for pre-auth payment |
is_domestic | 1 = Domestic, 0 = International | Domestic cards can use S2S Native OTP for pre-auth. International cards redirect to 3DS for authentication |
is_otp_on_the_fly | 1 = Supported, 0 = Not | Critical: If 1, card supports Native OTP for pre-auth. You can authenticate via submit_otp API in Step 4 instead of bank page redirect. If 0, only 3DS Redirect works |
is_atmpin_card | 1 / 0 | If 1, card supports ATM PIN based authentication |
is_zero_redirect_supported | 1 / 0 | If 1, zero redirect flow is possible for pre-auth. Returned only when var5=1 |
is_si_supported | 1 / 0 | If 1, card supports Standing Instructions — useful for recurring pre-auth scenarios. Returned only when var5=1 |
Call _payment with pre_authorize=1 to hold funds. Final debit happens later when you capture.
Before calling _payment with pre_authorize=1, you must generate a SHA-512 hash. This hash ensures that no one has tampered with the payment request parameters. The hash formula is identical to a normal payment.
_payment API
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
| Field | Description | Example |
|---|---|---|
key | Merchant Key provided by PayU | a4vGC2 |
txnid | Your unique transaction ID | TXN_1234567890 |
amount | Pre-auth hold amount | 10.00 |
productinfo | Product description | Test Product |
firstname | Customer first name | Test |
email | Customer email | test@example.com |
udf1–udf5 | User-defined fields — pass empty string if not used | (empty) |
|||||| | Six pipes for empty udf6–udf10 (always required) | |||||| |
salt | Merchant Salt — never expose to client | hKvGJP28d2... |
|||||| (six pipes) between udf5 and salt are for empty udf6–udf10 and are always requiredpre_authorize, ccnum, ccvv, ccexpmon, ccexpyr, pg, bankcode, surl, furl, txn_s2s_flow — these are sent as separate parameters. The pre_authorize=1 flag does not change the hash formula.
_payment with pre_authorize=1)
Submit a pre-authorization request to hold funds on the customer’s card without debiting. The pre_authorize=1 parameter is the only difference from a normal card payment.
https://test.payu.in/_paymentapplication/x-www-form-urlencoded| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | JPg****f |
txnid | Mandatory | Unique transaction ID generated by the merchant. PayU rejects duplicate txnids. | ypl938459435 |
amount | Mandatory | Payment amount to hold on the card | 18000 |
productinfo | Mandatory | Brief description of the product | iPhone |
firstname | Mandatory | Customer first name | Ashish |
email | Mandatory | Customer email address | test@gmail.com |
phone | Mandatory | Customer phone number | 9876543210 |
pg | Mandatory | CC for Credit Card | CC |
bankcode | Mandatory | Bank code for the card (e.g. CC, AMEX) | CC |
ccnum | Mandatory | 13–19 digit card number (15 for AMEX). Validated with LUHN algorithm. | 5123456789012346 |
ccname | Mandatory | Name on card as entered by the customer | Test User |
ccvv | Mandatory | 3-digit CVV (4-digit CID for AMEX) | 123 |
ccexpmon | Mandatory | Card expiry month in MM format (e.g. 01, 12) | 05 |
ccexpyr | Mandatory | Card expiry year in YYYY format (e.g. 2030) | 2030 |
surl | Mandatory | Success URL — PayU redirects here on successful authorization | https://test.payu.in/admin/test_response |
furl | Mandatory | Failure URL — PayU redirects here on failed authorization | https://test.payu.in/admin/test_response |
pre_authorize | Mandatory | Must be 1 for pre-authorization. This holds funds without debiting. | 1 |
hash | Mandatory | SHA-512 hash (see Generate Payment Hash step above). pre_authorize is NOT included in hash. | (computed) |
txn_s2s_flow | Mandatory | Must be 4 for Cards Decoupled (S2S) flow | 4 |
s2s_client_ip | Mandatory | The source IP of the customer | 10.200.12.12 |
s2s_device_info | Mandatory | The customer agent’s device information (User-Agent string) | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
address1 | Optional | Billing address line 1 (recommended for fraud detection) | 123 Main Street |
address2 | Optional | Billing address line 2 | Suite 100 |
city | Optional | Customer city | Mumbai |
state | Optional | Customer state | Maharashtra |
country | Optional | Customer country | India |
zipcode | Optional | Billing zip code | 400004 |
udf1–udf5 | Optional | User-defined fields to store additional info per transaction | — |
CC, DC, AMEX)
1 for pre-authorization. Holds funds without debiting.
After the payment API call, check binData.pureS2SSupported in the response to determine how the customer completes 3DS authentication:
This card supports Native OTP. You have two choices below to complete authentication. Pick whichever method you prefer.
This card/bank does not support native OTP. Only Pay on Bank Page (3DS Redirect) is available. The bank’s 3DS page will load below.
Choose how to complete 3DS authentication:
⏳ Waiting for payment response… Send a pre-auth payment request in the previous step. The authentication options will appear here automatically.
ResponseHandler.php endpoint. The customer stays on your checkout page throughout — no redirects.
https://test.payu.in/ResponseHandler.php | Submit OTP| Parameter | Description | Value |
|---|---|---|
referenceId | Unique reference from payment response — auto-filled from metaData.referenceId | Auto-filled |
otp | OTP entered by the customer on your page | Test: 123456 |
data | Must include payuPureS2S flag | {"payuPureS2S":"1"} |
metaData.referenceId in the payment response123456
acsTemplate (base64-encoded HTML). When decoded and rendered, it auto-submits a form that redirects the customer to the bank’s 3DS page. After authentication, the bank redirects back to your surl/furl.
The bank’s 3DS authentication page is ready. Click the button below to open it in a new tab. After completing OTP on the bank page, you will be redirected to the callback page.
⚠ No ACS template received yet. This will load automatically after you send the payment request in the previous step.
The acsTemplate is a Base64-encoded HTML string. Decode it to get the bank redirect form.
// JavaScript – Decode Base64 acsTemplate
const acsTemplate = response.result.acsTemplate;
const decodedHtml = atob(acsTemplate);
// Open decoded HTML in popup window
const bankWindow = window.open('', 'BankAuth', 'width=800,height=600');
bankWindow.document.write(decodedHtml);
bankWindow.document.close();
Decoded HTML Structure:
<html><body>
<form name="payment_post" action="https://pgsim01.payu.in/initiate" method="post">
<input type="hidden" name="merchantName" value="PAYU">
<input type="hidden" name="txnAmount" value="1.00">
<input type="hidden" name="txnRefId" value="MANDATE_xxx">
<input type="hidden" name="ibibo_code" value="ICICENCC">
<!-- ... more hidden fields ... -->
</form>
<script>
window.onload = function() {
document.forms['payment_post'].submit(); // Auto-submits to bank
}
</script>
</body></html>
Verify the hold (auth), then capture (auth => captured). Optionally cancel the hold.
Verify the pre-auth transaction server-side using verify_payment command. Look for unmappedstatus: auth in the response which confirms funds are held on the card.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|verify_payment|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | verify_payment — fixed value for this API | verify_payment |
var1 | Mandatory | Transaction ID(s) to verify. Multiple txnids can be separated by pipe (|) | TXN_001 |
hash | Mandatory | sha512(key|verify_payment|var1|salt) | (computed) |
transaction_details.<txnid>.unmappedstatus — value auth confirms the pre-authorization hold is active. After capture, this changes to captured.
Cancel the pre-authorized (held) payment using PayU cancel_transaction. This command cancels the hold and releases the funds back to the card. Cancel is only applicable to Authorization requests — any captured transaction can only be refunded.
https://test.payu.in/merchant/postservice.php?form=2sha512(key|cancel_transaction|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | cancel_transaction — fixed value | cancel_transaction |
var1 | Mandatory | PayU ID (mihpayid) from the pre-auth or verify_payment response | 403993715537230966 |
var2 | Mandatory | Merchant unique reference number (token) for this cancel request | CANCEL_REF_001 |
hash | Mandatory | sha512(key|cancel_transaction|var1|salt) | (computed) |
Capture the pre-authorized amount to actually debit the customer’s card. The captured amount can be less than or equal to the authorized amount (partial capture). After partial capture, the remaining balance is cancelled automatically.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|capture_transaction|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | capture_transaction — fixed value for this API | capture_transaction |
var1 | Mandatory | PayU ID (mihpayid) generated by PayU as part of the pre-authorize operation | 403993715537230966 |
var2 | Mandatory | Merchant unique reference number (token) for this capture request | CAPTURE_REF_001 |
var3 | Mandatory | Amount to capture — must be ≤ authorized amount. Partial capture is supported. | 18000 |
hash | Mandatory | sha512(key|capture_transaction|var1|salt) | (computed) |
"status": 1, "msg": "Capture Request Queued", a request_id, and bank_ref_num. Always verify the final status using verify_payment after capture.
After capture, verify again using verify_payment to confirm the transaction status. The unmappedstatus should change from auth to captured, confirming the funds have been debited.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|verify_payment|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | verify_payment — fixed value for this API | verify_payment |
var1 | Mandatory | Transaction ID(s) to verify. Multiple txnids can be separated by pipe (|) | TXN_001 |
hash | Mandatory | sha512(key|verify_payment|var1|salt) | (computed) |
unmappedstatus = auth (funds held)unmappedstatus = captured (funds debited)unmappedstatus = auth with cancellation reflected
PayU processes capture requests via a background cron that runs every ~1 minute. After clicking “Verify Final Status”, if the status is still auth, the tool will automatically retry every 10 seconds (up to ~80 seconds) until the status changes to captured.
Tokenization replaces sensitive card data with secure tokens per RBI guidelines. Choose the model that fits your integration needs. Each model below shows the complete Pre-Payment, Payment & Post-Payment lifecycle.
Prerequisite: You must be PCI DSS compliant (or use a PCI-compliant tokenization flow) before handling raw card data during first-time token creation.
Just add store_card=1 & user_credentials to your existing payment request. PayU tokenizes automatically.
Full control with save_payment_instrument, get_payment_instrument, delete_payment_instrument & Cryptogram APIs.
PayU is onboarded as token requestor. You pass consent (store_card=1) and a user ID (user_credentials) during payment. PayU processes the transaction, creates network/issuer tokens, and stores them on your behalf. For repeat payments, retrieve saved cards with get_user_cards and pay using the token + CVV.
New customer paying for the first time. Collect card details, process the payment with store_card=1, and the card is automatically tokenized by PayU.
store_card=1 → 3DS Auth → Verify PaymentReturning customer with a previously saved card. Fetch their saved cards, let them pick one, enter CVV, and process payment using the stored token.
store_card_token + CVV → 3DS Auth → Verify
For first-time customers, validate the card BIN. For returning customers, also fetch their saved (tokenized) cards using get_user_cards.
Validate the card BIN (first 6–8 digits) to check card type, issuing bank, card category (domestic/international), capabilities (ATM PIN, OTP, Zero Redirect, SI) before proceeding with tokenized payment.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|getBinInfo|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU for authentication | JPg****f |
command | Mandatory | getBinInfo — fixed value for this API | getBinInfo |
var1 | Mandatory | Request type: 1 = single BIN lookup, 2 = feature-based BIN list, 3 = all BINs | 1 |
var2 | Conditional | If var1=1: BIN number (e.g. 512345). If var1=2: 1 (ATM PIN) or 2 (OTP). If var1=3: leave empty. | 512345 |
var3 | Optional | Start index for pagination (default: 0) | 0 |
var4 | Optional | Records per page (default: 100, range: 1–1000) | 100 |
var5 | Optional | Set to 1 to fetch enhanced features (is_zero_redirect_supported, is_si_supported) | 1 |
hash | Mandatory | sha512(key|getBinInfo|var1|salt) | (computed) |
| Use Case | var1 | var2 | var3 | var4 | var5 | Description |
|---|---|---|---|---|---|---|
| Single BIN Query | 1 | 512345 | 0 | 0 | 0 | Get info for a specific BIN |
| Single BIN + Enhanced | 1 | 512345 | 0 | 0 | 1 | Single BIN with zero redirect & SI support |
| ATM PIN Support Cards | 2 | 1 | 1 | 20 | 0 | Get BINs with ATM PIN support |
| OTP Support Cards | 2 | 2 | 1 | 20 | 0 | Get BINs with OTP-on-the-fly support |
| All Cards – Page 1 | 3 | 1 | 20 | 0 | First 20 cards (records 1–20) | |
| Large Batch Query | 3 | 1 | 100 | 0 | Get 100 cards at once |
| Parameter | Values | Use Case in Model 2 Tokenization |
|---|---|---|
issuing_bank | e.g. HDFC, ICICI | Display issuing bank to user during card entry. Helps confirm card identity before tokenization |
bin | BIN number | The resolved BIN. Use for pre-validation before sending _payment with store_card=1 |
category | creditcard / debitcard | Show card category to user. Both credit and debit cards support Model 2 tokenization |
card_type | VISA, MAST, AMEX, MAES, DINR | Identify card network. Tokenization support varies: VISA, MAST, AMEX fully supported. DINR uses issuer tokens. Use to set bankcode in payment |
is_domestic | 1 = Domestic, 0 = International | Domestic cards support S2S Native OTP for tokenized payment. International cards go through 3DS redirect |
is_otp_on_the_fly | 1 = Supported, 0 = Not | Critical for 3DS step: If 1, both Native OTP and 3DS Redirect options appear in Step 4. If 0, only Pay on Bank Page (3DS Redirect) is available. This directly controls the pureS2SSupported behavior |
is_atmpin_card | 1 / 0 | If 1, ATM PIN authentication may be available as an alternative during tokenized payment |
is_zero_redirect_supported | 1 / 0 | If 1, zero redirect (headless) tokenized payment is possible. Returned only when var5=1 |
is_si_supported | 1 / 0 | If 1, card supports Standing Instructions with tokenization — useful for subscription-based repeat payments. Returned only when var5=1 |
is_otp_on_the_fly before payment — it determines whether you can use Native OTP (submit_otp API) or must use 3DS Redirect after the _payment call with store_card=1. For repeat customers using store_card_token, the same parameter applies for authentication method selection.
Retrieve saved (tokenized) cards for a returning customer. Returns card_token, masked card number, card type, card mode, and token details (network/issuer). Customer selects a saved card and enters only CVV.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|get_user_cards|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPM7Fg |
command | Mandatory | API command — fixed value get_user_cards | get_user_cards |
var1 | Mandatory | User credentials in format merchantKey:userId. Must match what was used during save_payment_instrument or store_card. | JPM7Fg:abc |
hash | Mandatory | sha512(key|get_user_cards|var1|salt) | Computed hash |
a4vGC2:test_customer1
{"status":0, "msg":"Card not found."}. This is expected for first-time users. Cards are saved only after a successful payment with store_card=1.For first-time customers, send full card details with store_card=1. For returning customers, send store_card_token + CVV.
Before calling _payment, you must generate a SHA-512 hash. This hash ensures that no one has tampered with the payment request parameters. The hash formula is the same for both first-time and repeat customers.
_payment API
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
| Field | Description | Example |
|---|---|---|
key | Merchant Key provided by PayU | a4vGC2 |
txnid | Your unique transaction ID | TXN_1234567890 |
amount | Transaction amount | 10.00 |
productinfo | Product description | Test Product |
firstname | Customer first name | Test |
email | Customer email | test@example.com |
udf1–udf5 | User-defined fields — pass empty string if not used | (empty) |
|||||| | Six pipes for empty udf6–udf10 (always required) | |||||| |
salt | Merchant Salt — never expose to client | hKvGJP28d2... |
|||||| (six pipes) between udf5 and salt are for empty udf6–udf10 and are always requiredstore_card, user_credentials, store_card_token, ccnum, ccvv, ccexpmon, ccexpyr, pg, bankcode, surl, furl, txn_s2s_flow — tokenization parameters and card details are sent separately but are not part of the hash computation.
Send full card details with two extra tokenization parameters (store_card=1 and user_credentials) to instruct PayU to tokenize the card after successful payment. The _payment API processes the transaction first, then creates a network/issuer token which is stored in PayU Vault.
https://test.payu.in/_paymentapplication/x-www-form-urlencoded| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | JPg****f |
txnid | Mandatory | Unique transaction ID generated by the merchant | ypl938459435 |
amount | Mandatory | Payment amount (e.g. 10.00) | 10.00 |
productinfo | Mandatory | Brief description of the product | iPhone |
firstname | Mandatory | Customer first name | Ashish |
email | Mandatory | Customer email address | test@gmail.com |
phone | Mandatory | Customer phone number | 9876543210 |
pg | Mandatory | CC for Credit Card | CC |
bankcode | Mandatory | Card bank code (e.g. CC, AMEX) | CC |
ccnum | Mandatory | Full card number (13–19 digits, validated with LUHN) | 5123456789012346 |
ccname | Mandatory | Name on card as entered by the customer | Test User |
ccvv | Mandatory | 3-digit CVV (4-digit CID for AMEX) | 123 |
ccexpmon | Mandatory | Card expiry month in MM format (e.g. 05) | 05 |
ccexpyr | Mandatory | Card expiry year in YYYY format (e.g. 2030) | 2030 |
surl | Mandatory | Success URL — PayU redirects here on successful payment | https://test.payu.in/admin/test_response |
furl | Mandatory | Failure URL — PayU redirects here on failed payment | https://test.payu.in/admin/test_response |
hash | Mandatory | SHA-512 hash (see Generate Payment Hash step above) | (computed) |
store_card | Mandatory | 1 = customer consent to save card. 0 = no consent. | 1 |
user_credentials | Mandatory | merchantKey:uniqueUserId — identifies the customer | JPg****f:customer1 |
txn_s2s_flow | Mandatory | 4 — enables S2S JSON response format | 4 |
s2s_client_ip | Mandatory | Customer’s IP address (e.g. 10.200.12.12) | 10.200.12.12 |
s2s_device_info | Mandatory | Customer’s User-Agent string | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
address1, address2 | Optional | Billing address (recommended for fraud detection) | 123 Main Street |
city, state, country, zipcode | Optional | Billing address details | Mumbai, MH, India, 400004 |
udf1–udf5 | Optional | User-defined fields for additional transaction info | — |
5506900480000008 (MC) • 4895370077346937 (Visa) — OTP: 1234561 = customer consent to save cardmerchantKey:uniqueUserId
cardToken in the callback response. Store this token for repeat payments.Send the store_card_token instead of full card details. Card number, name, expiry are not needed — PayU resolves them from the token. CVV is optional for saved card transactions.
https://test.payu.in/_paymentapplication/x-www-form-urlencoded| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
txnid | Mandatory | Unique transaction ID generated by the merchant | ypl938459435 |
amount | Mandatory | Payment amount | 10.00 |
productinfo | Mandatory | Brief description of the product | iPhone |
firstname | Mandatory | Customer first name | Ashish |
email | Mandatory | Customer email address | test@gmail.com |
phone | Mandatory | Customer phone number | 9876543210 |
pg | Mandatory | CC for Credit Card | CC |
bankcode | Mandatory | Card bank code (e.g. CC) | CC |
surl | Mandatory | Success URL | https://test.payu.in/admin/test_response |
furl | Mandatory | Failure URL | https://test.payu.in/admin/test_response |
hash | Mandatory | SHA-512 hash (same formula as first-time payment) | (computed) |
user_credentials | Mandatory | merchantKey:uniqueUserId — must match value used during card save | JPg****f:customer1 |
store_card_token | Mandatory | Card token from get_user_cards response (card_token field) | abc123tokenxyz |
txn_s2s_flow | Mandatory | 4 — enables S2S JSON response format | 4 |
s2s_client_ip | Mandatory | Customer’s IP address | 10.200.12.12 |
s2s_device_info | Mandatory | Customer’s User-Agent string | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
ccvv | Optional | CVV — not required for saved card transactions | 123 |
storecard_token_type | Optional | 0 for PayU token hub (default if omitted) | 0 |
address1, address2 | Optional | Billing address (recommended for fraud detection) | 123 Main Street |
city, state, country, zipcode | Optional | Billing address details | Mumbai, MH, India, 400004 |
udf1–udf5 | Optional | User-defined fields for additional transaction info | — |
ccnum, ccname, ccexpmon, ccexpyr, store_card — card details are resolved from the token by PayU.
card_token from the response.
1230 for PayU token hub (default if omitted)
merchantKey:uniqueUserId
After the payment API call, check binData.pureS2SSupported in the response to determine how the customer completes 3DS authentication:
This card supports Native OTP. You have two choices below to complete authentication. Pick whichever method you prefer.
This card/bank does not support native OTP. Only Pay on Bank Page (3DS Redirect) is available. The bank’s 3DS page will load below.
Choose how to complete 3DS authentication:
⏳ Waiting for payment response… Send a payment request in the previous step. The authentication options will appear here automatically.
ResponseHandler.php endpoint. The customer stays on your checkout page throughout — no redirects.
https://test.payu.in/ResponseHandler.php | Submit OTP| Parameter | Description | Value |
|---|---|---|
referenceId | Unique reference from payment response — auto-filled from metaData.referenceId | Auto-filled |
otp | OTP entered by the customer on your page | Test: 123456 |
data | Must include payuPureS2S flag | {"payuPureS2S":"1"} |
metaData.referenceId in the payment response123456
acsTemplate (base64-encoded HTML). When decoded and rendered, it auto-submits a form that redirects the customer to the bank’s 3DS page. After authentication, the bank redirects back to your surl/furl.
The bank’s 3DS authentication page is ready. Click the button below to open it in a new tab. After completing OTP on the bank page, you will be redirected to the callback page.
⚠ No ACS template received yet. This will load automatically after you send the payment request in the previous step.
The acsTemplate is a Base64-encoded HTML string. Decode it to get the bank redirect form.
// JavaScript – Decode Base64 acsTemplate
const acsTemplate = response.result.acsTemplate;
const decodedHtml = atob(acsTemplate);
// Open decoded HTML in popup window
const bankWindow = window.open('', 'BankAuth', 'width=800,height=600');
bankWindow.document.write(decodedHtml);
bankWindow.document.close();
Decoded HTML Structure:
<html><body>
<form name="payment_post" action="https://pgsim01.payu.in/initiate" method="post">
<input type="hidden" name="merchantName" value="PAYU">
<input type="hidden" name="txnAmount" value="1.00">
<input type="hidden" name="txnRefId" value="MANDATE_xxx">
<input type="hidden" name="ibibo_code" value="ICICENCC">
<!-- ... more hidden fields ... -->
</form>
<script>
window.onload = function() {
document.forms['payment_post'].submit(); // Auto-submits to bank
}
</script>
</body></html>
Verify the transaction. For first-time payments, the cardToken is returned in the callback — store it for future repeat payments.
Confirm the transaction status server-side using verify_payment command. Always verify before trusting callback data. You can verify multiple transactions by separating txnid values with a pipe (|).
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|verify_payment|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | verify_payment — fixed value for this API | verify_payment |
var1 | Mandatory | Transaction ID(s) to verify. Multiple txnids separated by pipe (|) | TXN_001 |
hash | Mandatory | sha512(key|verify_payment|var1|salt) | (computed) |
PayU's callback (surl/furl) for a first-time payment includes cardToken. Store this securely in your database linked to the customer ID for future repeat payments.
status=success
cardToken=28b99d39e83e8031caa7ad ← Store this for repeat payments
cardnum=XXXXXXXXXXXX2346
mode=CC
unmappedstatus=capturedAlways verify sha512(SALT|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key) before trusting callback data.
Remove a saved token when the customer revokes consent or the card expires. Use delete_payment_instrument (or delete_user_card) API.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|delete_payment_instrument|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | delete_payment_instrument — fixed value for this API | delete_payment_instrument |
var1 | Mandatory | User credentials: merchantKey:userId | JPg****f:customer1 |
var2 | Mandatory | Card token (cardToken) to delete | abc123tokenxyz |
var3 | Optional | Network token value (if deleting specific network token) | — |
var4 | Optional | Issuer token value (if deleting specific issuer token) | — |
hash | Mandatory | sha512(key|delete_payment_instrument|var1|salt) | (computed) |
You have full control over the token lifecycle using dedicated REST APIs. For first-time transactions, process the payment first, then call save_payment_instrument to create the token. For repeat transactions, retrieve saved cards via get_user_cards or token details via get_payment_instrument, and optionally get the cryptogram for network tokens. You can also process tokens outside PayU.
New customer paying with a fresh card. Process the payment first, then explicitly call save_payment_instrument API to create the token. You control when and how the token is created.
save_payment_instrumentReturning customer using a previously tokenized card. Retrieve token details via get_payment_instrument, fetch the cryptogram (TAVV), and process payment using the network token.
For first-time customers, collect card details and consent, then validate the BIN. For repeat customers, retrieve saved cards via get_user_cards or token details via get_payment_instrument, and optionally get the cryptogram (TAVV) for network token transactions.
Validate the card BIN (first 6–8 digits) to check card type, issuing bank, card category (domestic/international), supported authentication methods, and token capabilities before proceeding with REST API tokenization.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|getBinInfo|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU for authentication | JPg****f |
command | Mandatory | getBinInfo — fixed value for this API | getBinInfo |
var1 | Mandatory | Request type: 1 = single BIN lookup, 2 = feature-based BIN list, 3 = all BINs | 1 |
var2 | Conditional | If var1=1: BIN number (e.g. 512345). If var1=2: 1 (ATM PIN) or 2 (OTP). If var1=3: leave empty. | 512345 |
var3 | Optional | Start index for pagination (default: 0) | 0 |
var4 | Optional | Records per page (default: 100, range: 1–1000) | 100 |
var5 | Optional | Set to 1 to fetch enhanced features (is_zero_redirect_supported, is_si_supported) | 1 |
hash | Mandatory | sha512(key|getBinInfo|var1|salt) | (computed) |
| Use Case | var1 | var2 | var3 | var4 | var5 | Description |
|---|---|---|---|---|---|---|
| Single BIN Query | 1 | 512345 | 0 | 0 | 0 | Get info for a specific BIN |
| Single BIN + Enhanced | 1 | 512345 | 0 | 0 | 1 | Single BIN with zero redirect & SI support |
| ATM PIN Support Cards | 2 | 1 | 1 | 20 | 0 | Get BINs with ATM PIN support |
| OTP Support Cards | 2 | 2 | 1 | 20 | 0 | Get BINs with OTP-on-the-fly support |
| All Cards – Page 1 | 3 | 1 | 20 | 0 | First 20 cards (records 1–20) | |
| Large Batch Query | 3 | 1 | 100 | 0 | Get 100 cards at once |
| Parameter | Values | Use Case in Model 3 Tokenization |
|---|---|---|
issuing_bank | e.g. HDFC, ICICI | Identify issuing bank. Used for display and helps determine token provisioning path (network vs issuer) |
bin | BIN number | The resolved BIN. Validate before calling save_payment_instrument for first-time or get_payment_details for repeat |
category | creditcard / debitcard | Card category. Both types support Model 3. Debit cards may have different token provisioning behavior |
card_type | VISA, MAST, AMEX, MAES, DINR | Critical for token type: VISA/MAST → Network Token (storecard_token_type=1). DINR (Diners) → Issuer Token (storecard_token_type=2). Determines which token path to use in repeat payments |
is_domestic | 1 = Domestic, 0 = International | Domestic cards support S2S Native OTP. International cards use 3DS redirect for authentication during payment |
is_otp_on_the_fly | 1 = Supported, 0 = Not | Critical for 3DS step: If 1, both Native OTP and 3DS Redirect options appear in the Handle 3DS step. If 0, only Pay on Bank Page (3DS Redirect) is available. Controls pureS2SSupported in the _payment response |
is_atmpin_card | 1 / 0 | If 1, ATM PIN authentication may be available during tokenized payment |
is_zero_redirect_supported | 1 / 0 | If 1, zero redirect (headless) flow possible for tokenized payments. Returned only when var5=1 |
is_si_supported | 1 / 0 | If 1, card supports Standing Instructions — useful for subscription payments with saved tokens. Returned only when var5=1 |
card_type is the most important parameter for Model 3. It determines the token type for repeat payments:
VISA/MAST → Use Network Token (storecard_token_type=1) with TAVV from get_payment_detailsDINR → Use Issuer Token (storecard_token_type=2) with trMerchantId, tokenReferenceId, tokenBank from cryptogramstorecard_token_type=0) via get_user_cardsRetrieve all saved (tokenized) cards for a returning customer. Returns card_token, masked card number, card type, card mode, and token details. Customer selects a saved card and enters only CVV for repeat payment.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|get_user_cards|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPM7Fg |
command | Mandatory | Fixed value get_user_cards | get_user_cards |
var1 | Mandatory | User credentials: merchantKey:userId. Must match what was used during card save. | JPM7Fg:abc |
hash | Mandatory | sha512(key|get_user_cards|var1|salt) | (computed) |
{"status":0, "msg":"Card not found."}. Cards are saved after a successful payment with store_card=1 (Model 2) or via save_payment_instrument (Model 3).Retrieve saved tokens with full metadata — PayU token, network token, issuer token, masked card number, card type, and expiry. Alternative to get_user_cards with richer token details.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|get_payment_instrument|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | get_payment_instrument — fixed value for this API | get_payment_instrument |
var1 | Mandatory | merchantKey:userId — must match what was used during save_payment_instrument | JPg****f:customer1 |
hash | Mandatory | sha512(key|get_payment_instrument|var1|salt) | (computed) |
For network token transactions processed outside PayU, retrieve the cryptogram (TAVV) needed for authentication. Call get_payment_details with var3=1 to request cryptogram.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|get_payment_details|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | get_payment_details — fixed value for this API | get_payment_details |
var1 | Mandatory | User credentials: merchantKey:userId | JPg****f:customer1 |
var2 | Mandatory | Card token (cardToken) from Get Payment Instrument / Get User Cards response | abc123tokenxyz |
var3 | Mandatory | Transaction amount (e.g. 10) | 10 |
var4 | Mandatory | Currency code (default: INR). Left blank defaults to INR. | INR |
var5 | Mandatory | Token type: NETWORK or PAYU. Left blank defaults to PAYU. | NETWORK |
hash | Mandatory | sha512(key|get_payment_details|var1|salt) | (computed) |
1)INRNETWORK or PAYU
Retrieve all saved (tokenized) cards for a returning customer using PayU's get_user_cards API. Returns card_token which is used as store_card_token when storecard_token_type=0.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|get_user_cards|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | a4vGC2 |
command | Mandatory | Fixed value get_user_cards | get_user_cards |
var1 | Mandatory | User credentials: merchantKey:userId. Must match what was used during card save. | a4vGC2:test_customer1 |
hash | Mandatory | sha512(key|get_user_cards|var1|salt) | (computed) |
For first-time, send plain card details (token will be created post-payment via save_payment_instrument). For repeat, choose between PayU token, network token, or issuer token.
Before calling _payment, you must generate a SHA-512 hash. This hash ensures that no one has tampered with the payment request parameters. The hash formula is the same for all three token types (PayU Token, Network Token, Issuer Token) and for first-time customers.
_payment API
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
| Field | Description | Example |
|---|---|---|
key | Merchant Key provided by PayU | a4vGC2 |
txnid | Your unique transaction ID | TXN_1234567890 |
amount | Transaction amount | 10.00 |
productinfo | Product description | Test Product |
firstname | Customer first name | Test |
email | Customer email | test@example.com |
udf1–udf5 | User-defined fields — pass empty string if not used | (empty) |
|||||| | Six pipes for empty udf6–udf10 (always required) | |||||| |
salt | Merchant Salt — never expose to client | hKvGJP28d2... |
|||||| (six pipes) between udf5 and salt are for empty udf6–udf10 and are always requiredstore_card_token, storecard_token_type, user_credentials, additional_info, ccnum, ccvv, ccexpmon, ccexpyr, txn_s2s_flow, pg, bankcode, surl, furl — token type, card details, and S2S parameters are sent separately but are not part of the hash. The hash remains identical for PayU, Network, and Issuer tokens.
Process the transaction with full card details. After payment succeeds, call save_payment_instrument in Post-Payment phase to create the token. Unlike Model 2, no store_card or user_credentials parameter is needed during payment — tokenization happens explicitly via a separate API call.
https://test.payu.in/_paymentapplication/x-www-form-urlencoded| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
txnid | Mandatory | Unique transaction ID generated by the merchant | ypl938459435 |
amount | Mandatory | Payment amount (e.g. 10.00) | 10.00 |
productinfo | Mandatory | Brief description of the product | iPhone |
firstname | Mandatory | Customer first name | Ashish |
email | Mandatory | Customer email address | test@gmail.com |
phone | Mandatory | Customer phone number | 9876543210 |
pg | Mandatory | CC for Credit Card | CC |
bankcode | Mandatory | Card bank code (e.g. CC, AMEX) | CC |
ccnum | Mandatory | Full card number (13–19 digits, validated with LUHN) | 5123456789012346 |
ccname | Mandatory | Name on card as entered by the customer | Test User |
ccvv | Mandatory | 3-digit CVV (4-digit CID for AMEX) | 123 |
ccexpmon | Mandatory | Card expiry month in MM format | 05 |
ccexpyr | Mandatory | Card expiry year in YYYY format | 2030 |
surl | Mandatory | Success URL — PayU redirects here on success | https://test.payu.in/admin/test_response |
furl | Mandatory | Failure URL — PayU redirects here on failure | https://test.payu.in/admin/test_response |
hash | Mandatory | SHA-512 hash (see Generate Payment Hash step) | (computed) |
txn_s2s_flow | Mandatory | 4 — enables S2S JSON response format | 4 |
s2s_client_ip | Mandatory | Customer’s IP address | 10.200.12.12 |
s2s_device_info | Mandatory | Customer’s User-Agent string | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
user_credentials | Optional | merchantKey:userId — not required for Model 3 first-time (tokenization is done via save_payment_instrument) | JPg****f:customer1 |
address1, address2 | Optional | Billing address (recommended for fraud detection) | 123 Main Street |
city, state, country, zipcode | Optional | Billing address details | Mumbai, MH, India, 400004 |
udf1–udf5 | Optional | User-defined fields for additional transaction info | — |
Send the PayU token from get_payment_instrument instead of full card details. Customer only enters CVV.
https://test.payu.in/_paymentapplication/x-www-form-urlencoded| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
txnid | Mandatory | Unique transaction ID | ypl938459435 |
amount | Mandatory | Payment amount | 10.00 |
productinfo | Mandatory | Product description | iPhone |
firstname | Mandatory | Customer first name | Ashish |
email | Mandatory | Customer email | test@gmail.com |
phone | Mandatory | Customer phone | 9876543210 |
surl / furl | Mandatory | Success / Failure callback URLs | https://test.payu.in/admin/test_response |
store_card_token | Mandatory | PayU token from get_payment_instrument or get_user_cards | abc123tokenxyz |
user_credentials | Mandatory | merchantKey:userId — mandatory for PayU Token payments | JPg****f:customer1 |
storecard_token_type | Mandatory | 0 (PayU Token) | 0 |
txn_s2s_flow | Mandatory | 4 — S2S JSON response | 4 |
s2s_client_ip | Mandatory | Customer’s IP address | 10.200.12.12 |
s2s_device_info | Mandatory | Customer’s User-Agent string | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
pg | Mandatory | CC | CC |
bankcode | Mandatory | CC | CC |
hash | Mandatory | SHA-512 hash | (computed) |
ccvv | Optional | CVV — optional for saved card transactions | 123 |
Send a repeat payment using a stored token. Choose the token type below: PayU Token (from Get User Cards), Network Token (from Get Cryptogram), or Issuer Token.
https://test.payu.in/_paymentapplication/x-www-form-urlencoded| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
txnid | Mandatory | Unique transaction ID | ypl938459435 |
amount | Mandatory | Payment amount | 10.00 |
productinfo | Mandatory | Product description | iPhone |
firstname | Mandatory | Customer first name | Ashish |
email | Mandatory | Customer email | test@gmail.com |
phone | Mandatory | Customer phone | 9876543210 |
pg | Mandatory | CC | CC |
bankcode | Mandatory | CC | CC |
surl | Mandatory | Success URL | https://test.payu.in/admin/test_response |
furl | Mandatory | Failure URL | https://test.payu.in/admin/test_response |
hash | Mandatory | SHA-512 hash | (computed) |
storecard_token_type | Mandatory | 0 = PayU Token | 1 = Network Token | 2 = Issuer Token | 0 |
store_card_token | Mandatory | Token value: PayU token / Network DPAN / Issuer token value | abc123tokenxyz |
txn_s2s_flow | Mandatory | 4 — S2S JSON response | 4 |
s2s_client_ip | Mandatory | Customer’s IP address | 10.200.12.12 |
s2s_device_info | Mandatory | Customer’s User-Agent string | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
user_credentials | Conditional | key:customerId — mandatory when storecard_token_type=0. Optional for Network/Issuer. | JPg****f:customer1 |
additional_info | Conditional | JSON with TAVV, TRID, last4Digits — mandatory when storecard_token_type=1 or 2 | {"tavv":"...","trid":"..."} |
ccexpmon / ccexpyr | Conditional | Token expiry month/year — required for Network & Issuer tokens | 05 / 2030 |
ccvv | Optional | CVV — optional for saved card / token transactions | 123 |
address1, address2 | Optional | Billing address (recommended for fraud detection) | 123 Main Street |
city, state, country, zipcode | Optional | Billing address details | Mumbai, MH, India, 400004 |
udf1–udf5 | Optional | User-defined fields for additional transaction info | — |
| Token Type | APIs to Call (in order) | Token Source |
|---|---|---|
0 — PayU Token |
Get User Cards API (get_user_cards) |
Use card_token from Get User Cards response as store_card_token |
1 — Network Token |
Get Payment Instrument (get_payment_instrument) → Get Cryptogram / TAVV (get_payment_details) |
Use network_token from Cryptogram response as store_card_token, plus tavv, last4Digits in additional_info |
2 — Issuer Token |
Get Payment Instrument (get_payment_instrument) → Get Cryptogram / TAVV (get_payment_details) |
Use issuer_token.token_value from Cryptogram response as store_card_token, plus trMerchantId, tokenReferenceId, tokenBank, last4Digits in additional_info |
card_token, then call Get Cryptogram (TAVV) with that token to obtain the TAVV/cryptogram data needed for payment. For PayU Token, simply call Get User Cards API — the card_token in the response is your Store Card Token.
store_card_token from the Get User Cards API response. user_credentials is mandatory and must match the value used during card storage.
additional_info JSON is mandatory.
additional_info JSON must contain: trMerchantId, tokenReferenceId, tokenBank, last4Digits.
| Parameter | Description | Source |
|---|---|---|
store_card_token | Issuer token value | details.issuer_token.token_value from Cryptogram API |
ccexpmon | Issuer token expiry month | issuer_token.token_exp_mon |
ccexpyr | Issuer token expiry year | issuer_token.token_exp_yr |
additional_info.trMerchantId | Wibmo Merchant ID | details.wibmoMerchantId |
additional_info.tokenReferenceId | Token reference ID | details.token_refernce_id |
additional_info.tokenBank | Issuing bank name | e.g. HDFC |
additional_info.last4Digits | Last 4 digits of original card | details.card_no (last 4) |
details.card_no (last 4 chars)
After the payment API call, check binData.pureS2SSupported in the response to determine how the customer completes 3DS authentication:
This card supports Native OTP. You have two choices below to complete authentication. Pick whichever method you prefer.
This card/bank does not support native OTP. Only Pay on Bank Page (3DS Redirect) is available. The bank’s 3DS page will load below.
Choose how to complete 3DS authentication:
⏳ Waiting for payment response… Send a payment request in the previous step. The authentication options will appear here automatically.
ResponseHandler.php endpoint. The customer stays on your checkout page throughout — no redirects.
https://test.payu.in/ResponseHandler.php | Submit OTP| Parameter | Description | Value |
|---|---|---|
referenceId | Unique reference from payment response — auto-filled from metaData.referenceId | Auto-filled |
otp | OTP entered by the customer on your page | Test: 123456 |
data | Must include payuPureS2S flag | {"payuPureS2S":"1"} |
metaData.referenceId in the payment response123456
acsTemplate (base64-encoded HTML). When decoded and rendered, it auto-submits a form that redirects the customer to the bank’s 3DS page. After authentication, the bank redirects back to your surl/furl.
The bank’s 3DS authentication page is ready. Click the button below to open it in a new tab. After completing OTP on the bank page, you will be redirected to the callback page.
⚠ No ACS template received yet. This will load automatically after you send the payment request in the previous step.
The acsTemplate is a Base64-encoded HTML string. Decode it to get the bank redirect form.
// JavaScript – Decode Base64 acsTemplate
const acsTemplate = response.result.acsTemplate;
const decodedHtml = atob(acsTemplate);
// Open decoded HTML in popup window
const bankWindow = window.open('', 'BankAuth', 'width=800,height=600');
bankWindow.document.write(decodedHtml);
bankWindow.document.close();
Decoded HTML Structure:
<html><body>
<form name="payment_post" action="https://pgsim01.payu.in/initiate" method="post">
<input type="hidden" name="merchantName" value="PAYU">
<input type="hidden" name="txnAmount" value="1.00">
<input type="hidden" name="txnRefId" value="MANDATE_xxx">
<input type="hidden" name="ibibo_code" value="ICICENCC">
<!-- ... more hidden fields ... -->
</form>
<script>
window.onload = function() {
document.forms['payment_post'].submit(); // Auto-submits to bank
}
</script>
</body></html>
After a first-time payment, verify the transaction and save the card as a token using save_payment_instrument. For ongoing management, edit or delete tokens as needed.
Confirm the transaction status server-side. Always verify before trusting callback data. Supports verifying multiple transactions by passing pipe-separated txnid values.
https://test.payu.in/merchant/postserviceapplication/x-www-form-urlencodedsha512(key|verify_payment|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | verify_payment — fixed value for this API | verify_payment |
var1 | Mandatory | Transaction ID(s) — multiple txnids separated by pipe (|) | TXN_001 |
hash | Mandatory | sha512(key|verify_payment|var1|salt) | (computed) |
After a successful first-time payment, explicitly create a token by calling save_payment_instrument (also referred to as save_user_card). This returns the PayU reference ID and network/issuer tokens.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|save_payment_instrument|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | a4vGC2 |
command | Mandatory | Fixed value save_payment_instrument | save_payment_instrument |
var1 | Mandatory | User credentials: merchantKey:userId | a4vGC2:test1 |
var2 | Mandatory | Name/label for the card (card nickname) | My HDFC Visa |
var3 | Mandatory | PG value — payment gateway type | CC |
var4 | Mandatory | Bank code | CC |
var5 | Mandatory | Cardholder name | Test User |
var6 | Mandatory | Full card number (13–19 digits) | 5123456789012346 |
var7 | Mandatory | Expiry month (MM) | 05 |
var8 | Mandatory | Expiry year (YYYY) | 2030 |
var9 | Conditional | Network auth reference — mandatory for Rupay/Amex cards | — |
var10 | Conditional | AFA consent — mandatory for Visa/MC/Diners (true/false) | true |
var11 | Conditional | Card tokenization consent — mandatory for Visa/MC/Diners (true/false) | true |
hash | Mandatory | sha512(key|save_payment_instrument|var1|salt) | (computed) |
You must be PCI-DSS compliant to use Model 3 as you handle raw card details in API calls.
Remove a saved token when the customer revokes consent or the card expires. Use delete_payment_instrument (or delete_user_card) API.
https://test.payu.in/merchant/postservice.php?form=2application/x-www-form-urlencodedsha512(key|delete_payment_instrument|var1|salt)| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU | JPg****f |
command | Mandatory | delete_payment_instrument — fixed value for this API | delete_payment_instrument |
var1 | Mandatory | User credentials: merchantKey:userId | JPg****f:customer1 |
var2 | Mandatory | Card token (cardToken) to delete | abc123tokenxyz |
var3 | Optional | Network token value (if deleting specific network token) | — |
var4 | Optional | Issuer token value (if deleting specific issuer token) | — |
hash | Mandatory | sha512(key|delete_payment_instrument|var1|salt) | (computed) |
Decode and inspect the acsTemplate returned by PayU’s payment API for 3D Secure authentication.
acsTemplate?When you make a card payment via S2S (server-to-server), PayU returns an acsTemplate in the response. This is a base64-encoded HTML page that, when decoded and rendered in the browser, auto-submits a form to redirect the customer to the bank’s 3DS (3D Secure) authentication page where they enter their OTP.
_payment API callresult.acsTemplateYou send _payment request with card details. PayU processes and returns response with acsTemplate.
The acsTemplate is a base64-encoded HTML string. Decode it using atob() in JS or base64_decode() in PHP.
Write the decoded HTML to a new browser window or page. The HTML contains an auto-submitting form that redirects to the bank.
Customer enters OTP on the bank’s page. After authentication, the bank redirects back to your surl/furl.
Paste the raw acsTemplate value (base64 string) from the payment API response below.
// JavaScript — Decode and open in new window
var acsBase64 = response.result.acsTemplate;
// Step 1: Decode from Base64
var decodedHtml = atob(acsBase64);
// Step 2: Open in a new browser window/tab
var win = window.open('', '_blank');
win.document.open();
win.document.write(decodedHtml);
win.document.close();
// The HTML auto-submits a form → redirects to bank 3DS page
// PHP — Decode and render to browser
$acsBase64 = $response['result']['acsTemplate'];
// Step 1: Decode from Base64
$decodedHtml = base64_decode($acsBase64);
// Step 2: Output directly to browser (auto-submits to bank)
header('Content-Type: text/html; charset=UTF-8');
echo $decodedHtml;
exit;
# Python (Flask) — Decode and return as HTML response
import base64
from flask import Response
acs_base64 = response['result']['acsTemplate']
# Step 1: Decode from Base64
decoded_html = base64.b64decode(acs_base64).decode('utf-8')
# Step 2: Return as HTML response (auto-submits to bank)
return Response(decoded_html, content_type='text/html')
// Java (Spring Boot) — Decode and write to response
String acsBase64 = response.getResult().getAcsTemplate();
// Step 1: Decode from Base64
byte[] decodedBytes = Base64.getDecoder().decode(acsBase64);
String decodedHtml = new String(decodedBytes, StandardCharsets.UTF_8);
// Step 2: Write HTML to HttpServletResponse
httpResponse.setContentType("text/html;charset=UTF-8");
httpResponse.getWriter().write(decodedHtml);
httpResponse.getWriter().flush();
X-Frame-Options: DENY, blocking iframe embedding. Always use window.open() or render on a full page.<form> with a <script> that auto-submits. You do not need to manually submit anything.surl (success) or furl (failure). Ensure these are set correctly in the payment request.binData.pureS2SSupported = true, you can also use the Native OTP method (Submit OTP API) instead of rendering the ACS template. Both options work.acsTemplate is returned in S2S flows regardless of pureS2SSupported value. It’s the universal fallback for 3DS authentication.Select the Net Banking product you want to integrate. Each card walks you through the complete flow — from initiation to verification.
Accept single Net Banking payments. Customer selects bank, authenticates via OTP, and completes payment.
Register recurring payment mandates via eNACH. Perfect for subscriptions, EMIs, SIPs, and insurance premiums.
Validate payments originate from a specific bank account. Required for mutual funds, stock trading, and KYC flows.
Hash generator, bank codes reference, and active bank status checker for Net Banking integration.
Use bankcode=TESTPGNB (Test Bank) for sandbox testing. Click "NB One-Time Payment" above to try it now.
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | Merchant salt for hash generation (never sent in request) | hKvGJP28d2... |
txnid | Mandatory | Unique transaction ID (max 25 chars) | NB_unique123 |
amount | Mandatory | Transaction amount in INR | 100.00 |
productinfo | Mandatory | Product/service description | Test Product |
firstname | Mandatory | Customer's first name | John |
email | Mandatory | Customer's email address | john@email.com |
phone | Mandatory | Customer's phone number | 9876543210 |
surl | Mandatory | Success callback URL | https://yoursite.com/success |
furl | Mandatory | Failure callback URL | https://yoursite.com/failure |
hash | Mandatory | SHA-512 payment hash (auto-computed) | (computed) |
pg | Mandatory | Payment gateway type — fixed NB | NB |
bankcode | Mandatory | Bank code from getNetbankingStatus API | TESTPGNB |
txn_s2s_flow | Mandatory | S2S flow identifier — fixed 4 | 4 |
s2s_client_ip | Conditional | Source IP of the customer. Required for S2S flow | 10.200.12.12 |
s2s_device_info | Conditional | Customer agent's device information. Required for S2S flow | Mozilla/5.0 |
udf1 | Optional | User-defined field 1 | |
udf2 | Optional | User-defined field 2 | |
udf3 | Optional | User-defined field 3 | |
udf4 | Optional | User-defined field 4 | |
udf5 | Optional | User-defined field 5 |
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
Example:
sha512(a4vGC2|NB_unique123|100.00|Test Product|John|john@email.com|||||||||||YourSaltHere)
When PayU returns the acsTemplate, you must:
acsTemplate valueThis demonstrates how a merchant-hosted checkout presents the bank selection UI to customers. In a seamless (S2S) integration, you build this page — the customer picks their bank here, and you pass the corresponding bankcode to the _payment API.
1. Fetch live bank availability using getNetbankingStatus API → 2. Render available banks as a selection grid → 3. Customer selects a bank → 4. Pass bankcode in the _payment API call
AXIBHDFBICIBSBIBYESBKTKBINDBCITIPNBBBKIDUNIBCABBBARBIOBAIDIBFDRLSVCBDCBBTESTPGNBNo banks found matching your search.
In your production checkout, you would:
// 1. Fetch available banks from PayU
fetch('/proxy.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
endpoint: 'postservice',
method: 'POST',
params: { key: merchantKey, command: 'getNetbankingStatus', var1: '', hash: hash }
})
})
.then(res => res.json())
.then(data => {
// 2. Render bank grid from response
const banks = data.response; // array of bank objects
banks.forEach(bank => {
// Create clickable bank card with bank.bankcode, bank.title, bank.status
});
});
// 3. On bank selection, pass bankcode to _payment API
function onBankSelected(bankcode) {
paymentPayload.pg = 'NB';
paymentPayload.bankcode = bankcode;
// Send _payment request with the selected bank...
}
Initiate a Net Banking payment using the _payment API with pg=NB and the appropriate bank code. The response contains an acsTemplate (base64 HTML) that you decode and render to redirect the customer to their bank's login page.
getNetbankingStatus API to get active bank codesCall getNetbankingStatus API to fetch available banks and their codes.
Display available banks and let customer choose their preferred bank.
Use formula: sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
Send payment request with pg=NB, bankcode, and txn_s2s_flow=4 for JSON response.
Base64 decode the acsTemplate and render it to redirect customer to bank.
POST https://test.payu.in/_payment (Test) | POST https://secure.payu.in/_payment (Production)
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | Merchant salt for hash generation (never sent in request) | hKvGJP28d2... |
txnid | Mandatory | Unique transaction ID (max 25 chars) | NB_1234567890 |
amount | Mandatory | Transaction amount in INR | 100.00 |
productinfo | Mandatory | Product/service description | Test Product |
firstname | Mandatory | Customer's first name | John |
email | Mandatory | Customer's email address | john@example.com |
phone | Mandatory | Customer's phone number | 9876543210 |
surl | Mandatory | Success callback URL | https://yoursite.com/success |
furl | Mandatory | Failure callback URL | https://yoursite.com/failure |
hash | Mandatory | SHA-512 payment hash (auto-computed) | (computed) |
pg | Mandatory | Payment gateway type — fixed NB | NB |
bankcode | Mandatory | Bank code from getNetbankingStatus API | TESTPGNB |
txn_s2s_flow | Mandatory | S2S flow identifier — fixed 4 | 4 |
s2s_client_ip | Conditional | Source IP of the customer. Required for S2S flow | 10.200.12.12 |
s2s_device_info | Conditional | Customer agent's device information | Mozilla/5.0 |
udf1 | Optional | User-defined field 1 | |
udf2 | Optional | User-defined field 2 | |
udf3 | Optional | User-defined field 3 | |
udf4 | Optional | User-defined field 4 | |
udf5 | Optional | User-defined field 5 |
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
Example:
sha512(a4vGC2|NB_123456|100.00|Test Product|John|john@example.com|||||||||||YourSaltHere)
{
"metaData": {
"message": null,
"referenceId": "abc123...",
"statusCode": null,
"txnId": "NB_123456",
"txnStatus": "pending",
"unmappedStatus": "pending"
},
"result": {
"acsTemplate": "PGh0bWw+Li4uPC9odG1sPg==", // Base64 encoded bank redirect page
"otpPostUrl": "https://test.payu.in/ResponseHandler.php"
}
}
Your payment has been completed successfully
Payment authenticity confirmed. Hash matches perfectly.
All callback data has been auto-filled in the Hash Verification Utility.
Just enter your SALT to recalculate and verify the hash manually.
{}
POST https://test.payu.in/_payment (Test) | POST https://secure.payu.in/_payment (Production)
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | String — Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | String — Merchant salt for hash generation (never sent in request) | hKvGJP28d2... |
txnid | Mandatory | String — Unique transaction ID (max 25 chars) | NB_1234567890 |
amount | Mandatory | String — Transaction amount in INR | 100.00 |
productinfo | Mandatory | String — Product/service description | Test Product |
firstname | Mandatory | String — Customer’s first name | John |
email | Mandatory | String — Customer’s email address | john@example.com |
phone | Mandatory | String — Customer’s phone number | 9876543210 |
surl | Mandatory | String — Success callback URL | https://yoursite.com/success |
furl | Mandatory | String — Failure callback URL | https://yoursite.com/failure |
hash | Mandatory | String — SHA-512 payment hash (auto-computed) | (computed) |
pg | Mandatory | String — Payment gateway type — fixed NB | NB |
bankcode | Mandatory | String — Bank code from getNetbankingStatus API | TESTPGNB |
txn_s2s_flow | Mandatory | String — S2S flow identifier — fixed 4 | 4 |
s2s_client_ip | Conditional | String — Source IP of the customer (required for S2S) | 10.200.12.12 |
s2s_device_info | Conditional | String — Customer agent’s device information | Mozilla/5.0 |
udf1 | Optional | String — User-defined field 1 | |
udf2 | Optional | String — User-defined field 2 | |
udf3 | Optional | String — User-defined field 3 | |
udf4 | Optional | String — User-defined field 4 | |
udf5 | Optional | String — User-defined field 5 |
| Parameter | Description | Example |
|---|---|---|
metaData.txnId | String — Your original transaction ID | NB_1234567890 |
metaData.txnStatus | String — Transaction status — pending means awaiting bank auth | pending |
metaData.unmappedStatus | String — Raw status from payment gateway | pending |
metaData.referenceId | String — PayU internal reference for this transaction | abc123... |
result.acsTemplate | String — Base64-encoded HTML containing auto-submit form to redirect customer to bank | PGh0bWw+Li4u... |
result.otpPostUrl | String — PayU response handler URL (used internally by bank redirect) | https://test.payu.in/ResponseHandler.php |
| Parameter | Description | Example |
|---|---|---|
status | Transaction status — success or failure | success |
mihpayid | PayU’s unique transaction reference ID | 10731087875 |
mode | Payment mode — NB for Net Banking | NB |
txnid | Your original transaction ID | NB_1234567890 |
amount | Transaction amount | 100.00 |
bankcode | Bank code used for the payment | TESTPGNB |
bank_ref_num | Bank reference number | YESB00000... |
unmappedstatus | Detailed status — captured for successful payment | captured |
field9 | Payment gateway response message | Transaction Completed Successfully |
After calling the _payment API, you receive an acsTemplate (base64-encoded HTML). Decode and render this to redirect the customer to their bank's login page for authentication.
// After receiving _payment API response
const response = await payuApiResponse;
if (response.result && response.result.acsTemplate) {
// Decode base64 acsTemplate
const html = atob(response.result.acsTemplate);
// Option 1: Open in new window
const win = window.open('', '_blank');
win.document.write(html);
win.document.close();
// Option 2: Redirect in same window
// document.open();
// document.write(html);
// document.close();
}
<?php
$response = json_decode($payuResponse, true);
if (isset($response['result']['acsTemplate'])) {
$html = base64_decode($response['result']['acsTemplate']);
echo $html;
exit;
}
?>
After the customer completes authentication at the bank:
surl (success) or furl (failure) with POST parametersverify_payment API (recommended)The test bank simulator (TESTPGNB) auto-completes the payment instantly. You may see "Transaction is already in terminal state" — this is normal and means the payment was processed successfully.
After the customer completes payment on the bank page and is redirected back, use the verify_payment API to confirm the transaction status. This is the authoritative source of payment status and should always be used to determine the final state.
txnid from the payment you want to verifyPOST https://test.payu.in/merchant/postservice.php?form=2
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
command | Mandatory | API command — fixed verify_payment | verify_payment |
var1 | Mandatory | Transaction ID to verify | NB_123456 |
hash | Mandatory | SHA-512 hash (auto-computed from key, command, var1, salt) | (computed) |
sha512(key|command|var1|salt)
Example:
sha512(a4vGC2|verify_payment|NB_123456|YourSaltHere)
{
"status": 1,
"msg": "Transaction Fetched Successfully",
"transaction_details": {
"NB_123456": {
"mihpayid": "403993715525331373",
"mode": "NB",
"status": "success",
"unmappedstatus": "captured",
"key": "a4vGC2",
"txnid": "NB_123456",
"amount": "100.00",
"bank_ref_num": "450699821592111537",
"bankcode": "TESTPGNB",
"error": "E000",
"error_Message": "No Error"
}
}
}
Use the cancel_refund_transaction API to initiate a refund for a successful Net Banking transaction. You'll need the mihpayid from the original transaction response.
POST https://test.payu.in/merchant/postservice.php?form=2
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
command | Mandatory | API command — fixed cancel_refund_transaction | cancel_refund_transaction |
var1 | Mandatory | PayU transaction ID (mihpayid) | 403993715537135556 |
var2 | Mandatory | Unique token/reference ID for refund | REFUND_123456 |
var3 | Mandatory | Refund amount (can be partial) | 500.00 |
hash | Mandatory | SHA-512 hash (auto-computed from key, command, var1, salt) | (computed) |
sha512(key|command|var1|salt)
Example:
sha512(a4vGC2|cancel_refund_transaction|403993715537135556|YourSaltHere)
{
"status": 1,
"msg": "Refund Request Queued",
"request_id": "10825083",
"bank_ref_num": null,
"mihpayid": "403993715537135556",
"refund_amount": "500.00"
}
check_action_status API to track refund statusvar3After initiating a refund, use check_action_status to track its progress.
Split Refund allows you to refund a split payment transaction where the original payment was distributed among multiple merchants/aggregators. You can refund the entire split amount or partial amounts to specific split recipients.
POST https://test.payu.in/merchant/postservice.php?form=2
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
command | Mandatory | API command — fixed cancel_refund_transaction | cancel_refund_transaction |
var1 | Mandatory | PayU transaction ID (mihpayid) | 403993715537135556 |
var2 | Mandatory | Unique token/reference ID for refund | SPLIT_REFUND_123456 |
var3 | Mandatory | Refund amount | 500.00 |
var5 | Mandatory | Split refund details JSON | {"splitInfo":[...]} |
hash | Mandatory | SHA-512 hash (auto-computed from key, command, var1, salt) | (computed) |
sha512(key|command|var1|salt)
Example:
sha512(a4vGC2|cancel_refund_transaction|403993715537135556|YourSaltHere)
{
"splitInfo": [
{
"merchantId": "SPLIT_MERCHANT_1",
"amount": "300.00"
},
{
"merchantId": "SPLIT_MERCHANT_2",
"amount": "200.00"
}
]
}
{
"status": 1,
"msg": "Refund Request Queued",
"request_id": "10825084",
"bank_ref_num": null,
"mihpayid": "403993715537135556",
"refund_amount": "500.00",
"split_refund_status": "queued"
}
check_action_status API to track split refund statusTPV ensures that the payment originates from a specific bank account belonging to the customer. The merchant provides beneficiary details (account number + IFSC), and PayU validates that the paying account matches before processing. Used in mutual funds, stock trading, insurance, and regulated financial products.
POST https://test.payu.in/_payment (Test) | POST https://secure.payu.in/_payment (Production)
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | Merchant salt for hash generation (never sent in request) | hKvGJP28d2... |
txnid | Mandatory | Unique transaction ID | TPV_123456 |
amount | Mandatory | Transaction amount in INR | 100.00 |
productinfo | Mandatory | Product/service description | Mutual Fund SIP |
firstname | Mandatory | Customer's first name | John |
email | Mandatory | Customer's email address | john@example.com |
phone | Mandatory | Customer's phone number | 9876543210 |
surl | Mandatory | Success callback URL | https://yoursite.com/success |
furl | Mandatory | Failure callback URL | https://yoursite.com/failure |
hash | Mandatory | SHA-512 payment hash (auto-computed) | (computed) |
pg | Mandatory | Payment gateway type — fixed NB | NB |
bankcode | Mandatory | TPV-enabled bank code | SBITPV |
txn_s2s_flow | Mandatory | S2S flow identifier — fixed 4 | 4 |
api_version | Mandatory | API version for TPV — fixed 6 | 6 |
beneficiarydetail | Mandatory | JSON with beneficiary account details | {"beneficiaryAccountNumber":"..."} |
s2s_client_ip | Conditional | Source IP of the customer. Required for S2S flow | 10.200.12.12 |
s2s_device_info | Conditional | Customer agent's device information | Mozilla/5.0 |
udf1-udf5 | Optional | User-defined fields |
| Field | Required | Description | Example |
|---|---|---|---|
beneficiaryAccountNumber | Mandatory | Customer's bank account number | 9876543210123456789 |
ifscCode | Mandatory | Bank IFSC code (11 characters) | SBIN0001234 |
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||beneficiarydetail|salt)
Note: 12 pipes between email and beneficiarydetail for api_version=6
Example:
sha512(a4vGC2|TPV_123|100.00|Mutual Fund|John|john@email.com||||||||||||{"beneficiaryAccountNumber":"9876...","ifscCode":"SBIN..."}|YourSalt)
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||beneficiarydetail|SALT)
// beneficiarydetail is a JSON string:
// {"beneficiaryAccountNumber":"1234567890","ifscCode":"SBIN0001234"}
// Key parameters for TPV:
api_version = 6
beneficiarydetail = JSON.stringify({beneficiaryAccountNumber, ifscCode})
Only showing TPV-enabled banks. Use the ibibo_code as bankcode in your payment request.
| ibibo_code | Bank Name | Status | Action |
|---|---|---|---|
AXNBTPV | Axis Bank TPV | ▲ Up | |
HABOROTPV | Bank of Baroda TPV | ▲ Up | |
BOITPV | Bank of India TPV | ▲ Up | |
BOMTPV | Bank of Maharashtra TPV | ▲ Up | |
ABOROTPV | Canara Bank TPV | ▲ Up | |
CBOTPV | Central Bank of India TPV | ▲ Up | |
CUBTPV | City Union Bank TPV | ▲ Up | |
COBTPV | Cosmos Bank TPV | ▲ Up | |
DCBTPV | DCB Bank TPV | ▲ Up | |
DLBTPV | Dhanlaxmi Bank TPV | ▲ Up | |
FEDTPV | Federal Bank TPV | ▲ Up | |
HABOROTPV | HDFC Bank TPV | ▲ Up | |
IKIBTPV | ICICI Bank TPV | ▲ Up | |
IDBTPV | IDBI Bank TPV | ▲ Up | |
IDFCTPV | IDFC First Bank TPV | ▲ Up | |
INBTPV | Indian Bank TPV | ▲ Up | |
INDUTPV | IndusInd Bank TPV | ▲ Up | |
IOBTPV | Indian Overseas Bank TPV | ▲ Up | |
JKBTPV | J&K Bank TPV | ▲ Up | |
KBLTPV | Karnataka Bank TPV | ▲ Up | |
KVBTPV | Karur Vysya Bank TPV | ▲ Up | |
KOTATPV | Kotak Mahindra Bank TPV | ▲ Up | |
PNBTPV | Punjab National Bank TPV | ▲ Up | |
RBLTPV | RBL Bank TPV | ▲ Up | |
SBTPV | South Indian Bank TPV | ▲ Up | |
SBINBTPV | State Bank of India TPV | ▲ Up | |
TMBTPV | Tamilnad Mercantile Bank TPV | ▲ Up | |
UBOTPV | Union Bank of India TPV | ▲ Up | |
UCOTPV | UCO Bank TPV | ▲ Up | |
YESBKTPV | Yes Bank TPV | ▲ Up |
Note: You can add up to 4 beneficiary accounts. Multiple accounts should be separated by pipe (|) symbol in the same order.
Example:
Account: 919013353419388|919013353419387
IFSC: UTIB9992478|UTIB9992478
The acsTemplate is a Base64-encoded HTML string that contains a self-submitting form. When decoded and rendered in the browser, it automatically redirects the customer to the bank's authentication page.
| Field | Description |
|---|---|
metaData.txnStatus | "pending" — Transaction awaits bank authentication |
metaData.txnId | Your transaction ID for tracking |
metaData.referenceId | PayU's internal reference for this transaction |
result.acsTemplate | Base64 encoded HTML — Must be decoded and rendered to redirect user to bank |
result.otpPostUrl | PayU's response handler URL (used internally) |
// Step 1: Decode the Base64 string
const decodedHtml = atob(response.result.acsTemplate);
// Step 2: Open in a new popup window (Recommended)
const bankWindow = window.open('', 'BankAuth', 'width=800,height=600');
bankWindow.document.write(decodedHtml);
bankWindow.document.close();
// The decoded HTML contains a form that auto-submits:
// <form action="https://bank-url/..." method="post">
// <input name="txnAmount" value="100.00">
// <input name="txnRefId" value="TPV_xxx">
// ...
// </form>
// <script>document.forms[0].submit();</script>
surl (success) or furl (failure)verify_payment API to confirm final statusbeneficiarydetail JSON must be included in the hash calculationapi_version=6 for beneficiary detail supportPOST https://test.payu.in/_payment (Test) | POST https://secure.payu.in/_payment (Production)
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | String — Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | String — Merchant salt for hash generation (never sent in request) | hKvGJP28d2... |
txnid | Mandatory | String — Unique transaction ID | TPV_123456 |
amount | Mandatory | String — Transaction amount in INR | 100.00 |
productinfo | Mandatory | String — Product/service description | Mutual Fund SIP |
firstname | Mandatory | String — Customer’s first name | John |
email | Mandatory | String — Customer’s email address | john@example.com |
phone | Mandatory | String — Customer’s phone number | 9876543210 |
surl | Mandatory | String — Success callback URL | https://yoursite.com/success |
furl | Mandatory | String — Failure callback URL | https://yoursite.com/failure |
hash | Mandatory | String — SHA-512 payment hash (auto-computed) | (computed) |
pg | Mandatory | String — Payment gateway type — fixed NB | NB |
bankcode | Mandatory | String — TPV-enabled bank code | SBITPV |
txn_s2s_flow | Mandatory | String — S2S flow identifier — fixed 4 | 4 |
api_version | Mandatory | String — API version for TPV — fixed 6 | 6 |
beneficiarydetail | Mandatory | String — JSON with beneficiary account details | {"beneficiaryAccountNumber":"..."} |
s2s_client_ip | Conditional | String — Source IP of the customer (required for S2S) | 10.200.12.12 |
s2s_device_info | Conditional | String — Customer agent’s device information | Mozilla/5.0 |
udf1-udf5 | Optional | String — User-defined fields |
| Parameter | Description | Example |
|---|---|---|
metaData.txnId | String — Your original transaction ID | TPV_1775739737886 |
metaData.txnStatus | String — Transaction status — pending means awaiting bank auth | pending |
metaData.unmappedStatus | String — Raw status from payment gateway | pending |
metaData.referenceId | String — PayU internal reference for this transaction | cb2ccfe8ad1ea77... |
result.acsTemplate | String — Base64-encoded HTML containing auto-submit form to redirect customer to bank | PGh0bWw+PGJv... |
result.otpPostUrl | String — PayU response handler URL (used internally by bank redirect) | https://test.payu.in/ResponseHandler.php |
| Parameter | Description | Example |
|---|---|---|
status | Transaction status — success or failure | success |
mihpayid | PayU’s unique transaction reference ID | 10731087875 |
mode | Payment mode — NB for Net Banking TPV | NB |
txnid | Your original transaction ID | TPV_1775739737886 |
amount | Transaction amount | 100.00 |
bankcode | Bank code used for the TPV payment | AXNBTPV |
bank_ref_num | Bank reference number | YESB00000... |
unmappedstatus | Detailed status — captured for successful TPV | captured |
field9 | Payment gateway response message | Transaction Completed Successfully |
After calling the TPV _payment API, you receive an acsTemplate. The bank will validate the beneficiary account details (beneficiarydetail) during authentication.
During bank authentication, the bank verifies that:
beneficiaryAccountNumberIf the customer tries to pay from a different account than specified in beneficiarydetail, the bank will reject the payment. This is the core security feature of TPV.
The acsTemplate is a Base64-encoded HTML string that contains a self-submitting form. When decoded and rendered in the browser, it automatically redirects the customer to the bank's authentication page.
{
"metaData": {
"message": null,
"referenceId": "cb2ccfe8ad1ea77a30f33dfb68055a0af363b...",
"statusCode": null,
"txnId": "TPV_1775739737886",
"txnStatus": "pending", // Transaction is pending bank auth
"unmappedStatus": "pending"
},
"result": {
"acsTemplate": "PGh0bWw+PGJvZHk+PGZvcm0gbmFtZT0i...", // Base64 encoded HTML
"otpPostUrl": "https://test.payu.in/ResponseHandler.php"
}
}
// Method 1: Using atob() - Browser native
const decodedHtml = atob(response.result.acsTemplate);
// Method 2: Using Buffer - Node.js
const decodedHtml = Buffer.from(response.result.acsTemplate, 'base64').toString('utf-8');
// The decoded HTML looks like this:
<html><body>
<form name="payment_post" id="payment_post"
action="https://pgsim01.payu.in/initiate" method="post">
<input type="hidden" name="merchantName" value="PAYU">
<input type="hidden" name="merchantCode" value="SlEscuJA98">
<input type="hidden" name="txnAmount" value="100.00">
<input type="hidden" name="txnRefId" value="TPV_1775739737886">
<input type="hidden" name="ibibo_code" value="AXNBTPV">
<!-- ... more hidden fields ... -->
</form>
<script>
window.onload = function() {
document.forms['payment_post'].submit(); // Auto-submits to bank
}
</script>
</body></html>
// Option 1: Open in a new popup window (Recommended for S2S)
const bankWindow = window.open('', 'BankAuth', 'width=800,height=600');
const decodedHtml = atob(response.result.acsTemplate);
bankWindow.document.write(decodedHtml);
bankWindow.document.close();
// Option 2: Redirect current page (if full page redirect is acceptable)
document.open();
document.write(atob(response.result.acsTemplate));
document.close();
// Option 3: Render in an iframe (for embedded experience)
const iframe = document.getElementById('bankFrame');
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(atob(response.result.acsTemplate));
iframe.contentWindow.document.close();
txnStatus: "pending" — Transaction awaits bank authenticationacsTemplate — Must be decoded (Base64) and rendered in browserotpPostUrl — PayU's handler URL (used internally by bank redirect)surl or furlPOST https://test.payu.in/merchant/postservice.php?form=2
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | String — Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | String — Merchant salt used for hash generation (never sent in request) | mGHSxpD2iB... |
command | Mandatory | String — API command — fixed verify_payment | verify_payment |
var1 | Mandatory | String — Transaction ID (txnid) used during TPV payment initiation | TPV_1775739737886 |
hash | Mandatory | String — SHA-512 hash — sha512(key|verify_payment|var1|salt) | (computed) |
| Parameter | Description | Example |
|---|---|---|
status | Transaction status — success or failure | success |
mihpayid | PayU’s unique transaction reference ID | 10731087875 |
mode | Payment mode — NB for Net Banking TPV | NB |
txnid | Your original transaction ID | TPV_1775739737886 |
amount | Transaction amount | 100.00 |
unmappedstatus | Detailed status — captured for successful TPV payment | captured |
bankcode | Bank code confirms the bank used matches expected bank | AXNBTPV |
bank_ref_num | Bank reference number for the transaction | YESB00000... |
firstname | Customer first name | Test |
email | Customer email | test@example.com |
phone | Customer phone number | 9876543210 |
field9 | Payment gateway response message | Transaction Completed Successfully |
After the customer completes bank authentication, use verify_payment to confirm the transaction status. For TPV transactions, the response includes additional validation details confirming that the beneficiary account was verified.
sha512(key|command|var1|salt)
sha512(merchantKey|verify_payment|txnid|merchantSalt)
status — "success" means payment completed and account validatedunmappedstatus — "captured" for successful TPV paymentmode — Should be "NB" for Net Banking TPVbankcode — Confirms the bank used matches the expected bankPACB allows you to pre-authorize (block) funds in the customer's bank account without immediate debit. You can later capture the blocked amount fully or partially.
Block funds once and capture the full or partial amount. Ideal for single transactions where final amount may vary.
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
// Key parameter for PACB:
pre_authorize=1 // Enable pre-authorization mode
POST https://test.payu.in/_payment (Test) | POST https://secure.payu.in/_payment (Production)
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | Merchant salt for hash generation (never sent in request) | hKvGJP28d2... |
txnid | Mandatory | Unique transaction ID | PACB_123456 |
amount | Mandatory | Amount to pre-authorize (block) | 500.00 |
productinfo | Mandatory | Product/service description | Hotel Booking Deposit |
firstname | Mandatory | Customer's first name | John |
email | Mandatory | Customer's email address | john@example.com |
phone | Mandatory | Customer's phone number | 9876543210 |
surl | Mandatory | Success callback URL | https://yoursite.com/success |
furl | Mandatory | Failure callback URL | https://yoursite.com/failure |
hash | Mandatory | SHA-512 payment hash (auto-computed) | (computed) |
pg | Mandatory | Payment gateway type — fixed NB | NB |
bankcode | Mandatory | Bank code from getNetbankingStatus API | TESTPGNB |
txn_s2s_flow | Mandatory | S2S flow identifier — fixed 4 | 4 |
pre_authorize | Mandatory | Enable pre-authorization — fixed 1 | 1 |
api_version | Mandatory | API version for PACB — fixed 6 | 6 |
s2s_client_ip | Conditional | Source IP of the customer. Required for S2S flow | 10.200.12.12 |
s2s_device_info | Conditional | Customer's device/browser info | Mozilla/5.0... |
udf1-udf5 | Optional | User-defined fields |
{
"metaData": {
"message": null,
"referenceId": "abc123...",
"txnId": "PACB_123456",
"txnStatus": "pending",
"unmappedStatus": "pending" // After bank auth: "auth" = funds blocked
},
"result": {
"acsTemplate": "PGh0bWw+Li4uPC9odG1sPg==",
"mihpayid": "403993715537135556" // Save for capture_transaction
}
}
Select your merchant category to understand which parameters are required for your use case:
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||SALT)
Physical Goods (PACB-Import): Include Import/Export Code & Airway Bill Number for goods imports.
udf_params parameter: {"udf7":"value", "udf8":"value"}
LRS (Liberalised Remittance Scheme) parameters for cross-border payments. Required for Travel & Education merchants only. NOT required for Digital Services or Physical Goods (PACB-Import only).
Setup recurring pre-authorizations for subscription-based services. Block and capture funds on a scheduled basis.
| One-Time: | Single pre-auth → Single capture |
| Subscription: | Mandate registration → Recurring pre-auth → Scheduled captures |
POST https://test.payu.in/_payment
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key | a4vGC2 |
txnid | Mandatory | Unique transaction ID | PACB_SUB_123 |
amount | Mandatory | Amount to pre-authorize | 1000.00 |
pg | Mandatory | Payment gateway — fixed NB | NB |
bankcode | Mandatory | Bank code | TESTPGNB |
pre_authorize | Mandatory | Enable pre-auth — fixed 1 | 1 |
si | Mandatory | Standing instruction — fixed 1 | 1 |
si_details | Mandatory | JSON with subscription parameters | {"billingAmount":"1000",...} |
api_version | Mandatory | API version — fixed 7 | 7 |
hash | Mandatory | SHA-512 hash | (computed) |
{
"billingAmount": "1000.00",
"billingCurrency": "INR",
"billingCycle": "MONTHLY",
"billingInterval": 1,
"paymentStartDate": "2026-05-01",
"paymentEndDate": "2027-04-30",
"multiCapture": "Y" // Enable multi-capture per cycle
}
mihpayid from response - you'll need it for captureAfter calling the PACB _payment API with pre_authorize=1, the customer completes bank authentication. The funds are then blocked (not debited) in their account.
| Regular Payment: | unmappedstatus = captured (funds debited) |
| PACB Pre-Auth: | unmappedstatus = auth (funds blocked) |
Before capturing funds, verify the pre-authorization was successful. Use verify_payment API and check that unmappedstatus is "auth".
status = "success"unmappedstatus = "auth"mihpayid = (save this for capture)This means PACB is not enabled on your account. The funds were immediately debited instead of blocked. Contact your PayU KAM to enable PACB.
unmappedstatus must be "auth".
If it shows "captured", the funds were already debited and capture will fail with
"Delayed capture not allowed".
After a successful pre-authorization, use the capture_transaction API to capture (debit) the blocked funds. You can capture the full amount or a partial amount.
POST https://test.payu.in/merchant/postservice.php?form=2
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
command | Mandatory | API command — fixed capture_transaction | capture_transaction |
var1 | Mandatory | PayU transaction ID (mihpayid) | 403993715537135556 |
var2 | Mandatory | Unique capture request ID | CAP_123456 |
var3 | Mandatory | Amount to capture (can be partial) | 500.00 |
hash | Mandatory | SHA-512 hash (auto-computed from key, command, var1, salt) | (computed) |
sha512(key|command|var1|salt)
Example:
sha512(a4vGC2|capture_transaction|403993715537135556|YourSaltHere)
{
"status": 1,
"msg": "Transaction captured successfully",
"mihpayid": "403993715537135556",
"bank_ref_num": "450699821592111537",
"captured_amount": "500.00",
"original_amount": "500.00"
}
POST https://test.payu.in/_payment (Test) | POST https://secure.payu.in/_payment (Production)
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | String — Merchant key provided by PayU during onboarding | a4vGC2 |
txnid | Mandatory | String — Unique transaction ID generated by the merchant. PayU rejects duplicates. | MANDATE_1713200000 |
amount | Mandatory | String — Transaction amount. For eNACH, use 1.00 (actual billing amount is in si_details). | 1.00 |
productinfo | Mandatory | String — Brief product description (max 100 chars) | SIP Investment |
firstname | Mandatory | String — Customer first name (max 60 chars) | Test |
lastname | Mandatory | String — Customer last name (max 60 chars) | User |
email | Mandatory | String — Customer email address (max 50 chars) | test@example.com |
phone | Mandatory | String — Customer phone number | 9876543210 |
surl | Mandatory | String — Success callback URL | https://yoursite.com/callback.php |
furl | Mandatory | String — Failure callback URL | https://yoursite.com/callback.php |
hash | Mandatory | String — SHA-512 payment hash (auto-computed) | (computed) |
pg | Mandatory | String — Payment gateway type — fixed ENACH | ENACH |
bankcode | Mandatory | String — eNACH bank code from getNetbankingStatus API | ICICENCC |
si | Mandatory | String — Must be 1 to enable Standing Instruction / Recurring Payment | 1 |
si_details | Mandatory | String — JSON with billing cycle details (see si_details breakdown below) | (see below) |
beneficiarydetail | Mandatory | String — JSON with beneficiary bank account details (see beneficiarydetail breakdown below) | (see below) |
api_version | Mandatory | String — API version. Must be 7 so si_details is included in hash | 7 |
txn_s2s_flow | Mandatory | Integer — S2S flow identifier — fixed 4 | 4 |
free_trial | Optional | String — Enable free trial. When set to 1, a zero-value auth is performed to register the mandate without charging the customer. | 1 |
udf1 | Optional | String — User-defined field 1 | |
udf2 | Optional | String — User-defined field 2 | |
udf3 | Optional | String — User-defined field 3 | |
udf4 | Optional | String — User-defined field 4 | |
udf5 | Optional | String — User-defined field 5 |
| Field | Required | Description | Example |
|---|---|---|---|
billingAmount | Mandatory | String — Maximum amount for each recurring debit | 1000.00 |
billingCurrency | Mandatory | String — Currency — must be INR | INR |
billingCycle | Mandatory | String — Billing frequency: DAILY, WEEKLY, MONTHLY, YEARLY, or ADHOC | MONTHLY |
billingInterval | Mandatory | Integer — Coupled with billingCycle. e.g. MONTHLY & 3 = charge every 3 months | 1 |
paymentStartDate | Mandatory | String — Mandate start date in YYYY-MM-DD. For eNACH, must be tomorrow or later. | 2026-04-16 |
paymentEndDate | Mandatory | String — Mandate end date in YYYY-MM-DD | 2027-04-16 |
| Field | Required | Description | Example |
|---|---|---|---|
beneficiaryName | Mandatory | String — Account holder name as per bank records | Test User |
beneficiaryAccountNumber | Mandatory | String — Bank account number of the customer | 1234567890123456 |
beneficiaryAccountType | Mandatory | String — Account type: SAVINGS or CURRENT | SAVINGS |
beneficiaryIfscCode | Mandatory | String — 11-digit IFSC code of the customer’s bank branch | ICIC0001234 |
Register recurring payment mandates via eNACH (electronic National Automated Clearing House) for Net Banking. The customer authorizes a standing instruction for future debits from their bank account.
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|SALT)
// Note: 11 pipes between email and si_details, then si_details, then salt
// si_details structure:
{
"billingAmount": "1000.00",
"billingCurrency": "INR",
"billingCycle": "MONTHLY",
"billingInterval": 1,
"paymentStartDate": "2026-04-06",
"paymentEndDate": "2027-04-06"
}
// beneficiarydetail structure (MANDATORY for Net Banking):
{
"beneficiaryName": "Customer Name",
"beneficiaryAccountNumber": "1234567890",
"beneficiaryAccountType": "SAVINGS",
"beneficiaryIfscCode": "ICIC0001234"
}
The acsTemplate has been received. Click below to open the bank authentication page.
🔐 ACS Template Decode Guide
The acsTemplate is a Base64-encoded HTML string. Decode it to get the bank redirect form.
// JavaScript - Decode Base64 acsTemplate
const acsTemplate = response.result.acsTemplate;
const decodedHtml = atob(acsTemplate);
// Open decoded HTML in popup window
const bankWindow = window.open('', 'BankAuth', 'width=800,height=600');
bankWindow.document.write(decodedHtml);
bankWindow.document.close();
Decoded HTML Structure:
<html><body>
<form name="payment_post" action="https://pgsim01.payu.in/initiate" method="post">
<input type="hidden" name="merchantName" value="PAYU">
<input type="hidden" name="txnAmount" value="1.00">
<input type="hidden" name="txnRefId" value="MANDATE_xxx">
<input type="hidden" name="ibibo_code" value="ICICENCC">
<!-- ... more hidden fields ... -->
</form>
<script>
window.onload = function() {
document.forms['payment_post'].submit(); // Auto-submits to bank
}
</script>
</body></html>
mihpayid from callback becomes your authpayuidexecute_si APIPOST https://test.payu.in/merchant/postservice.php?form=2
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | String — Merchant key provided by PayU during onboarding | a4vGC2 |
salt | Mandatory | String — Merchant salt used for hash generation (never sent in request) | mGHSxpD2iB... |
command | Mandatory | String — API command — fixed verify_payment | verify_payment |
var1 | Mandatory | String — Transaction ID (txnid) used during mandate registration in Step 1 | MANDATE_1713200000 |
hash | Mandatory | String — SHA-512 hash — sha512(key|verify_payment|var1|salt) | (computed) |
| Parameter | Description | Example |
|---|---|---|
status | Transaction status — success or failure | success |
mihpayid | PayU’s unique transaction reference. Use this as authpayuid in subsequent steps (Check Status & Execute Debit). | 10731087875 |
mode | Payment mode used | ENACH |
txnid | Your original transaction ID | MANDATE_1713200000 |
amount | Transaction amount | 1.00 |
net_amount_debit | Actual amount debited from customer | 1.00 |
bank_ref_num | Bank reference number for the transaction | YESB00000... |
bankcode | Bank code used for the eNACH mandate | ICICENCC |
firstname | Customer first name | Test |
email | Customer email | test@example.com |
phone | Customer phone number | 9876543210 |
field9 | Payment gateway response message | Transaction Completed Successfully |
sha512(key|verify_payment|txnid|salt)
// Example: sha512(a4vGC2|verify_payment|MANDATE_1713200000|YourSalt)
After the customer authorizes the mandate at their bank, PayU sends the response to your callback URL. Use verify_payment to get the mihpayid which becomes your authpayuid for future operations.
Use verify_payment to confirm the mandate registration and get the mihpayid.
The mihpayid has been auto-filled in Step 3 (Check Status) form.
authpayuid: -
POST https://test.payu.in/merchant/postservice.php?form=2
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | String — Merchant key provided by PayU during onboarding | a4vGC2 |
command | Mandatory | String — API command — fixed NB_mandate_status | NB_mandate_status |
var1 | Mandatory | String — JSON string containing authpayuid and requestId (see var1 breakdown below) | (see below) |
hash | Mandatory | String — SHA-512 hash — sha512(key|NB_mandate_status|var1|salt) | (computed) |
| Field | Required | Description | Example |
|---|---|---|---|
authpayuid | Mandatory | String — The mihpayid received from mandate registration (Step 2 — Handle Response) | 10731087875 |
requestId | Mandatory | String — A unique request identifier for this status check call | 1892432156 |
| Parameter | Description | Example |
|---|---|---|
status | String — Mandate status (see status values below) | SUCCESS |
action | String — API action performed | NB_mandate_status |
authpayuid | String — PayU’s unique mandate reference ID | 10731087875 |
amount | String — Mandate billing amount | 100.00 |
mandateStartDate | String — Mandate start date | 2026-04-16 |
mandateEndDate | String — Mandate end date | 2027-04-16 |
Use the NB_mandate_status API to verify the current state of the eNACH mandate. This helps you understand if the mandate is active and ready for debit execution.
authpayuid (mihpayid) from mandate registration responserequestId for this status checksha512(key|command|var1|salt)
sha512(merchantKey|NB_mandate_status|{"authpayuid":"...","requestId":"..."}|merchantSalt)
// Endpoint: https://test.payu.in/merchant/postservice.php?form=2
{
"key": "merchant_key",
"command": "NB_mandate_status",
"var1": "{\"authpayuid\":\"10731087875\",\"requestId\":\"1892432156\"}",
"hash": "sha512(key|NB_mandate_status|var1|salt)"
}
{
"status": "SUCCESS",
"action": "NB_mandate_status",
"authpayuid": "10731087875",
"amount": "100.00",
"mandateStartDate": "2022-07-19",
"mandateEndDate": "2023-12-20"
}
INITIATED | Mandate registration initiated |
SUCCESS | Mandate is active and ready for debits |
FAILED | Mandate registration failed |
CANCEL_INITIATED | Cancellation request initiated |
CANCEL_PENDING | Cancellation pending at bank |
CANCEL_SUCCESS | Mandate successfully cancelled |
CANCEL_FAILED | Cancellation request failed |
Once the mandate status is SUCCESS, you can execute recurring debits using the si_transaction API. This is a server-to-server call that doesn't require customer 2FA.
POST https://test.payu.in/merchant/postservice.php?form=2
| Parameter | Required | Description | Example |
|---|---|---|---|
form | Mandatory | Fixed value for API type | 2 |
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
command | Mandatory | API command — fixed si_transaction | si_transaction |
var1 | Mandatory | JSON object with transaction details (see below) | {"authpayuid":...} |
hash | Mandatory | SHA-512 hash (auto-computed from key, command, var1, salt) | (computed) |
{
"authpayuid": "403993715537190503", // mihpayid from mandate registration
"invoiceDisplayNumber": "INV123456", // Invoice/reference number
"amount": "100.00", // Debit amount
"txnid": "DEBIT_1775821582262", // Unique txnid for THIS debit
"phone": "9999999999", // Customer phone
"email": "test@example.com", // Customer email
"udf2": "", // User defined field 2
"udf3": "", // User defined field 3
"udf4": "", // User defined field 4
"udf5": "" // User defined field 5
}
sha512(key|si_transaction|var1|salt)
Example:
sha512(a4vGC2|si_transaction|{"authpayuid":"6611192557","invoiceDisplayNumber":"12345678910",...}|YourSaltHere)
The Execute Debit (si_transaction) API will only work after 24 hours from mandate registration. This is a PayU policy to allow mandate activation and bank confirmation.
billingAmount in mandateUse the getNetbankingStatus API to fetch the list of active Net Banking options for your merchant account. This API returns real-time bank availability so you can display only working banks to your customers.
Get current bank status - some banks may be temporarily down.
Get correct ibibo_code values to use as bankcode in payments.
Only show active banks to customers, reducing failed attempts.
POST https://test.payu.in/merchant/postservice.php?form=2
| Parameter | Required | Description | Example |
|---|---|---|---|
key | Mandatory | Merchant key provided by PayU during onboarding | a4vGC2 |
command | Mandatory | API command — fixed getNetbankingStatus | getNetbankingStatus |
var1 | Mandatory | Bank code or default for all banks | default |
hash | Mandatory | SHA-512 hash (auto-computed from key, command, var1, salt) | (computed) |
sha512(key|command|var1|salt)
Example (all banks):
sha512(a4vGC2|getNetbankingStatus|default|YourSaltHere)
Example (specific bank):
sha512(a4vGC2|getNetbankingStatus|AXIB|YourSaltHere)
[
{
"id": "103",
"ibibo_code": "AXIB", // Use this as bankcode
"bank_name": "Axis Bank",
"mode": "NB", // Filter by this for Net Banking
"up_status": 1, // 1 = Up, 0 = Down
"priority": "1",
"account_required_on_signup": "1"
},
...
]
Only showing mode: "NB" options. Use the ibibo_code as bankcode in your payment request.
| ibibo_code | title | up_status | Action |
|---|
Split Payment allows you to automatically distribute payment amounts among multiple merchants or aggregators. Configure split ratios, and PayU handles the fund distribution during settlement.
{
"split_info": [
{
"merchant_id": "CHILD_MERCHANT_ID_1",
"amount": "500.00"
},
{
"merchant_id": "CHILD_MERCHANT_ID_2",
"amount": "300.00"
}
]
}
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt|split_request_json)
After a split payment completes, verify the transaction and check that split distribution was applied correctly. The verify_payment response includes split details.
status — Should be "success"split_status — Confirms split was appliedsplit_info — Shows distribution among merchantsApply bank-specific offers, cashback, and discounts to Net Banking payments. Check eligible offers before payment and apply them using offer_key parameter.
// Endpoint: https://test.payu.in/merchant/postservice?form=2
// Command: check_offer
{
"key": "merchant_key",
"command": "check_offer",
"var1": "amount",
"var2": "NB", // Payment mode
"var3": "BANKCODE", // e.g., AXIB, HDFB
"hash": "sha512(key|check_offer|var1|salt)"
}
// Add these parameters to _payment request:
offer_key: "OFFER_KEY_FROM_CHECK_OFFER"
offer_auto_apply: "1" // Optional: auto-apply best offer
SKU (Stock Keeping Unit) offers allow you to apply category-specific or product-specific offers. Send cart details with SKU information to get targeted offers for specific products.
{
"items": [
{
"sku": "ELECTRONICS_001",
"category": "electronics",
"brand": "Samsung",
"amount": "25000.00",
"quantity": 1
},
{
"sku": "FASHION_002",
"category": "fashion",
"brand": "Nike",
"amount": "5000.00",
"quantity": 2
}
],
"total": "35000.00"
}
After successful payment, PayU settles funds to your configured bank account. Settlement cycles and timelines vary based on your merchant agreement.
// Endpoint: https://test.payu.in/merchant/postservice?form=2
// Command: get_settlement_details
{
"key": "merchant_key",
"command": "get_settlement_details",
"var1": "settlement_id", // Or date range
"hash": "sha512(key|get_settlement_details|var1|salt)"
}
| Standard Settlement: | T+2 business days |
| Express Settlement: | T+0 or T+1 (if enabled) |
| Refund Impact: | Deducted from next settlement |
| Split Settlement: | Distributed as per split config |
Every PayU API request requires a SHA-512 hash for authentication. The hash proves the request came from you and hasn't been tampered with. Different APIs use different hash formulas.
crypto in Node.js, hashlib in Python)Each PayU API uses a different hash formula. Payment APIs, PostService APIs, and response verification all have distinct formulas. See the comparison table below.
Concatenate the required parameters in exact order, separated by pipe (|) characters. Empty fields must remain as empty strings — do not skip them.
Pass the assembled string through SHA-512 and convert the result to a lowercase hexadecimal string (128 characters).
Add the computed hash as the hash parameter in your API request. PayU will independently compute the same hash and reject the request if they don't match.
| API | Hash Formula |
|---|---|
| Payment | sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt) |
| Payment (api_version=7) | sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|salt) |
| PostService APIs | sha512(key|command|var1|salt) |
| Response Verification | sha512(salt||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key|status) |
const crypto = require('crypto');
function generatePayUHash(key, txnid, amount, productinfo, firstname, email, salt) {
const udf1='', udf2='', udf3='', udf4='', udf5='';
const hashString = `${key}|${txnid}|${amount}|${productinfo}|${firstname}|${email}|${udf1}|${udf2}|${udf3}|${udf4}|${udf5}||||||${salt}`;
return crypto.createHash('sha512').update(hashString).digest('hex');
}
// Example — Net Banking Payment
const hash = generatePayUHash('a4vGC2', 'NB_TXN_123', '100.00', 'Test Product', 'John', 'john@example.com', 'YOUR_SALT');
console.log('Hash:', hash);
<?php
function generatePayUHash($key, $txnid, $amount, $productinfo, $firstname, $email, $salt) {
$udf1=$udf2=$udf3=$udf4=$udf5='';
$hashString = "$key|$txnid|$amount|$productinfo|$firstname|$email|$udf1|$udf2|$udf3|$udf4|$udf5||||||$salt";
return strtolower(hash('sha512', $hashString));
}
// Example — Net Banking Payment
$hash = generatePayUHash('a4vGC2', 'NB_TXN_123', '100.00', 'Test Product', 'John', 'john@example.com', 'YOUR_SALT');
echo "Hash: " . $hash;
?>
import hashlib
def generate_payu_hash(key, txnid, amount, productinfo, firstname, email, salt):
udf1=udf2=udf3=udf4=udf5=''
hash_string = f"{key}|{txnid}|{amount}|{productinfo}|{firstname}|{email}|{udf1}|{udf2}|{udf3}|{udf4}|{udf5}||||||{salt}"
return hashlib.sha512(hash_string.encode('utf-8')).hexdigest().lower()
# Example — Net Banking Payment
hash_val = generate_payu_hash('a4vGC2', 'NB_TXN_123', '100.00', 'Test Product', 'John', 'john@example.com', 'YOUR_SALT')
print(f"Hash: {hash_val}")
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;
public class PayUHash {
public static String generateHash(String key, String txnid, String amount,
String productinfo, String firstname, String email, String salt) {
String hashString = key+"|"+txnid+"|"+amount+"|"+productinfo+"|"+firstname+"|"+email+"|||||||||||"+salt;
try {
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] hash = md.digest(hashString.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : hash) sb.append(String.format("%02x", b));
return sb.toString();
} catch (Exception e) { throw new RuntimeException(e); }
}
}
Use these bank codes in the bankcode parameter when initiating Net Banking payments via the _payment API. The list below shows commonly used banks. For a live list, use the getNetbankingStatus API.
| Bank Code | Bank Name | Type | Status |
|---|---|---|---|
TESTPGNB | Test Bank (Sandbox) | Test | Active |
SBIB | State Bank of India | Public | Active |
HDFB | HDFC Bank | Private | Active |
ICIB | ICICI Bank | Private | Active |
AXIB | Axis Bank | Private | Active |
KTKB | Kotak Mahindra Bank | Private | Active |
YESB | Yes Bank | Private | Active |
INDB | IndusInd Bank | Private | Active |
| Bank Code | Bank Name | Type | Status |
|---|---|---|---|
PNBB | Punjab National Bank | Public | Active |
BKID | Bank of India | Public | Active |
UNIB | Union Bank of India | Public | Active |
CABB | Canara Bank | Public | Active |
BOBB | Bank of Baroda | Public | Active |
CITI | Citibank | Private | Active |
KTKB | Karnataka Bank | Private | Active |
IDBB | IDBI Bank | Public | Active |
FEDB | Federal Bank | Private | Active |
SCBB | Standard Chartered | Private | Active |
Use the getNetbankingStatus API to get real-time bank availability and the complete list of supported banks for your merchant account. Go to Prerequisite for NB section to try it live.
// Use bankcode in your _payment API request
{
"key": "a4vGC2",
"pg": "NB",
"bankcode": "AXIB", // Axis Bank
"txn_s2s_flow": "4",
"amount": "100.00",
"txnid": "NB_TXN_123",
// ... other required params
}
YOUR_MERCHANT_KEY with your actual PayU merchant keyYOUR_MERCHANT_SALT with your actual PayU merchant salt