upi_intent 1.0.1 copy "upi_intent: ^1.0.1" to clipboard
upi_intent: ^1.0.1 copied to clipboard

Launch UPI payment apps with a beautiful built-in app picker. Supports Android & iOS. NPCI spec compliant. The modern replacement for upi_pay.

upi_intent ๐Ÿ’ธ #

pub.dev pub points popularity likes license: MIT platform

A modern, production-ready Flutter plugin for UPI payments โ€” with a beautiful built-in app picker, NPCI-compliant URL construction, typed response parsing, and active maintenance.

๐Ÿš€ The only UPI package with a built-in Material 3 app picker. Replaces outdated packages like upi_pay (abandoned 2+ years ago).


โœจ Features #

Feature Details
๐ŸŽจ Beautiful App Picker Built-in Material 3 bottom sheet โ€” no extra code needed
๐Ÿ”’ NPCI-Compliant URLs Correct upi://pay format per official NPCI spec
โœ… VPA Validator Client-side format validation before initiating payment
๐Ÿ“ฑ Android + iOS Full cross-platform support
๐Ÿค– Android 11+ Ready Required <queries> manifest block included
๐ŸŒ™ Auto Dark Mode App picker adapts to system theme automatically
๐Ÿงช Null-safe & Typed Full null-safety with typed UpiResponse model
๐Ÿ“ฆ Zero bloat No unnecessary dependencies

๐Ÿ“ธ Screenshots #

UPI Intent Example & App Picker


๐Ÿš€ Installation #

Step 1 โ€” Add dependency #

# pubspec.yaml
dependencies:
  upi_intent: ^1.0.0

Then run:

flutter pub get

Step 2 โ€” Android Setup โš ๏ธ Required! #

Open your app's android/app/src/main/AndroidManifest.xml and add the <queries> block:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

  <!-- โœ… Required for Android 11+ (API 30+) to detect UPI apps -->
  <queries>
    <intent>
      <action android:name="android.intent.action.VIEW" />
      <data android:scheme="upi" />
    </intent>
  </queries>

  <application
    android:label="your_app"
    ...>
    ...
  </application>

</manifest>

โŒ Without this block, zero UPI apps will be detected on Android 11 and above!


Step 3 โ€” iOS Setup (Optional) #

Open ios/Runner/Info.plist and add URL scheme whitelist:

<key>LSApplicationQueriesSchemes</key>
<array>
  <string>gpay</string>
  <string>phonepe</string>
  <string>paytmmp</string>
  <string>bhim</string>
  <string>upi</string>
</array>

โ„น๏ธ iOS Note: Due to platform restrictions, iOS cannot return detailed transaction data. Always verify payment on your backend server.


๐Ÿ’ก Usage #

Basic Payment (with Built-in App Picker) #

import 'package:upi_intent/upi_intent.dart';

// Call inside an async function that has access to BuildContext
Future<void> makePayment(BuildContext context) async {
  try {
    final UpiResponse? response = await UpiIntent.pay(
      context: context,
      payment: UpiPayment(
        payeeVpa: 'merchant@upi',         // โ† Payee's UPI ID (required)
        payeeName: 'My Online Store',     // โ† Payee name (required)
        amount: 299.00,                   // โ† Amount in INR (optional)
        transactionNote: 'Order #1234',   // โ† Payment note (optional)
        transactionRefId: 'TXN_001',      // โ† Your reference ID (optional)
      ),
    );

    if (response == null) {
      // User dismissed the app picker without selecting
      print('User cancelled');
      return;
    }

    if (response.isSuccess) {
      // โœ… Payment marked successful by UPI app
      print('Payment successful!');
      print('Transaction ID: ${response.transactionId}');

      // โš ๏ธ IMPORTANT: Always verify on backend before confirming order!
      await verifyOnBackend(response.transactionId!);
    } else {
      // โŒ Payment failed or pending
      print('Payment status: ${response.status}');
    }

  } on UpiException catch (e) {
    // Plugin-level errors (invalid VPA, no UPI apps found, etc.)
    print('UPI Error: ${e.message}');
  }
}

Pay with a Specific App (Skip the Picker) #

// Get all installed UPI apps
final List<UpiApp> apps = await UpiIntent.getInstalledApps();

// Find a specific app
final googlePay = apps.firstWhereOrNull(
  (app) => app.packageName == 'com.google.android.apps.nbu.paisa.user',
);

if (googlePay == null) {
  print('Google Pay is not installed');
  return;
}

// Pay directly with that app
final response = await UpiIntent.payWithApp(
  payment: UpiPayment(
    payeeVpa: 'merchant@upi',
    payeeName: 'My Shop',
    amount: 99.00,
  ),
  app: googlePay,
);

Validate a VPA Before Payment #

// Validate format before calling pay()
final String vpa = 'user@okicici';

if (!UpiValidator.isValidVpa(vpa)) {
  showDialog(context: context, builder: (_) => AlertDialog(
    title: const Text('Invalid VPA'),
    content: const Text('Please enter a valid UPI ID (e.g. name@upi)'),
  ));
  return;
}

// Now safe to proceed with payment
await UpiIntent.pay(context: context, payment: UpiPayment(payeeVpa: vpa, ...));

Get List of Installed UPI Apps #

final List<UpiApp> apps = await UpiIntent.getInstalledApps();

for (final app in apps) {
  print('${app.name} โ†’ ${app.packageName}');
}

// Example output:
// Google Pay โ†’ com.google.android.apps.nbu.paisa.user
// PhonePe โ†’ com.phonepe.app
// Amazon Pay โ†’ in.amazon.mShop.android.shopping

Build UPI URL (for QR Codes) #

final String upiUrl = UpiIntent.buildUpiUrl(
  UpiPayment(
    payeeVpa: 'merchant@upi',
    payeeName: 'My Shop',
    amount: 199.00,
    transactionNote: 'Online order',
  ),
);

// Result: upi://pay?pa=merchant@upi&pn=My+Shop&am=199.00&cu=INR&tn=Online+order
print(upiUrl); // Use this URL in a QR code widget

๐Ÿ“‹ API Reference #

UpiPayment โ€” Payment Parameters #

Parameter Type Required Description
payeeVpa String โœ… Payee's UPI Virtual Payment Address (e.g. name@upi)
payeeName String โœ… Name of the payee / merchant
amount double? โŒ Amount in INR. Leave null to let user enter amount
transactionNote String? โŒ Short description shown in UPI app
transactionRefId String? โŒ Your order/transaction reference ID
merchantCode String? โŒ Merchant Category Code (MCC) for business payments

UpiResponse โ€” Payment Response #

Property Type Description
status UpiTransactionStatus Outcome of the transaction
isSuccess bool true only when status is success
transactionId String? UPI network transaction ID (txnId)
approvalRefNo String? Bank approval reference number
responseCode String? Raw response code from bank

UpiTransactionStatus Enum #

Value Meaning What to do
success UPI app reported success โœ… Verify transactionId on backend
failure Payment failed โŒ Show error, let user retry
submitted Submitted to bank, pending โณ Check backend after a few seconds
unknown Status unclear ๐Ÿ” Always verify via backend

UpiApp โ€” Installed App Info #

Property Type Description
name String Display name (e.g. "Google Pay")
packageName String Android package name
icon List<int>? App icon as raw bytes (for custom UI)

UpiValidator โ€” Static Helpers #

// Check if a VPA has valid format (user@handle)
bool UpiValidator.isValidVpa(String vpa)

// Check if amount is within NPCI limits (โ‚น1 โ€“ โ‚น1,00,000)
bool UpiValidator.isValidAmount(double amount)

๐Ÿฆ Supported UPI Apps #

App Android iOS
Google Pay โœ… โœ…
PhonePe โœ… โœ…
Paytm โœ… โœ…
Amazon Pay โœ… โœ…
WhatsApp Pay โœ… โŒ
BHIM โœ… โœ…
FreeCharge โœ… โŒ
MobiKwik โœ… โŒ
Airtel Thanks โœ… โŒ
YONO SBI โœ… โŒ
iMobile ICICI โœ… โŒ
Any other UPI app โœ… โš ๏ธ

iOS Note: Only apps with registered URL schemes can be detected on iOS.


โš ๏ธ Security โ€” Important! #

Never trust client-side UPI responses alone.

A malicious user could fake a success response. Always verify the transactionId on your server:

// โŒ WRONG โ€” Do NOT do this
if (response.isSuccess) {
  confirmOrder(); // Dangerous!
}

// โœ… CORRECT โ€” Always verify on backend
if (response.isSuccess && response.transactionId != null) {
  final verified = await myBackend.verifyUpiTransaction(
    txnId: response.transactionId!,
    amount: 299.00,
    vpa: 'merchant@upi',
  );
  if (verified) confirmOrder();
}

๐Ÿ› ๏ธ Troubleshooting #

โ“ No UPI apps detected on Android 11+? โ†’ Add the <queries> block to your AndroidManifest.xml โ€” see Android Setup.

โ“ UpiException: Invalid UPI VPA thrown? โ†’ Validate the VPA first using UpiValidator.isValidVpa(vpa).

โ“ Payment works but response is null? โ†’ User dismissed the app picker. Handle the null case gracefully.

โ“ Works on physical device but not emulator? โ†’ Expected behavior. UPI apps are not available on emulators. Test on a real device.

โ“ iOS showing submitted status always? โ†’ iOS cannot return detailed transaction data due to platform restrictions. Verify on backend.

โ“ Lost connection to device during testing? โ†’ Normal! The Flutter app goes to background when UPI app opens. Debug connection drops. Payment still works โ€” press the back button and check result.


๐Ÿ“„ Changelog #

See CHANGELOG.md for version history.


๐Ÿ“œ License #

MIT License โ€” Copyright (c) 2025 Yash Dodani

See LICENSE for full details.


๐Ÿ™ Contributing #

PRs are welcome! Please open an issue first to discuss what you'd like to change.

  1. Fork the repo
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Commit changes: git commit -m 'Add my feature'
  4. Push: git push origin feature/my-feature
  5. Open a Pull Request

Made with โค๏ธ by Yash Dodani

6
likes
150
points
163
downloads
screenshot

Documentation

API reference

Publisher

verified publisheryashdodani.me

Weekly Downloads

Launch UPI payment apps with a beautiful built-in app picker. Supports Android & iOS. NPCI spec compliant. The modern replacement for upi_pay.

Homepage

Topics

#upi #payments #fintech #india #flutter

License

MIT (license)

Dependencies

flutter, plugin_platform_interface, url_launcher

More

Packages that depend on upi_intent

Packages that implement upi_intent