Plain Cards Integration
Process a one-time card transactions via PayU (without tokenization)
This section explains how to integrate plain card payments for cross-border transactions using the Server-to-Server (S2S) flow. This is the standard card transaction flow without tokenization.
Post the required parameters to PayU for plain card payment
Check and handle the response received from PayU
Verify the payment status and ensure transaction completion
Update the invoice ID associated with the transaction
Upload invoice documents related to the completed transaction
Step 1: Post Parameters to PayU
Post the payment parameters to PayU's _payment API endpoint to initiate a plain card transaction.
Reference: For more information, refer to One-Time Payment for Cards - CB.
Environment
| Environment | URL |
|---|---|
| Test | https://test.payu.in/_payment |
| Production | https://secure.payu.in/_payment |
HTTP Method: POST
Content Type: application/x-www-form-urlencoded
Request Parameters
| Parameter | Description | Example |
|---|---|---|
keymandatory | StringMerchant key provided by PayU during onboarding. | JPM7Fg |
txnidmandatory | StringThe transaction ID is a reference number for a specific order generated by the merchant. Must be unique. | payuTestTxn12345 |
amountmandatory | StringThe payment amount for the transaction. | 100.00 |
productinfomandatory | StringA brief description of the product. Character Limit: 100 | iPhone |
firstnamemandatory | StringThe first name of the customer. Character Limit: 60 | Ashish |
emailmandatory | StringThe email address of the customer. Character Limit: 50 | [email protected] |
phonemandatory | StringThe phone number of the customer. | 9876543210 |
address1optional butrecommended`for higher approval rate | varchar The customer's primary billing address line. This field is required for billing and fraud prevention purposes. Character limit: 255. | 123 Main Street |
cityoptional butrecommendedfor higher approval rate | varchar The customer's billing city. This field is required for billing and fraud prevention purposes. Character limit: 50. | New Delhi |
stateoptional butrecommendedfor higher approval rate | varchar The customer's billing state or province. This field is required for billing and fraud prevention purposes. Character limit: 50. | Delhi |
countryoptional butrecommendedfor higher approval rate | varchar The customer's billing country code. This field is required for billing and fraud prevention purposes. Use ISO 3166-1 alpha-2 country codes. Character limit: 2. | India |
zipcodemandatory | varchar The customer's billing postal/zip code. This field is required for billing and fraud prevention purposes. Character limit: 6 digit (India Zipcode) | 110075 |
surlmandatory | StringThe Success URL - page PayU will redirect to if the transaction is successful. | https://example.com/success |
furlmandatory | StringThe Failure URL - page PayU will redirect to if the transaction fails. | https://example.com/failure |
pgmandatory | StringPayment gateway type. For cards, use CC. | CC |
bankcodemandatory | StringBank code for the payment option. Use CC for credit cards, DC for debit cards. | CC |
ccnummandatory | String13-19 digit card number (15 for AMEX, 13-19 for Maestro). Validate with LUHN algorithm. | 5506900480000008 |
ccvvmandatory | String3-digit CVV (4 digits for AMEX). | 123 |
ccnamemandatory | StringCardholder name as entered by the customer. | Test User |
ccexpmonmandatory | StringCard expiry month in MM format (01-12). | 09 |
ccexpyrmandatory | StringCard expiry year in YYYY format. | 2026 |
txn_s2s_flowmandatory | IntegerParameter to enable S2S flow. Set to 4 for S2S4 flow. | 4 |
s2s_client_ipmandatory | StringClient IP captured by merchant in S2S flow. Required for fraud detection. | 10.200.12.12 |
s2s_device_infomandatory | StringUser Agent captured by merchant in S2S flow. | Mozilla/5.0 (Windows NT 10.0; Win64; x64) PayU-API-Test/1.0 |
udf1 optional butrecommendedfor higher approval rate | String The Permanent Account Number (PAN primary taxation ID in India) of the buyer must be collected in this field.Character limit: 10 character alphanumeric | ABCDE1234K |
udf2 optional | String User-defined field for storing transaction-specific data. Character limit: 255. | Additional transaction data |
udf3 optional butrecommendedfor higher approval rate | String Date of Birth (DOB) of buyer in DD-MM-YYYY | 02-02-1980 |
udf4 mandatoryfor paymentaggregators | String End merchant legal entity name. For UPI, this field should not be passed. Character limit: 255. | XYZ Pvt. Ltd. |
udf5 mandatory | String Contains invoice ID for the transaction. Invoice ID / number should be the ID present on the invoice issued to the customer. . Character limit: 255. | INV123456 |
buyer_type_businessoptional incase of B2Btransaction forcross-border payments | Binary To be sent as "1" in case the buyer is a business. In case of individual buyers, it can be skipped. Default is "0". Note: This will be included in hash if posted (covered in next section). | 1 |
udf_params optional | String JSONUDF7 value to capture "Import or Export Code" of the buyerUDF8 value to capture Airway Bill Number / Consignment Number (in case of goods imports) | {"udf7":"0100000029", "udf8":"99953729071"} |
hash mandatory | String This must include the generated hash. For more information, refer to Hash Generation below this table. | Your Generated Hash |
Hash Generation
Parameters in the below sequence needs to be checked before generating the hash, if these params are being posted, it needs to be added in the hash calculation:
|additional_charges|miles|base_payuid|base_merchantid|paisa_mecode|subvention_amount|subvention_eligibility|merchant_data|payoutdetails|loan_id|twid_customer_hash|splitrequest|percentage_additional_charges|force_pa|udf_params|buyer_type_business|tcs_amount
- Case1 example: Simple Hashing, if the merchant is not sending the api_version in the payment request, then it will be treated as hash sequence version 1.
key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|salt
- Case2 example: if the merchant is passing the additional_charges in the payment request then they have to append the additional_charges value in the raw hash sequence as below.
key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|salt|additional_charges
- Case3 example: If the merchant wants to pass additional_charges, buyer_type_business in the payment request, then hash formula for payment request will be:
key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|salt|additional_charges|buyer_type_business
- Case4 example: if the merchant wants to pass the api_version = 7 and buyer_type_business, udf_params in the payment request.
key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||si_details|salt|udf_params|buyer_type_businesskey|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5|udf6|udf7|udf8|udf9|udf10|salt|additional_charges|buyer_type_business- Case4 example: if the merchant wants to pass the api_version = 7 and buyer_type_business, udf_params in the payment request.
key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5|udf6|udf7|udf8|udf9|udf10|si_details|salt|udf_params|buyer_type_businessReference: PayU recommends you to use PayU Hash Verification Tool to verify the hashing. For more information, refer to Using PayU Hash Verification Tool
Sample request
curl --location --request POST 'https://test.payu.in/_payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=JPM7Fg' \
--data-urlencode 'txnid=payuTestTransaction12345' \
--data-urlencode 'amount=100.00' \
--data-urlencode 'firstname=Ashish' \
--data-urlencode 'lastname=Kumar' \
--data-urlencode '[email protected]' \
--data-urlencode 'phone=9988776655' \
--data-urlencode 'productinfo=Product Info' \
--data-urlencode 'address1=123 Main Street' \
--data-urlencode 'city=New York' \
--data-urlencode 'state=NY' \
--data-urlencode 'country=US' \
--data-urlencode 'zipcode=10001' \
--data-urlencode 'surl=https://test.payu.in/admin/test_response' \
--data-urlencode 'furl=https://test.payu.in/admin/test_response' \
--data-urlencode 'pg=CC' \
--data-urlencode 'bankcode=CC' \
--data-urlencode 'ccnum=5506900480000008' \
--data-urlencode 'ccname=Test User' \
--data-urlencode 'ccvv=123' \
--data-urlencode 'ccexpmon=09' \
--data-urlencode 'ccexpyr=2026' \
--data-urlencode 'udf1=AELPR1234E' \
--data-urlencode 'udf2=' \
--data-urlencode 'udf3=02-02-1980' \
--data-urlencode 'udf4=XYZ Pvt. Ltd.' \
--data-urlencode 'udf5=INV123456' \
--data-urlencode 'buyer_type_business=1' \
--data-urlencode 'udf_params={"udf7":"0100000029","udf8":"99953729071"}' \
--data-urlencode 'txn_s2s_flow=4' \
--data-urlencode 's2s_client_ip=10.200.12.12' \
--data-urlencode 's2s_device_info=Mozilla/5.0 (Windows NT 10.0; Win64; x64) PayU-API-Test/1.0' \
--data-urlencode 'hash=YOUR_CALCULATED_HASH'Response Parameters
| Parameter | Description | Example |
|---|---|---|
| metaData | ObjectJSON object containing transaction metadata. | - |
| metaData.referenceId | StringPayU reference ID to be sent back in subsequent calls. | 5a3e7cb9884e003dce1f28f965478a9a12fb9244fc15be91b0b3de48763a12e7 |
| metaData.txnId | StringMerchant's transaction ID. | payuTestTransaction12345 |
| metaData.txnStatus | StringTransaction status (e.g., "Enrolled"). | Enrolled |
| metaData.unmappedStatus | StringStatus for flow control: pending, captured, or failed. | pending |
| result.otpPostUrl | StringURL to post OTP for verification. | https://test.payu.in/ResponseHandler.php |
| result.acsTemplate | StringBase64 encoded HTML form for bank ACS redirect. | PGh0bWw+PGJvZHk+... |
| binData.pureS2SSupported | BooleanWhether native S2S OTP flow is supported. | true |
| binData.issuingBank | StringCard issuing bank. | AXIS |
| binData.category | StringCard category ( creditcard or debitcard). | creditcard |
| binData.cardType | StringCard network ( VISA, MAST, RUPAY). | MAST |
| binData.isDomestic | BooleanWhether the card is domestic. | true |
Sample Response
{
"metaData": {
"message": null,
"referenceId": "5a3e7cb9884e003dce1f28f965478a9a12fb9244fc15be91b0b3de48763a12e7",
"statusCode": null,
"txnId": "payuTestTransaction12345",
"txnStatus": "Enrolled",
"unmappedStatus": "pending",
"resendOtp": {
"isSupported": true,
"attemptsLeft": 2
},
"submitOtp": {
"attemptsLeft": 3
}
},
"result": {
"otpPostUrl": "https://test.payu.in/ResponseHandler.php",
"acsTemplate": "PGh0bWw+PGJvZHk+PGZvcm0gbmFtZT0icGF5bWVudF9wb3N0IiBpZD0i..."
},
"binData": {
"pureS2SSupported": true,
"issuingBank": "AXIS",
"category": "creditcard",
"cardType": "MAST",
"isDomestic": true
}
}Step 2: Handle the Initiate Response from PayU
After posting the payment request, PayU returns a response containing transaction status and next steps for 3DS authentication.
Response Parameters
| Parameter | Description | Example |
|---|---|---|
| metaData | ObjectJSON object containing transaction metadata. | - |
| metaData.referenceId | StringPayU reference ID to be sent back in subsequent calls. | 5a3e7cb9884e003dce1f28f965478a9a12fb9244fc15be91b0b3de48763a12e7 |
| metaData.txnId | StringMerchant's transaction ID. | payuTestTransaction12345 |
| metaData.txnStatus | StringTransaction status (e.g., "Enrolled"). | Enrolled |
| metaData.unmappedStatus | StringStatus for flow control: pending, captured, or failed. | pending |
| result.otpPostUrl | StringURL to post OTP for verification. | https://test.payu.in/ResponseHandler.php |
| result.acsTemplate | StringBase64 encoded HTML form for bank ACS redirect. | PGh0bWw+PGJvZHk+... |
| binData.pureS2SSupported | BooleanWhether native S2S OTP flow is supported. | true |
| binData.issuingBank | StringCard issuing bank. | AXIS |
| binData.category | StringCard category ( creditcard or debitcard). | creditcard |
| binData.cardType | StringCard network ( VISA, MAST, RUPAY). | MAST |
| binData.isDomestic | BooleanWhether the card is domestic. | true |
Sample Response
{
"metaData": {
"message": null,
"referenceId": "5a3e7cb9884e003dce1f28f965478a9a12fb9244fc15be91b0b3de48763a12e7",
"statusCode": null,
"txnId": "payuTestTransaction12345",
"txnStatus": "Enrolled",
"unmappedStatus": "pending",
"resendOtp": {
"isSupported": true,
"attemptsLeft": 2
},
"submitOtp": {
"attemptsLeft": 3
}
},
"result": {
"otpPostUrl": "https://test.payu.in/ResponseHandler.php",
"acsTemplate": "PGh0bWw+PGJvZHk+PGZvcm0gbmFtZT0icGF5bWVudF9wb3N0IiBpZD0i..."
},
"binData": {
"pureS2SSupported": true,
"issuingBank": "AXIS",
"category": "creditcard",
"cardType": "MAST",
"isDomestic": true
}
}Redirect the customer using the result.acsTemplate(base64encoded) to their bank's page for authentication. The final response will be posted to surl/furl and the configured Webhook.
Submit OTP and Resend OTP
For S2S4 flow, you'll receive an OTP enrollment response if the card requires OTP authentication. Use the Submit OTP API and Resend OTP API (if the OTP entered by the customer fails). For more information refer to Submit OTP API and Resend OTP API.
Sample response from Submit OTP
First failure
{
"metaData": {
"message": "OTP invalid. 2 retry attempts left out of 3",
"referenceId": "3d954a723bbb920cee8b0975556f115957ca9992514e4810c859365f0666b044",
"statusCode": null,
"txnId": "my_order_13975",
"unmappedStatus": "pending",
"submitOtp": {
"status": "failed",
"attemptsLeft": 2
}
},
"result": {}
} Second failure
{
"metaData": {
"message": "OTP invalid. 1 retry attempts left out of 3",
"referenceId": "3d954a723bbb920cee8b0975556f115957ca9992514e4810c859365f0666b044",
"statusCode": null,
"txnId": "my_order_13975",
"unmappedStatus": "pending",
"submitOtp": {
"status": "failed",
"attemptsLeft": 1
}
},
"result": {}
} Third attempt (success), any further attempt for SUBMIT/RESEND OTP, when the unmapped status reached to success/failure will provide the final result as below JSON only.
{
"metaData": {
"message": "No Error",
"referenceId": "3d954a723bbb920cee8b0975556f115957ca9992514e4810c859365f0666b044",
"statusCode": "E000",
"txnId": "my_order_13975",
"unmappedStatus": "success",
"submitOtp": {
"status": "success"
}
},
"result": {
"mihpayid": "403993715534252033",
"mode": "CC",
"status": "success",
"key": "PRiQvJ",
"txnid": "my_order_13975",
"amount": "2.00",
"addedon": "2025-07-03 19:12:46",
"productinfo": "asfas",
"firstname": "sudhanshu",
"lastname": "",
"address1": "",
"address2": "",
"city": "",
"state": "",
"country": "",
"zipcode": "",
"email": "[email protected]",
"phone": "9999999999",
"udf1": "<optional>",
"udf2": "<optional>",
"udf3": "<optional>",
"udf4": "<optional>",
"udf5": "",
"udf6": "",
"udf7": "",
"udf8": "",
"udf9": "",
"udf10": "",
"card_token": "",
"card_no": "XXXXXXXXXXXX0008",
"field0": "",
"field1": "766301020057097000",
"field2": "466683",
"field3": "2.00",
"field4": "",
"field5": "00",
"field6": "02",
"field7": "AUTHPOSITIVE",
"field8": "AUTHORIZED",
"field9": "Transaction is Successful",
"payment_source": "payuPureS2S",
"PG_TYPE": "CC-PG",
"error": "E000",
"error_Message": "No Error",
"issuing_bank": "YES",
"card_type": "MAST",
"cardToken": "",
"net_amount_debit": "2",
"discount": "0.00",
"offer_key": "",
"offer_availed": "",
"unmappedstatus": "captured",
"hash": "67d5aa0304a0699ab0764d157d362074f4cfd54178abd060e1f53850b6b1445a9627dd17c679c0902d74f5c03718e5e8ce32ef836d175786ef42c372a43801fa",
"bank_ref_no": "766301020057097000",
"bank_ref_num": "766301020057097000",
"bankcode": "CC",
"surl": "https://test.payu.in/admin/test_response",
"curl": "https://test.payu.in/admin/test_response",
"furl": "https://test.payu.in/admin/test_response",
"card_hash": "46261359f70225c5ed11ef395058f3b2f7d003280bb4feb2f21e41aac113a252",
"threeDSVersion": "2.2.0"
}
} Resend OTP
First resend
{
"metaData": {
"message": null,
"referenceId": "3d954a723bbb920cee8b0975556f115957ca9992514e4810c859365f0666b044",
"statusCode": null,
"txnId": "my_order_13975",
"unmappedStatus": "pending",
"resendOtp": {
"status": "success",
"attemptsLeft": 1
}
},
"result": {}
} Second resend
{
"metaData": {
"message": null,
"referenceId": "3d954a723bbb920cee8b0975556f115957ca9992514e4810c859365f0666b044",
"statusCode": null,
"txnId": "my_order_13975",
"unmappedStatus": "pending",
"resendOtp": {
"status": "success",
"attemptsLeft": 0
}
},
"result": {}
} Reference: PayU recommends you to use PayU Hash Verification Tool to verify the reverse hashing. For more information, refer to Using PayU Hash Verification Tool
Step 3: Verify the Payment
After the payment is complete, verify the transaction status using PayU's verification APIs.
Verification Methods
Use one of the following methods to verify the payment:
- Webhook/Callback: PayU sends a POST request to your
surlorfurlwith transaction details - Verify Payment API: Call the
verify_paymentAPI with the transaction ID
Verify Payment API
curl --location --request POST 'https://info.payu.in/merchant/postservice.php?form=2' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=JPM7Fg' \
--data-urlencode 'command=verify_payment' \
--data-urlencode 'var1=payuTestTransaction12345' \
--data-urlencode 'hash=YOUR_CALCULATED_HASH'Use the webhooks to verify the payment. The following is the sample webhook payload in response. For more information, refer to Webhook Events and Sample Payloads.
Sample Webhook Response
mihpayid=27553369917
&mode=SBQR
&status=success
&key=rZ1fX4
&txnid=T2603041446091822117753
&amount=40.00
&addedon=2026-03-04+14%3A46%3A14
&productinfo=Static+QR
&firstname=
&lastname=
&address1=
&address2=
&city=Gurgaon
&state=
&country=
&zipcode=122001
&email=
&phone=##########
&udf1=
&udf2=
&udf3=
&udf4=SoftQR
&udf5=BFL0000006601446
&udf6=
&udf7=
&udf8=
&udf9=
&udf10=
&card_token=
&card_no=
&field0=STQ9IUFeqlafg78815827
&field1=PRIYA+SHANKAR+PUSNAKE
&field2=995486
&field3=_mobilenum_%40axl
&field4=bajajpay.6879729.d2m9cckd%40indus
&field5=AXLd36cfcd317f243b5b3a2d62bc71caf78
&field6=00000038683323284%7C_mobilenum_%7CSBIN0011418
&field7=APPROVED+OR+COMPLETED+SUCCESSFULLY%7C00
&field8=Payment+from+PhonePe
&field9=Transaction+is+Successful.+Bank+Sent%3ATransaction+success
&payment_source=payu
&cardToken=
&authenticaticationMethod=
&PG_TYPE=SBQR-PG
&error=E000
&error_Message=No+Error
&net_amount_debit=40
&discount=0.00
&offer_key=
&offer_availed=
&unmappedstatus=captured
&hash=aefe0213c4299c7ee2039d5430f7bee63711ee627e1b47d2605d0384abbbf828f3641dae3cb126c8b2f761084cbb0bebad27bb325696cc44ce3061157d7cd9ff
&bank_ref_no=793887773815
&bank_ref_num=793887773815
&bankcode=UPISBQR
&surl=
&curl=
&furl=
&psp_nError Handling
If any error message is displayed with an error code, refer to Error Codes to understand the reason. For error codes during various transaction stages, refer to Transaction Stages - Error References.
ReferenceFor the character limit of each parameter and detailed description, refer to Additional Info for Payment APIs.
Step 4: Update Invoice ID [Conditional]
If the Invoice ID value was unavailable when posting the transaction at Step 1, it can be updated using the UDF Update API by posting it in the UDF5 parameter.
Environment
| Test Environment | <https://test.payu.in/merchant/postservice.php?form=2> |
| Production Environment | <https://info.payu.in/merchant/postservice.php?form=2> |
Sample request other then UPI AutoPay
curl --location --globoff 'https://test.payu.in/merchant/postservice.php?form=2' \
--form 'key="PRiQvJ"' \
--form 'command="udf_update"' \
--form 'var1="my_order_642"' \
--form 'var2="AAAPZ1234C"' \
--form 'var4="22/08/1972"' \
--form 'var5="SellerName"' \
--form 'var6="INV000000005"' \
--form 'hash="{{hash}}"'Sample request for UPI AutoPay
curl --location 'https://test.payu.in/merchant/postservice.php?form=2' \
--form 'key="PRiQvJ"' \
--form 'command="udf_update"' \
--form 'var1="my_order_642"' \
--form 'var2="AAAPZ1234C||22-08-1972"' \
--form 'var4="INV_121312||SellerName"' \
--form 'hash="{{hash}}"'Sample response
Success Scenario
- If successfully updated for cards or Net Banking
{
"status": "UDF values updated",
"transaction_id": "my_order_64240",
"udf1": "AAAPZ1234C",
"udf2": "",
"udf3": "22/08/1972",
"udf4": "SellerName",
"udf5": "INV000000005"
}- If successfully updated for UPI autopay:
{
"status": "UDF values updated",
"transaction_id": "my_order_64240",
"udf1": "AAAPZ1234C||22-08-1972",
"udf2": "",
"udf3": "INV_121312||SellerName"
}Failure Scenarios
- If the transaction ID is empty
(
[status] => 0
[msg] => Parameter missing
) - If the transaction ID is invalid
(
[status] => 0
[msg] => Invalid TXN ID
) - If Hash is invalid:
{
"status": 0,
"msg": "Invalid Hash."
}- If the merchant is not enabled for UDF updates:
{
"status": "0",
"msg": "Update not allowed on provided Field"
}- If no data found in the transaction ID:
{
"status": "0",
"msg": "No Data Found for txnid: 3424"
}- If the merchant is inactive:
{
"msg": "Merchant is not authorized to use PayU API",
"status": 0
}Step 5: Upload the Invoices [Optional]
The invoices / Airway Bill can be uploaded using the Invoice Upload API API. AWB details are mandatory for Goods transactions. Invoice copies can be uploaded optionally.
Environment
| Test Environment | <https://test.payu.in/merchant/postservice.php?form=2> |
| Production Environment | <https://info.payu.in/merchant/postservice.php?form=2> |
Sample request
curl --location -g --request POST '{{baseUrl}}/merchant/postservice?form=2' \
--form 'key="{{merchantKey}}"' \
--form 'command="opgsp_upload_invoice_awb"' \
--form 'var1="403993715525825059"' \ - PayuId
--form 'var2="TestInv0001234568"' \ - invoice Id
--form 'var3="Invoice"' \ - type of upload - Invoice/AWB
--form 'file=@"/path/to/file"' \ - file
--form 'hash="{{hash}}"' Sample response
Success Scenario
- When a file is uploaded successfully:
{
"responseCode":"00",
"responseMsg":"File Uploaded Successfully"
}Failure Scenarios
- When there is an error in uploading the file:
{
"responseCode": "103",
"responseMsg": "Failed to Upload"
} - When the file format is not supported:
{
"responseCode": "105",
"responseMsg": "Not an PACB merchant, contact KAM"
} - When the payuid is invalid:
{
"responseCode":"107",
"responseMsg":"The PayuID in request is invalid"
}- When a mandatory field is missing:
{
"responseCode":"109",
"responseMsg":"All fields are mandatory, please check!"
} Response Code and Description
Updated about 2 hours ago
