Go to previous page

Seamless payment flow using the UPI intent mechanism

UPI apps
#
UPI
#
Payment
Himanshu Bansal
Himanshu
Android Engineer
July 14, 2023

UPI

The Unified Payments Interface (UPI) is a real-time payment system that allows users to transfer funds between bank accounts using their mobile phones. UPI has revolutionized the way people make payments in India, making it faster, more efficient, and more convenient.

One of the key features of UPI is the intent mechanism, which enables seamless payment flows between different apps and services. With the intent mechanism, users can initiate a payment from within any app or service that supports UPI payments, without having to switch to a separate payments app.

To enable seamless payment flow using the UPI intent mechanism, developers need to integrate the UPI SDK into their apps or services. The UPI SDK provides a set of APIs that allow developers to initiate UPI payments from within their apps or services.

Prerequisites

  1. Business channels must accept UPI and be verified merchants by NPCI/banks.
  2. Ensure you have the details required to accept payments using UPI ID with your bank.
  3. Ensure that you have all of the required APIs from your bank to check the status of a payment.
  4. Note that every transaction should use a unique transaction ID.

Getting Started

The UPI intent mechanism works by using a deep link to launch the UPI payments app on the user's device.

Let's look into the intent.

The <span class="text-color-code">Intent.action</span> is simply <span class="text-color-code">ACTION_VIEW</span>, which is usually used to display data to the user.

And the data is just the URI of a specific format that is expected.

	
Copy
val upiPaymentUri = Uri.Builder() .scheme("upi") .authority("pay") .appendQueryParameter("pa", "your-merchant-vpa@xxx") .appendQueryParameter("pn", "your-merchant-name") .appendQueryParameter("mc", "your-merchant-code") .appendQueryParameter("tr", "your-transaction-ref-id") .appendQueryParameter("tn", "your-transaction-note") .appendQueryParameter("am", "your-order-amount") .appendQueryParameter("cu", "INR") .build()

The scheme and authority are used to link and map supported applications, reducing ambiguity.

The rest of the query parameters are as follows:

There are two ways to start UPI intent flow

  1. Implicit Intent flow
  2. Explicit Intent flow

Implicit Intent flow

In the Implicit Intent flow, your application will allow the user to choose from all the available apps that can handle UPI payments and are ready for UPI payments. It is also a mandatory option that your application should support as per NPCI.

To display all supported applications, create an Intent chooser.

	
Copy
val genericUpiPaymentIntent = Intent.createChooser( Intent().apply { action = Intent.ACTION_VIEW data = upiPaymentUri }, "Pay with" )

Now, register for activity result

	
Copy
//Activity val activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { val status = it.data?.getStringExtra("Status") Toast.makeText(this, status, Toast.LENGTH_LONG).show() }
	
Copy
//Compose val activityResultLauncher = rememberLauncherForActivityResult( ActivityResultContracts.StartActivityForResult() ) { val status = it.data?.getStringExtra("Status") Toast.makeText(context, status, Toast.LENGTH_LONG).show() }

And, launch accordingly

	
Copy
Button(onClick = { activityResultLauncher.launch(genericUpiPaymentIntent) }) { Text(text = "Pay with UPI") }

Explicit Intent flow

In the Explicit Intent flow, your application will target a specific application instead of all available applications, and the operating system will launch that specific application directly. However, this method is not required, but it will greatly improve the user experience.

First, we need the package of the application that we need to target our intent to. For example, here is the list of packages of some of the applications that support UPI intent flow;

Google Pay - <span class="text-color-code">com.google.android.apps.nbu.paisa.user</span>

Paytm - <span class="text-color-code">net.one97.paytm</span>

PhonePe - <span class="text-color-code">com.phonepe.app</span>

You can find the list of other supported apps here.

Now add this info to the intent

	
Copy
val gpayUPIPaymentIntent = Intent().apply { action = Intent.ACTION_VIEW data = upiPaymentUri setPackage("com.google.android.apps.nbu.paisa.user") }

And, launch accordingly

	
Copy
Button(onClick = { activityResultLauncher.launch(gpayUPIPaymentIntent) }) { Text(text = "Pay with UPI") }

What if the user does not have that specific application installed?

In that case OS will throw the following error

Error: <span class="text-color-code">android.content.ActivityNotFoundException: No Activity found to handle Intent</span>

We can check whether that particular application is installed and is ready for UPI payments with the following methods:

	
Copy
//Determines whether the application is installed or not fun Context.isAppInstalled(packageName: String): Boolean { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of( PackageManager.GET_ACTIVITIES.toLong())) } else { packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES) } return true } catch (e: PackageManager.NameNotFoundException) { //Log the error } return false } //Determines if the application is ready for UPI payments fun Context.isAppUpiReady(packageName: String): Boolean { val upiIntent = Intent(Intent.ACTION_VIEW, Uri.parse("upi://pay")) val upiActivities: List = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { packageManager.queryIntentActivities( upiIntent, PackageManager.ResolveInfoFlags.of( PackageManager.MATCH_DEFAULT_ONLY.toLong() ) ) } else { packageManager.queryIntentActivities(upiIntent, PackageManager.MATCH_DEFAULT_ONLY) } for (activities in upiActivities) { if (activities.activityInfo.packageName == packageName) return true } return false }

The result of the above two methods can be used to display only the available explicit UPI payment option.

GPay PayTM Other UPI Apps

Here is how you can access the app icon and label with help of <span class="text-color-code">PackageManager</span>:

	
Copy
fun Context.getIconsAndLabelOfUPApplications(): Map { val upiIntent = Intent(Intent.ACTION_VIEW, Uri.parse("upi://pay")) val upiActivities: List = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { packageManager.queryIntentActivities( upiIntent, PackageManager.ResolveInfoFlags.of( PackageManager.MATCH_DEFAULT_ONLY.toLong() ) ) } else { packageManager.queryIntentActivities(upiIntent, PackageManager.MATCH_DEFAULT_ONLY) } return upiActivities.associate { val drawable = it.loadIcon(packageManager) val appName = it.loadLabel(packageManager).toString() appName to getBitmapFromImage(drawable) } } private fun getBitmapFromImage(drawable: Drawable): Bitmap { val bitmap = Bitmap.createBitmap( drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888 ) val canvas = Canvas(bitmap) drawable.setBounds(0, 0, canvas.width, canvas.height) drawable.draw(canvas) return bitmap }

However you can directly access the icon and label of the application, and use them directly, but it is recommended to use the guidelines provided by each application.

For example here is the brand guideline for Google Pay.

Android 11 requirements

Merchants who target API level 30 or higher and run on Android 11 will only be able to view a limited number of apps.

To include the specific application app, include the package name in <span class="text-color-code">&lt;package></span> elements inside the <span class="text-color-code">&lt;queries></span> element.

	
Copy
<manifest> . . . <queries> <package android:name="com.google.android.apps.nbu.paisa.user" /> <package android:name="net.one97.paytm" /> <package android:name="com.phonepe.app" /> </queries> </manifest>

Note

At this moment payment receiver should be a valid merchant with all the required details with it, like merchant code, sign, etc., which will be provided to you by the provider.

In conclusion, the UPI intent mechanism is a powerful tool for enabling seamless payment flows between different apps and services. By integrating the UPI SDK into their apps or services, developers can provide a more convenient and efficient payment experience for their users, while also driving higher conversion rates for their businesses.

References: https://developers.google.com/pay/india/api/android

Recommended Posts

Open new blog
Building apps
#
product
#
technology

Product Manager Challenges in 2023

Sohini
October 9, 2023
Open new blog
Future tech
#
CES
#
technology

Roro: A Catalyst for Innovation at CES 2024

Sohini
December 18, 2023
Open new blog
IoT
#
IoT
#
product

IoT Product Development: 10 essential steps to success

Sohini
September 8, 2023