Saved Cards with a Network Token Integration
Process a saved card transactions via PayU (using a network token)
This section describes how to integrate card payments using Network Tokens (Visa/Mastercard tokens) for cross-border transactions. Network tokens provide enhanced security and higher approval rates compared to traditional card-on-file transactions.
Prerequisites
Before using Network Tokens, ensure you have:
- Network token credentials from your token provider (Visa VTS / Mastercard MDES)
- Token details including:
last4Digits,tavv,trid,tokenRefNo - Token expiry date (different from original card expiry)
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 with network token details.
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
Reference: For more information, refer to One-Time Payment for Cards - CB.
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 butrecommendedfor 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 York |
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. | NY |
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. | US |
zipcodemandatory | varchar The customer's billing postal/zip code. This field is required for billing and fraud prevention purposes. Character limit: 20. | 10001 |
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 |
ccvvoptional | String3-digit CVV (4 digits for AMEX). | 123 |
ccexpmonmandatory | StringToken expiry month in MM format (01-12). Use token expiry, not original card expiry. | 09 |
ccexpyrmandatory | StringToken expiry year in YYYY format. Use token expiry, not original card expiry. | 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 |
storecard_token_typemandatory | IntegerToken type. Set to 1 for Network tokens. | 1 |
store_card_tokenmandatory | StringNetwork token (DPAN) provided by the token provider. | 5506900495826660 |
additional_infomandatory | JSONJSON object containing network token cryptogram and metadata. | See below |
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 |
additional_info Object Parameters
| Parameter | Description | Example |
|---|---|---|
| last4Digits | StringLast 4 digits of the original card (FPAN). | 0008 |
| tavv | StringToken Authentication Verification Value - cryptogram from network. | UAQAAAAMKJAQg+w+0IagAAAAAAAA |
| trid | StringToken Requestor ID assigned by the card network. | 400000340044 |
| tokenRefNo | StringToken reference number from the token provider. | DM4MMC1US00000003e1ebda85d81490d97cdc87975c7c3bc |
Example additional_info JSON:
{
"last4Digits": "0008",
"tavv": "UAQAAAAMKJAQg+w+0IagAAAAAAAA",
"trid": "400000340044",
"tokenRefNo": "DM4MMC1US00000003e1ebda85d81490d97cdc87975c7c3bc"
}
ImportantWhen using network tokens:
- The
ccexpyrandccexpmonmust contain the token expiry values, not the original card expiry values- The
store_card_tokenshould be the network token (DPAN), not the original card number (FPAN)- The
tavvcryptogram is transaction-specific and must be freshly generated for each transaction
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_businessFor more information, refer to Generate Hash.
Sample Request
curl --location --request POST 'https://test.payu.in/_payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=JPM7Fg' \
--data-urlencode 'txnid=payuTestTransaction12345' \
--data-urlencode 'amount=100.00' \
--data-urlencode 'firstname=Ashish' \
--data-urlencode '[email protected]' \
--data-urlencode 'phone=9988776655' \
--data-urlencode 'productinfo=Product Info' \
--data-urlencode '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 'ccvv=123' \
--data-urlencode 'ccexpmon=09' \
--data-urlencode 'ccexpyr=2026' \
--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 'storecard_token_type=1' \
--data-urlencode 'store_card_token=5506900495826660' \
--data-urlencode 'additional_info={"last4Digits":"0008","tavv":"UAQAAAAMKJAQg+w+0IagAAAAAAAA","trid":"400000340044","tokenRefNo":"DM4MMC1US00000003e1ebda85d81490d97cdc87975c7c3bc"}' \
--data-urlencode 'udf1=AELPR1234E' \
--data-urlencode 'udf3=02-02-1980' \
--data-urlencode 'udf4=XYZ Pvt. Ltd.' \
--data-urlencode 'udf5=INV123456' \
--data-urlencode 'buyer_type_business=1' \
--data-urlencode 'udf_params={"udf7":"0100000029","udf8":"99953729071"}' \
--data-urlencode 'hash=YOUR_CALCULATED_HASH'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_nStep 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
Error 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.
Updated about 2 hours ago
