1. Integration Steps

๐Ÿ’ฌ

Pre-requisites

To start transacting through Google Pay, register yourself on Google Pay using the following Google Onboarding form. In this registration process, add the Merchant VPA Ids created by PayU for you. In case of multiple VPAs, all of them need to be registered. For any queries regarding the same, send an email to the "[email protected].

Step 1: Create a PayU account

First, create a PayU account. For more information, refer to Register for a Merchant Account.

Step 2: Set up build.gradle

Add the PayU UPI SDK (available at Maven Central) to build.gradle:

implementation 'in.payu:upisdk:1.6.18'

๐Ÿšง

Watch Out

If you are getting the following compile error, expand the Merged Manifest view.

Android resource linking failed /Users/sample/AndroidStudioProjects/MyApp/app/build/intermediates/merged_manifests/debug/AndroidManifest.xml:18: error: unexpected element found in <manifest> Manifest merger failed with multiple errors, see logs

In the Merged Manifest view, the following additional error message is displayed. This indicates that you need to fix your Gradle plugin. For more information on the Gradle plugin, refer to the Google Andriod Documentation.

Error: Missing 'package' key attribute on element package

As UPI SDK is compiled on SDK version 29 with Androidx support, your app, and SDK might have common dependencies that lead to compilation errors due to the duplicity of classes. In such cases, you need to define resolutionStrategy on your project or appโ€™s build.gradle. For more information, refer to Gradle Documentation.

configurations.all {
resolutionStrategy {
force "path of conflicting library 1"
force "path of conflicting library 2"
...
}
}

Step 3: Generate Hash

To generate the hash, refer to Hash Generation.

๐Ÿ“˜

Tip

Every transaction (payment or non-payment) needs a hash by you before sending the transaction details to PayU. Hash is required for PayU to validate the authenticity of the transaction. The hashing must be done on your server.

Step 4: Payment Request Post Data

๐Ÿ“˜

Ways to generate postdata

  • By UPI SDK itself (recommended if you are using UPI SDK alone)
  • By using the PG SDK library.

Step 4.1 Build the payment parameters (mandatory step)

PostData can be generated by using the following sample code:

PaymentParamsUpiSdk mPaymentParamsUpiSdk = new PaymentParamsUpiSdk();
mPaymentParamsUpiSdk.setKey(inputData); //Your Merchant Key
mPaymentParamsUpiSdk.setProductInfo("product info");
mPaymentParamsUpiSdk.setFirstName("first name"); //Customer First name
mPaymentParamsUpiSdk.setEmail("email"); //Customer Email
mPaymentParamsUpiSdk.setTxnId("txnId"); //Your transaction id
mPaymentParamsUpiSdk.setAmount("Transaction Amount"); //Your transaction Amount(In Double as String)
mPaymentParamsUpiSdk.setSurl("success url");
mPaymentParamsUpiSdk.setFurl("failure url");
mPaymentParamsUpiSdk.setUdf1("udf1");
mPaymentParamsUpiSdk.setUdf2("udf2");
mPaymentParamsUpiSdk.setUdf3("udf3");
mPaymentParamsUpiSdk.setUdf4("udf4");
mPaymentParamsUpiSdk.setUdf5("udf5");
mPaymentParamsUpiSdk.setVpa("vpa"); //In case of UPI Collect set customer vpa here
mPaymentParamsUpiSdk.setUserCredentials("user credentials");
mPaymentParamsUpiSdk.setOfferKey("offer key");
mPaymentParamsUpiSdk.setPhone("phone number");//Customer Phone Number
mPaymentParamsUpiSdk.setHash("hash");//Your Payment Hash

String postDataFromUpiSdk = new PostDataGenerate.PostDataBuilder(this).
     setPaymentMode(UpiConstant.UPI).setPaymentParamUpiSdk(mPaymentParamsUpiSdk).
     build().toString();

Step 4.2 For Recurring Payments(SI) (Optional)

If you are integrating SI, then generate the below payment params additionally

SIParams siParams = new SIParams();
siParams.setFree_trial(false);
SIParamsDetails siParamsDetails = new SIParamsDetails();
siParamsDetails.setBillingAmount("100");
siParamsDetails.setBillingCurrency("INR");
siParamsDetails.setBillingCycle(BillingCycle.YEARLY);
siParamsDetails.setPaymentStartDate("08-02-2024");
siParamsDetails.setPaymentEndDate("08-02-2025");
siParamsDetails.setBillingInterval(1);
siParamsDetails.setBillingLimit(BillingLimit.ON);
siParamsDetails.setBillingRule(BillingRule.EXACT);
siParams.setSi_details(siParamsDetails);       
val siParams = SIParams()
siParams.isFree_trial = false
val siParamsDetails = SIParamsDetails()
siParamsDetails.billingAmount = "100"
siParamsDetails.billingCurrency = "INR"
siParamsDetails.billingCycle = BillingCycle.YEARLY
siParamsDetails.paymentStartDate = "08-02-2024"
siParamsDetails.paymentEndDate = "08-02-2025"
siParamsDetails.billingInterval = 1
siParamsDetails.billingLimit = BillingLimit.ON
siParamsDetails.billingRule = BillingRule.EXACT
siParams.si_details = siParamsDetails

For more information on the PayUSIParams parameters, refer to PayU Standing Instructions Parameters. After creating the above PayUSIParams object, configure it in the PayUPaymentParams object. For Standing Instruction, complete PayUPaymentParams similar to the following code block:

mPaymentParamsUpiSdk.setSiParams(siParams);
paymentParamsUpiSdk.siParams = siParams

Check for Payment availability Callback

 /**
     * Callback of payment availability while doing through UPISDK.
     */
    PayUUPICallback payUUpiSdkCallback = new PayUUPICallback() {

        @Override
        public void isPaymentOptionAvailable(boolean isAvailable, PaymentOption paymentOption) {
            super.isPaymentOptionAvailable(isAvailable, paymentOption);
            switch (paymentOption) {
                case PHONEPE:
                   //check whether you show Phonepe or not using isAvailable.
                    break;
                case SAMSUNGPAY:
                 //check whether you show Samsung Pay or not using isAvailable
                    break;
            }
        }
    };

Check For Payment availability

 //Checking the payment availability for PHONEPE, SAMSUNGPAY and Google Pay.
 // It will return the availability on payUUpiSdkCallback isPaymentOptionAvailable() method.
Upi upi = Upi.getInstance();
upi.checkForPaymentAvailability(this, PaymentOption.PHONEPE, payUUpiSdkCallback, mPayUHashes.getPaymentRelatedDetailsForMobileSdkHash(), mPaymentParamsUpiSdk.getKey(), mPaymentParamsUpiSdk.getUserCredentials());
upi.checkForPaymentAvailability(this, PaymentOption.SAMSUNGPAY, payUUpiSdkCallback, mPayUHashes.getPaymentRelatedDetailsForMobileSdkHash(), mPaymentParamsUpiSdk.getKey(), mPaymentParamsUpiSdk.getUserCredentials());
upi.checkForPaymentAvailability(this, PaymentOption.TEZ, payUUpiSdkCallback, mPayUHashes.getPaymentRelatedDetailsForMobileSdkHash(), mPaymentParamsUpiSdk.getKey(), mPaymentParamsUpiSdk.getUserCredentials());

Step 5: Set up for Test Merchant

If you are using the SDK with a test merchant, provide the following metadata value to the manifest file:

<application
<meta-data
android:name="payu_web_service_url"
android:value="https://test.payu.in" />
<meta-data
android:name="payu_post_url"
android:value="https://test.payu.in" />
</application>

Step 6: Payment Options

UPI SDK currently supports the following payment options:

PaymentOption.PHONEPE: Payment using PhonePe
PaymentOption.SAMSUNGPAY: Payment using Samsung pay.
PaymentOption.TEZ: Payment using Google Pay.
PaymentOption.UPI_INTENT: Payment using UPI apps installed on device.i,e, Intent flow..
PaymentOption.UPI_COLLECT: UPI payment through web flow.

Dependency for PhonePe

To make a payment through PhonePe, you must have to add PayU PhonePe dependency:

  • Add the following URL to the root project of build.gradle:
allprojects {
    repositories {
        maven {
            url "https://phonepe.mycloudrepo.io/public/repositories/phonepe-intentsdk-android"
        }
    }
}
  • Add the following dependency to the root project of build.gradle:
implementation 'in.payu:phonepe-intent:1.7.6'

Dependency on Google Pay

To make a payment through Google Pay, you must have to add PayU Google Pay dependency:

  • Add the following dependency to the root project of build.gradle:
implementation 'in.payu:payu-gpay:3.0.0'

Dependency on Samsung Pay

To make a payment through Samsung Pay, you must have to add PayU Samsung dependency:

  • Add the following dependency to the root project of build.gradle:
implementation 'com.payu.samsungpay:samsungpay:1.0'
  • Use PaymentPostParams class to generate Postdata. For more information, refer to TPV Integration.
    After you check the payment availability of Payment, you can go ahead to make the payment.

Step 7: Callbacks

  • onPaymentFailure(String payuResult,String merchantResponse): Calls when payment fails.
  • onPaymentSuccess(String payuResult,String merchantResponse): Calls when payment succeeds.
  • onUpiErrorReceived(int errorCode,String errorMessage): Called for error on UPI SDK where the following error messages are displayed for Samsung Pay initialization failure.
Error CodesError messagesDescription
1VENDOR_NOT_SUPPORTEDThe device Vendor is not supported
2DEVICE_NOT_SUPPORTEDThe device is not supported
3APP_VERSION_MISMATCHSamsung Pay version doesn't meet the requirements
4COUNTRY_NOT_SUPPORTEDThe country of device origin is not supported by Samsung Pay
5MERCHANT_KEY_NOT_REGISTER_FOR_SAMSUNG_PAYMerchant is not registered for Samsung Pay with PayU
6CONTEXT_NULLContext is null
7PAYMENT_ID_NOT_PRESENTCheck your postdata

If the following error messages are received while processing payment, check your Payment Post Data or Payment hash.

Error CodeError MessageDescription
1002MERCHANT_INFO_NOT_PRESENT
1004INVOKING_APP_NOT_INSTALLED_CODEThe selected app is not installed on the device.
1005INVOKING_APP_NOT_ONBOARDED_CODEApplication uses have not been onboarded on UPI on the selected
  • isPaymentOptionAvailable(boolean isAvailable, PaymentOption paymentOption): The merchant must check for Samsung Pay/PhonePe payment option availability on the customer device before showing Samsung Pay/PhonePe as the payment option on their checkout page.
  • onVpaEntered(String vpa, IValidityCheck iValidityCheck): For Generic Intent, you need to calculate validateVpahash using VPA and provide to verifyVpa method of iValidityCheck. Hash can be calculated using the validateVpa webservice. For more information, refer to Hash Generation.
PayUUPICallback payUUpiSdkCallbackUpiSdk = new PayUUPICallback() {
  @Override
  public void onPaymentFailure(String payuResult, String merchantResponse) {
  super.onPaymentFailure(payuResult, merchantResponse);
  //Payment failed
  }
  @Override
  public void onPaymentSuccess(String payuResult, String merchantResponse) {
  super.onPaymentSuccess(payuResult, merchantResponse);
  //Payment succeed
  }
  @Override
  public void onVpaEntered(String vpa, IValidityCheck iValidityCheck) {
  super.onVpaEntered(vpa, iValidityCheck);
  String input = "payu merchant key" + "|validateVPA|" + vpa + "|" + "payu merchant salt";
  iValidityCheck.verifyVpa(calculateHash(input));
  }
  @Override
  public void onUpiErrorReceived(int code, String errormsg) {
  super.onUpiErrorReceived(code, errormsg);
  //Any error on upisdk
  }
};

Make Payment

To make the payment, you need to create UpiConfig and provide mandatory parameters, merchant key, and postdata. For more information, refer to Payment Request Post Data.

UpiConfig upiConfig = new UpiConfig();
upiConfig.setMerchantKey("merchant key");
upiConfig.setPayuPostData("postdata");// that we generate above
//In order to set CustomProgress View use below settings
upiConfig.setProgressDialogCustomView();

Make Intent Payment by Specific App

To make Intent Payment by Specific UPI app, kindly set the desired name of the UPI app in the upiConfig object.

upiConfig.setPackageNameForSpecificApp("<UPI_PACKAGE_ID>");

Where UPI_PACKAGE_ID can be any of UPI apps such as: com.phonepe.app(PhonePe), com.google.android.apps.nbu.paisa.user(GPay) etc.

Disable Manual VPA Fallback Option from Generic Intent Tray

You can disable the Manual VPA Fallback option from the Generic Intent tray from the back-end and from the front-end.

In order to disable it from front-end, set UpiConfig.TRUE to setDisableIntentSeamlessFailure flag of UpiConfig.

upiConfig.setDisableIntentSeamlessFailure(UpiConfig.FALSE/UpiConfig.TRUE);

Provide the PayUUPICallback instance and Upiconfig object to the UPI makepayment() method.

Upi upi = Upi.getInstance();
upi.makePayment(payUUpiSdkCallbackUpiSdk, activity, upiConfig);

๐Ÿ“˜

Tip

For Device API Level 19, you must enable GMS provider service and set gmsProviderUpdatedStatus of UpiConfig similar to the following example. For more details, refer to the Andriod Documentation.

upiConfig.setGmsProviderUpdatedStatus(UpiConfig.DISABLE/UpiConfig.ENABLE);

Step 8: VPA Validation

You can validate a VPA of its own using the SDK. You need to create a hash through the below command. Hash can be calculated using the Webservice command validateVpa. For more information, refer to Hash Generation.

sha512(key|command|var1|salt)

Where:

  • key= "YOUR KEY"
  • command= <"validateVPA">
  • salt= "YOUR SALT"
  • var1= the VPA, you want to validate

โ—๏ธ

Note

This feature is only available from UPI SDK version 1.2.0 or later.

After creating the hash, you need to call the getCommandResponse() method of UPI with postdata.

Upi upi = Upi.getInstance();
upi.getCommandResponse(Activity, postdata, PayUUPICallback);

Create postdata for VPA Validation

String postData= "key=" + Your Key + "&var1=" + {VPA for validation} + "&command=validateVPA&" + "hash=" + {Hash you generated above}

You will get the response to onCommandResponse(String payUCommandResponse, String command) of PayUUPICallback.

PayUCommand Response Sample

{"status":"SUCCESS",
"vpa":"VPA you are validating",
"isVPAValid":1, //It will be 0(Invalid) or 1(Valid)
"payerAccountName":"Payer Name corresponding to the VPA"}

Verify the transaction through Webhooks or polling

๐Ÿ“˜

Tip

After you get the response from SDK, make sure to confirm it with the PayU server. It is recommended to implement the PayU Webhook or backend verify call from your backend.

Implementation of PayU WebHook

Webhook is a server-to-server callback. Once this feature is activated for merchants, PayU would send an S2S response, in addition to an SDK callback, to the merchant. It is recommended for the merchant process the transaction order status โ€“ based on the S2S response and not via the Browser Redirection/SDK callback response to ensure optimum translation outcomes. For more information on the Webhook implementation, refer to Web Checkout Integration Documentation > Webhooks.

Also, you can verify payment through polling, the transaction status after the SDK callback from your backend. For more information, refer to Verify the Transaction.

Sandbox Environment Configurations

To test on Sandbox or Test Environment(test.payu.in), use your Sandbox environment merchant key and Salt and add the following configurations in your application manifest:

<meta-data android:name="payu_debug_mode_enabled" android:value="true" />
<meta-data android:name="payu_web_service_url" android:value="https://test.payu.in" />
<meta-data android:name="payu_post_url" android:value="https://test.payu.in" />

Sample Response

๐Ÿšง

Watch Out

  • In case of UPI intent/InApp flow, you will not receive a callback response in surl or furl. In this case, the format of PayU response received will be different from other payment options that you need to handle at your end.
  • Consider the mihpayid in the PayU response as PayU ID/ID

UPI Collect Response

{
  "id": 403993715526100438,
  "mode": "CC",
  "status": "success",
  "unmappedstatus": "captured",
  "key": "gt***",
  "txnid": "1651831862726",
  "transaction_fee": "1.00",
  "amount": "1.00",
  "cardCategory": "domestic",
  "discount": "0.00",
  "addedon": "2022-05-06 15:41:38",
  "productinfo": "Macbook Pro",
  "firstname": "John",
  "email": "[email protected]",
  "phone": "7879*******",
  "udf1": "udf1",
  "udf2": "udf2",
  "udf3": "udf3",
  "udf4": "udf4",
  "udf5": "udf5",
  "hash": "62928c2f7490480951d25ae01bd0e748bb0b777ae27ef72eb93b7c1cc29eb2d84c4836faabe5ab1e1205a6f4a3f0876c5aece2ae96464c0cc9f1628693b074b1",
  "field1": "711633",
  "field2": "393337",
  "field3": "20220506",
  "field4": "0",
  "field5": "341867702575",
  "field6": "00",
  "field7": "AUTHPOSITIVE",
  "field8": "Approved or completed successfully",
  "field9": "No Error",
  "payment_source": "payu",
  "PG_TYPE": "CC-PG",
  "bank_ref_no": "711633",
  "ibibo_code": "MASTCC",
  "error_code": "E000",
  "Error_Message": "No Error",
  "offer_key": "OfferKey@9227",
  "offer_failure_reason": "Invalid Offer Key.",
  "name_on_card": "PayuUser",
  "card_no": "512345XXXXXX2346",
  "issuing_bank": "HDFC",
  "card_type": "MAST",
  "is_seamless": 1,
  "surl": "https://cbjs.payu.in/sdk/success",
  "furl": "https://cbjs.payu.in/sdk/failure"
}
{
  "id": "15130876153",
  "mode": "CC",
  "status": "failure",
  "unmappedstatus": "failed",
  "key": "sm*****",
  "txnid": "1651832033713",
  "transaction_fee": "1.00",
  "amount": "1.00",
  "cardCategory": "domestic",
  "offer_type": "instant",
  "addedon": "2022-05-06 15:44:09",
  "productinfo": "Macbook Pro",
  "firstname": "John",
  "email": "[email protected]",
  "phone": "7879*******",
  "udf1": "udf1",
  "udf2": "udf2",
  "udf3": "udf3",
  "udf4": "udf4",
  "udf5": "udf5",
  "hash": "c9c2d09d3387e7da70bc4ad6241f4ad3f610b3fcb0f9e481f5954a0d89d57791a5d027c303b239c1e8d6e0cad9c2d0b7ad87ba4911a60318675b15826c265929",
  "field5": "sl/mvXcXQLCWm49B/EAYjXMUh1o=",
  "field7": "EVNEGATIVE",
  "field9": "PROCEED",
  "payment_source": "payu",
  "PG_TYPE": "CC-PG",
  "ibibo_code": "CC",
  "error_code": "E1302",
  "Error_Message": "Bank failed to authenticate the customer due to 3D Secure Enrollment decline",
  "offer_key": "OfferKey@9227",
  "offer_failure_reason": "Invalid Offer for merchant. ",
  "name_on_card": "PayuUser",
  "card_no": "512345XXXXXX2346",
  "issuing_bank": "HDFC",
  "card_type": "MAST",
  "is_seamless": 1,
  "surl": "https://cbjs.payu.in/sdk/success",
  "furl": "https://cbjs.payu.in/sdk/failure"
}

UPI Intent/In-App Response

{
  "status": "success",
  "result": {
    "mihpayid": 15130530926,
    "mode": "UPI",
    "status": "success",
    "key": "sm*****",
    "txnid": "1651828235258",
    "amount": "1.00",
    "addedon": "2022-05-06 14:40:48",
    "productinfo": "Macbook Pro",
    "firstname": "John",
    "lastname": "",
    "address1": "",
    "address2": "",
    "city": "",
    "state": "",
    "country": "",
    "zipcode": "",
    "email": "[email protected]",
    "phone": "7879*******",
    "udf1": "udf1",
    "udf2": "udf2",
    "udf3": "udf3",
    "udf4": "udf4",
    "udf5": "udf5",
    "udf6": "",
    "udf7": "",
    "udf8": "",
    "udf9": "",
    "udf10": "",
    "card_token": "",
    "card_no": "",
    "field0": "",
    "field1": "",
    "field2": "",
    "field3": "andy**********@okhdfcbank",
    "field4": "",
    "field5": "",
    "field6": "ANAND*************|0000000000",
    "field7": "APPROVED OR COMPLETED SUCCESSFULLY|00",
    "field8": "",
    "field9": "Success|Completed Using Callback",
    "payment_source": "payuPureS2S",
    "PG_TYPE": "UPI-PG",
    "error": "E000",
    "error_Message": "No Error",
    "net_amount_debit": 1,
    "unmappedstatus": "captured",
    "hash": "8710a26e6f9da96e2de8648b7122b2ee243ba12e92059b69c66c831ec08cc69eaabff07bfea65de781a6a1c7605271164bf6075ab6e459687baa4888f4d97f2e",
    "bank_ref_no": "212631548690",
    "bank_ref_num": "212631548690",
    "bankcode": "INTENT",
    "surl": "https://cbjs.payu.in/sdk/success",
    "furl": "https://cbjs.payu.in/sdk/failure"
  }
}
{
  "status": "success",
  "result": {
    "mihpayid": "15130540072",
    "mode": "UPI",
    "status": "failure",
    "key": "sm*****",
    "txnid": "1651828340011",
    "amount": "1.00",
    "addedon": "2022-05-06 14:42:25",
    "productinfo": "Macbook Pro",
    "firstname": "John",
    "lastname": "",
    "address1": "",
    "address2": "",
    "city": "",
    "state": "",
    "country": "",
    "zipcode": "",
    "email": "[email protected]",
    "phone": "7879******",
    "udf1": "udf1",
    "udf2": "udf2",
    "udf3": "udf3",
    "udf4": "udf4",
    "udf5": "udf5",
    "udf6": "",
    "udf7": "",
    "udf8": "",
    "udf9": "",
    "udf10": "",
    "card_token": "",
    "card_no": "",
    "field0": "",
    "field1": "",
    "field2": "",
    "field3": "",
    "field4": "",
    "field5": "",
    "field6": "",
    "field7": "",
    "field8": "",
    "field9": "response_from_psp",
    "payment_source": "payuPureS2S",
    "PG_TYPE": "UPI-PG",
    "error": "E308",
    "error_Message": "Transaction Failed at bank end.",
    "net_amount_debit": "0",
    "unmappedstatus": "failed",
    "hash": "5c4d80992f88a3cdd1b5b2a1452d69fe27fece37bc33838e2fb31a70e5636e857fc66952a750b638876bceace31fb8435307a9e2b3bda0e4b29f3478e4bb595a",
    "bank_ref_no": "",
    "bank_ref_num": "",
    "bankcode": "INTENT",
    "surl": "https://cbjs.payu.in/sdk/success",
    "furl": "https://cbjs.payu.in/sdk/failure"
  }
}