Integrate Turbo UPI Headless
Steps to integrate Razorpay Turbo UPI Headless with your app.
Use Razorpay Turbo UPI to make UPI payments faster. Follow these steps to integrate with the Razorpay Turbo UPI Headless SDK.
What's New
Users can now link their credit cards alongside bank accounts during onboarding. Merchants can seamlessly retrieve both credit and bank accounts for transactions, thereby simplifying payments, expanding options, and ensuring security.
Changes have been made to the
regarding credit card support on UPI.Watch Out!
Charges will be levied for payments made using CC on UPI. Contact the
for further information.-
Contact our
to get your mobile number, app and GitHub account whitelisted to get access to thehttps://github.com/upi-turbo/android-turbo-sample-app
- sample app repository. In this repository, you will find the AAR files (libraries for Turbo) and the sample app source code to help you do the entire integration. The AARs on the main branch are for the UAT environment, and the ones on the prod branch are for the production environment.
These are the important files in the sample app repo:app/src/turboUI
: Sample app code for UI SDKapp/libs
: All libraries (Bank, SecureComponent and Turbo) common for headless and UI SDKapp/uiLibrary
: Library for UI SDK.app/build.gradle
: All transitive dependencies needed to integrate Turbo SDK.
-
Integrate with
. -
Import the following frameworks:
- Razorpay Turbo Wrapper Plugin SDK (maven)
- Razorpay Turbo Core SDK
- Razorpay SecureComponent SDK
- Bank SDK
-
Add the following lines to your Android project's
gradle.properties
file:android.enableJetifier=true
android.useAndroidX=true
Watch Out!
minSDKversion
for using Turbo UPI is currently 19 and cannot be over written.- Use the
rzp_test_0wFRWIZnH65uny
API key id for testing on the UAT environment and the for prod testing. - As a compliance requirement, you need to get approval from Google for READ_SMS permission. Refer for more details.
- If the user changes their mobile number during onboarding, you should store the updated number and pass it to the Turbo SDK.
-
You need to link the customer's UPI account with your app. Use the code samples given below to fetch the UPI account.
Watch Out!
If the device binding is not completed and the
getLinkedUpiAccounts
is triggered, it will return anOnError
with a DEVICE_BINDING_INCOMPLETE error message.- If your customer has already linked the UPI account, use the following code to fetch it. If there are no linked UPI accounts, an empty list is returned.
razorpay.upiTurbo.getLinkedUpiAccounts("9000090000", new UpiTurboResultListener(){@Overridepublic void onError(@NonNull Error error) {//Display error message to user.}@Overridepublic void onSuccess(@NonNull List<UpiAccount> accList) {if (accList.size()==0){//Display: no UpiAccounts onboarded yet. Please onboard an account.}else{//Display onboarded UpiAccounts.}}});customerMobile
string
The customer's mobile number.listener
object
The listener to be sent should be of typeUpiTurboResultListener
. -
If the customer has not linked any UPI account, there are two methods to link UPI accounts:
-
Link one UPI account at a time:
Use the following code to link the newly created UPI account with your app. This function can be called from anywhere in the application, providing multiple entry points for customers to link their UPI account with your app.razorpay.upiTurbo.linkNewUpiAccount("9000090000", new UpiTurboLinkAccountListener() {@Overridepublic void onResponse(@NonNull UpiTurboLinkAction action) {switch (action.getCode()) {case ASK_FOR_PERMISSION:action.requestPermission();break;case SHOW_PERMISSION_ERROR://Show dialog to redirect the user to the settings page of the application to grant permissionsbreak;case SELECT_SIM:if (action.getError() != null) {//Display error messagereturn;}if (action.getData() != null && action.getData() instanceof List) {try {List << ? > simList = (List << ? > ) action.getData();Sim sim1 = (Sim) simList.get(0);Sim sim2 = (Sim) simList.get(1);//Show dialogue with a list of simsaction.selectedSim(sim1);} catch (ClassCastException e) {}}break;case SELECT_BANK:if (action.getError() != null) {return;}if (action.getData() != null && action.getData() instanceof AllBanks) {AllBanks allBanks = (AllBanks) action.getData();List < Bank > popularBanks = allBanks.getPopularBanks();List < Bank > allBanksList = allBanks.getBanks();//show dialog with bank listaction.selectedBank(popularBanks.get(0));}break;case SELECT_BANK_ACCOUNT:if (action.getError() != null) {return;}if (action.getData() != null && action.getData() instanceof List) {List << ? > bankAccountList = (List << ? > ) action.getData();if (bankAccountList.get(0) instanceof BankAccount) {//Show dialog with bank account listaction.selectedBankAccount((BankAccount) bankAccountList.get(0));}}break;case SETUP_UPI_PIN:Card card = new Card("01", "28", "234567");action.setupUpiPin(card);break;case STATUS:if (action.getError() != null) {//Show error messagereturn;}if (action.getData() != null && action.getData() instanceof List) {List << ? > onboardedUpiAccounts = (List << ? > ) action.getData();showUpiAccount((UpiAccount) onboardedUpiAccounts.get(0));}break;case LOADER_DATA://Use this trigger to easily show background process happening in the SDK during onboardingshowLoaderData((String) action.getData());break;}}}); -
Prefetch and Link multiple accounts together:
Use the following code to prefetch and link multiple UPI accounts from popular banks. This function is versatile and can be called from anywhere in the application, offering customers multiple entry points to link their UPI accounts with your app.razorpay.upiTurbo.setCustomermobile("9000090000").prefetchAndLinkUpiAccounts(new UpiTurboLinkAccountListener() {@Overridepublic void onResponse(@NonNull UpiTurboLinkAction action) {switch (action.getCode()){case ASK_FOR_PERMISSION:if (action.getError()!=null){//Display error messagereturn;}List<PrefetchBank> banks = (List<PrefetchBank>) action.getData();Map<String, Object> data = new HashMap<>();data.put("banks", banks);String timeStampInSeconds = Long.toString(System.currentTimeMillis() / 1000);Consent consent = new Consent(isReceived, consentMessage, timeStampInSeconds, ConsentType.PREFETCH_AND_LINK, null);ArrayList consents = new ArrayList();consents.add(consent)action.consent(consents).requestPermission();break;case SHOW_PERMISSION_ERROR://Show dialog to redirect the user to the settings page of the application to grant permissionsbreak;case SELECT_SIM:if (action.getError()!=null){//Display error messagereturn;}if (action.getData() != null && action.getData() instanceof List){try{List<?> simList = (List<?>) action.getData();Sim sim1 = (Sim) simList.get(0);Sim sim2 = (Sim) simList.get(1);//Show dialogue with a list of simsaction.selectedSim(sim1);}catch (ClassCastException e){}}break;case SELECT_BANK:if (action.getError()!=null){return;}if (action.getData()!=null && action.getData() instanceof AllBanks){AllBanks allBanks = (AllBanks) action.getData();List<Bank> popularBanks = allBanks.getPopularBanks();List<Bank> allBanksList = allBanks.getBanks();//show dialog with bank listaction.selectedBank(popularBanks.get(0));}break;case SELECT_BANK_ACCOUNT:if (action.getError()!=null){return;}if (action.getData()!=null && action.getData() instanceof List){List<?> bankAccountList = (List<?>) action.getData();if (bankAccountList.get(0) instanceof BankAccount){//Show dialog with bank account listaction.selectedBankAccount((BankAccount)bankAccountList.get(0));}}break;case SETUP_UPI_PIN:Card card = new Card("01", "28", "234567");action.setupUpiPin(card);break;case STATUS:if (action.getError()!=null){//Show error messagereturn;}if (action.getData()!=null && action.getData() instanceof List){List<?> onboardedUpiAccounts = (List<?>) action.getData();showUpiAccount((UpiAccount) onboardedUpiAccounts.get(0));}else if (action.getData()!=null && action.getData() instanceof AllAccounts){AllAccounts allAccounts = (AllAccounts) action.getData();List<Object> accountsWithPinSet = allAccounts.getAccountsWithPinSet();List<BankAccount> accountsWithPinNotSet = allAccounts.getAccountsWithPinNotSet();if(accountsWithPinSet[0] instanceof BankAccount) {switch(accountsWithPinSet[0].state){case LINKING_IN_PRORESS://show account linking in progressbreakcase LINKING_FAILED://show account linking in progressbreak}}else if (accountsWithPinSet[0] instanceof UpiAccount) {// Continue Payment}//Display accountsWithoutPinSet in expandable section - with Set Pin buttonCard card = new Card("01", "28", "234567");action.selectBankAccount(accountsWithPinNotSet[0],card)}break;case LOADER_DATA://Use this trigger to easily show background process happening in the SDK during onboardingshowLoaderData((String) action.getData());break;}}});action
The current state of customer registration with which you can call further functions. All values for this variable are exposed as an enum for ease of integration. Know more about the
.Handy Tips
Conditions for
SELECT_SIM
action:- Triggered:
- CASE 1: The customer's phone has only one SIM, but the mobile number provided is not the same as the mobile number in the SIM object.
- CASE 2: The customer's phone has multiple SIMs, but the mobile number provided is not the same as the mobile number in the SIM object in either of the SIMs.
- Non-Triggered:
- CASE 1: The customer's phone has one SIM, and the mobile number provided is the same as the mobile number in the SIM object received.
- CASE 2: The customer's phone has multiple SIMs, and the mobile number provided is the same as the mobile number in one of the SIM objects received by the OS.
- Triggered:
-
-
The Reward feature allows you to allocate rewards to users without specific criteria. To avail rewards, you need to configure them from the dashboard. You can seamlessly integrate this function into your application, providing multiple entry points for users to check their rewards eligibility before completing a payment.
razorpay.upiTurbo.getRewardForCustomer("9000090000", "<action>", "10000", new Callback < CustomerReward > () {@Overridepublic void onFailure(Error error) {// Handle failure}@Overridepublic void onSuccess(CustomerReward object) {// Handle success}});mobileNumber
mandatory
string
Customer's mobile number.action
mandatory
RewardAction
This parameter specifies the action to check reward eligibility. Possible values:onboarding
: To check reward eligibility for onboarding process.payment
: To check reward eligibility for payment process.
amount
optional
string
The transaction amount expressed in the currency subunits.rewardsDelegate
mandatory
delegate
This parameter allows you to receive callbacks regarding reward eligibility. -
To process the payments, call the
authorize
method of custom checkout with the provided payload.JSONObject payload = new JSONObject();payload.put("currency", "INR");payload.put("email", "gaurav.kumar@example.com");payload.put("contact", "9000090000");payload.put("amount", "10000");payload.put("method", "upi");JSONObject upiBlock = new JSONObject();upiBlock.put("flow", "in_app");payload.put("upi", upiBlock);payload.put("order_id", "order_L2MUBUOeFItcpU");//optionalpayload.put("customer_id", "cust_KQlMczYKcDIqmB");//optional -
Pass the
vpa
andpayload
objects as shown in the code below. Upon receiving thePaymentData
response, you will also receiverewardStatus
along with the payment response. Please note that therewardStatus
key will be present in the response only if your eligible for a reward.HashMap < String, Object > turboPayload = new HashMap < > ();turboPayload.put("upiAccount", upiAccount);turboPayload.put("payload", payload);razorpay.submit(turboPayload, new PaymentResultWithDataListener() {@Overridepublic void onPaymentSuccess(String razorpayPaymentID, PaymentData paymentData) {JSONObject rewardData = paymentData.getData();//show success message with reward data}@Overridepublic void onPaymentError(int code, String response, PaymentData paymentData) {//Show error message}});- The
payment.getData()
function will return aJSONObject
.
{"reward": {"rewardStatus": true}} - The
Handy Tips
In case of an error response, you will get a nested reason
JSON object, which will contain the original error code and description from the bank/Secure component.
You can directly interact with the exposed methods of the Turbo Framework to perform the non-transactional flows listed below.
Fetch the customer's account balance. Call getBalance()
on the bank account object received from upiAccount
.
razorpay.upiTurbo.getBalance(upiAccount, new Callback<AccountBalance>() {@Overridepublic void onSuccess(AccountBalance accountBalance) {}@Overridepublic void onFailure(@NonNull Error error) {}});
Provide the customer the ability to change their UPI PIN. Call changeUpiPin()
on the bank account object received from UpiAccount
.
razorpay.upiTurbo.changeUpiPin(upiAccount, new Callback<UpiAccount>() {@Overridepublic void onSuccess(UpiAccount upiAccount) {}@Overridepublic void onFailure(@NonNull Error error) {}});
Let your customers reset the PIN for their account.
razorpay.upiTurbo.resetUpiPin(card, upiAccount, new Callback<Empty>() {@Overridepublic void onSuccess(Empty empty) {}@Overridepublic void onFailure(@NonNull Error error) {}});
-
The below function is triggered internally after integrating with the Razorpay Android Custom SDK.
@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){razorpay.upiTurbo.onPermissionsRequestResult()super.onRequestPermissionsResult(requestCode, permissions, grantResults);} -
razorpay.onBackPressed()
is triggered when a user tries to exit the app or return to the previous page. Therazorpay.upiTurbo.destroy()
function clears that particular session so that when the user comes back, the payment process starts from the beginning.@Overridepublic void onBackPressed() {razorpay.onBackPressed();razorpay.upiTurbo.destroy();super.onBackPressed();} -
To get the device binding status, please use the variable
razorpay.upiTurbo.isDeviceOnboarded()
of type boolean. It indicates whether the device binding, which is a prerequisite for adding UPI accounts, is done with the user's mobile number.if(razorpay.upiTurbo.isDeviceOnboarded()){// Device Binded}else{// Call linkNewUpiAccount for Device Binding}
The SDKs given below provide access to exposed models for seamless integration.
We recommend the following:
- Complete the integration on UAT before using the prod builds.
- Perform the UAT using the Razorpay-provided API keys.
Complete these steps to take your integration live:
-
You should get your app id whitelisted by Razorpay to test on prod.
Handy Tips
Contact our
to get your mobile number and app whitelisted. -
Import the prod library from the Github repository →
https://github.com/upi-turbo/android-turbo-sample-app/tree/prod/app/libs
prod branch. -
Add Proguard rules:
keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName <fields>; }
keepclassmembers enum * { *; }
keepclassmembers class * { @android.webkit.JavascriptInterface <methods>; }
dontwarn com.razorpay.**
keep class com.razorpay.** {*;}
keep class com.olivelib.** {*;}
keep class com.olive.** {*;}
keep class org.apache.xml.security.** {*;}
keep interface org.apache.xml.security.** {*;}
keep class org.npci.** {*;}
keep interface org.npci.** {*;}
keep class retrofit2.** { *; }
keep class okhttp3.** { *; }
-
Replace the UAT credential with the
for prod testing.
Is this integration guide useful?