Integrate Turbo UPI (Headless) on Android App
Steps to integrate Razorpay Turbo UPI Headless within your app.
Use Razorpay Turbo UPI to make UPI payments faster. Follow these steps to integrate with the Razorpay Turbo UPI Headless SDK.
-
Integrate with the
. -
Contact our
and provide the following details to get allowlisted:- Mobile numbers of your internal users.
- App id of your debug, staging and production apps.
-
Contact our
to get the access to the Sample App Repositoryhttps://github.com/upi-turbo/android-turbo-sample-app
. Once you have access, please read the readme section of the repository to learn how to locate the library files and integrate them into your project. -
Add the following lines to your Android project's
gradle.properties
file:android.enableJetifier=true
android.useAndroidX=true
-
The
minSDKversion
for using Turbo UPI is currently 23 and cannot be over written.
Add Transitive Dependencies
Refer to the app/build.gradle
file in the Sample App to add all required transitive dependencies to your module.
For Multi-Module Architecture
If you are using a library module that consumes Turbo SDK within another app module, follow these additional steps:
-
In the library module, use:
debugCompileOnly fileTree(include: ['*.aar'], dir: 'turboUATLibs')releaseCompileOnly fileTree(include: ['*.aar'], dir: 'turboProdLibs') -
In the
app
module, createturboUATLibs
andturboProdLibs
directories & copy the AAR files. Then, add the dependencies in thebuild.gradle
file:debugImplementation fileTree(include: ['*.aar'], dir: 'turboUATLibs')releaseImplementation fileTree(include: ['*.aar'], dir: 'turboProdLibs')
Watch Out!
Use the rzp_test_0wFRWIZnH65uny
API key id for testing on the UAT environment and the
To enhance security, you must create a session token via a server-to-server (S2S) call between your backend and Razorpay's backend. This session token ensures secure communication between the Turbo SDK and Razorpay's systems.
-
Trigger the S2S API from your Backend. Use the following API to generate a session token:
Environment based URLs:
-
UAT:
https://api-web-turbo-upi.ext.dev.razorpay.in
-
Production:
https://api.razorpay.com
Authorization Header Creation:
Base64.encode(${public_key}:${secret})
customer_reference
mandatory
string
A unique identifier for the customer provided by the business. The recommended value is mobile number. For example,9000090000
.token
string
A session token to be used in subsequent session-protected APIs.expire_at
long
Expiry time (in seconds) for the session token, used to optimise session handling and reduce unnecessary reinitialisations.error
object
The request failure due to business or technical failure. -
Initialise the TurboSessionDelegate
object anonymously and pass it through the initialize method. The SDK will call fetchToken
function whenever required to get new token.
In the fetchToken
function, retrieve a new token from your server section, check
TurboSessionDelegate turboSessionDelegate = completion -> {// Fetch token here and once fetched,// it can be passed back to Turbo SDK using the completion callbackcompletion.invoke(new Session("<new-token>"));};// pass the above created turboSessionDelegate object through initialize methodrazorpay.upiTurbo.initialize(turboSessionDelegate)
After initialising the Turbo SDK, proceed to securely link UPI accounts and complete the payment flow.
-
Get already linked accounts.
If your customer has already linked accounts, use the following code to fetch them. If there are no linked UPI accounts, an empty list is returned.
Handy Tips
When the user arrives at your checkout screen, use the
getLinkedUpiAccounts
function to fetch the updated list of UPI accounts.razorpay.upiTurbo.getLinkedUpiAccounts(<10 digit mobile number / random customer id>, 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.}}});Watch Out!
If the device binding is not completed and the
getLinkedUpiAccounts
is triggered, it will return anOnError
with a DEVICE_BINDING_INCOMPLETE error code.customerMobile
mandatory
string
The customer's mobile number.listener
object
The listener to be sent should be of typeUpiTurboResultListener
.
Invoke the below function for these use cases:
-
To initiate new onboarding, in case you get a DEVICE_BINDING_INCOMPLETE error in the above section,
-
To link additional bank accounts for already onboarded users.
razorpay.upiTurbo.linkNewUpiAccount({10 digit mobile number / random customer id}, 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;}}}); -
Invoke the below function in your Activity's
onRequestPermissionsResult
function.@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){if (requestCode == 101) {// make sure not to use the 101 requestCode for your other casesrazorpay.upiTurbo.onPermissionsRequestResult()return}super.onRequestPermissionsResult(requestCode, permissions, grantResults);} -
Additionally
razorpay.onBackPressed()
has to be invoked when a user tries to exit the app or return to the previous page. Therazorpay.upiTurbo.releaseActivityReference()
function releases the allocated memory.@Overridepublic void onBackPressed() {razorpay.onBackPressed();razorpay.upiTurbo.releaseActivityReference();super.onBackPressed();} -
To process the payment, first create a payload, which will be a
JSONObject
as shown in the code below.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");//mandatorypayload.put("customer_id", "cust_KQlMczYKcDIqmB");//optional -
Pass the
upiAccount
andpayload
objects as shown in the code below.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) {}@Overridepublic void onPaymentError(int code, String response, PaymentData paymentData) {//Show error message}});
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/NPCI.
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()
and pass the UpiAccount
instance you have received from Turbo SDK before.
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()
and pass the upiAccount
instance you have received from Turbo SDK before.
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. You will need to collect the below mentioned details for the account:
- Bank accounts: last 6 digits, expiry month & year of the Debit Card.
- Credit cards: last 6 digits, expiry month & year of the Credit Card.
Pass these details in the Card
data class provided by Turbo SDK and the upiAccount
object you received from Turbo SDK.
razorpay.upiTurbo.resetUpiPin(card, upiAccount, new Callback<Empty>() {@Overridepublic void onSuccess(Empty empty) {}@Overridepublic void onFailure(@NonNull Error error) {}});
-
To get the device binding status, please use the method
isDeviceOnboarded()
which returns a 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(activity: Activity)) {// User Device Binded} else {// Call Link New Account for Device Binding} -
Users can now link their credit cards alongside bank accounts during onboarding. You can seamlessly retrieve both credit and bank accounts for transactions, thereby simplifying payments, expanding options, and ensuring security.
-
Changes have been made to the
and models regarding credit card support on UPI. -
Charges will be levied for payments made using CC on UPI. Contact the
for further information. -
Turbo SDK will auto-select the SIM card in few cases and the
SELECT_SIM
action will not be triggered in such cases:-
Device has only one SIM card.
-
Device has multiple SIM cards and the mobile number provided by you matches the number on one of the SIM cards.
-
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.
-
As a compliance requirement, you need to get approval from Google for READ_SMS permission. Refer
for more details. -
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?