Introduction to Razorpay Flutter Integration
Accepting digital payments in mobile applications requires a robust, secure, and user-friendly checkout flow. When building e-commerce apps or subscription platforms targeted at India-focused commerce, the official razorpay_flutter Flutter package offers a straightforward integration point for processing payments via UPI, Credit/Debit cards, Net Banking, and digital wallets.
Instead of manually constructing webviews or native platform bridges, the razorpay_flutter package wraps native Razorpay Android and iOS SDKs into a unified Dart interface. In a clean Flutter architecture, payment logic should be isolated inside a dedicated service module so that your core domain logic stays decoupled from specific vendor SDKs.
When to Use the Package
You should consider using the razorpay_flutter package when:
- You need to support standard Razorpay checkout overlays inside an e-commerce, ticketing, or service app.
- You are targeting Android and iOS devices using Razorpay's native mobile SDK capabilities.
- You want to streamline payment event handling (success, error, wallet selection) using standard Dart streams and callbacks.
Architecture Tip: Place your payment logic behind a contract interface (e.g.,
PaymentRepositoryorPaymentService). This keeps presentation widgets clean and facilitates mock testing without triggering actual payment SDK calls.
Installing razorpay_flutter
To add the package to your Flutter project, run the standard pub command in your terminal:
flutter pub add razorpay_flutterThis updates your pubspec.yaml file with the latest compatible version. Always check the official package listing on pub.dev to review current version compatibility and native SDK prerequisites before deploying to production.
Setting Up Event Listeners and Checkout
The core entry point for managing payment flows is the Razorpay class. You instantiate the object, attach event listeners for various checkout outcomes, and trigger open() with your checkout options dictionary.
Basic Payment Integration Example
Here is a complete example demonstrating how to initialize the plugin, listen for events, trigger checkout, and properly clean up native listeners upon disposal:
import 'package:flutter/material.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
class CheckoutPage extends StatefulWidget {
const CheckoutPage({Key? key}) : super(key: key);
@override
State<CheckoutPage> createState() => _CheckoutPageState();
}
class _CheckoutPageState extends State<CheckoutPage> {
late Razorpay _razorpay;
@override
void initState() {
super.initState();
_razorpay = Razorpay();
_razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
_razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
}
@override
void dispose() {
_razorpay.clear();
super.dispose();
}
void _handlePaymentSuccess(PaymentSuccessResponse response) {
// Note: Send response.paymentId, response.orderId, and response.signature
// to your backend server for signature verification before fulfilling the order.
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Payment Successful: ${response.paymentId}')),
);
}
void _handlePaymentError(PaymentFailureResponse response) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Payment Failed: ${response.code} - ${response.message}')),
);
}
void _handleExternalWallet(ExternalWalletResponse response) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('External Wallet Selected: ${response.walletName}')),
);
}
void _startCheckout() {
var options = {
'key': 'rzp_test_YOUR_KEY_HERE',
'amount': 1000, // Amount in lowest currency unit (e.g., 1000 paise = 10 INR)
'name': 'Sample Store',
'description': 'Order #12345',
'retry': {'enabled': true, 'max_count': 1},
'send_sms_hash': true,
'prefill': {
'contact': '9876543210',
'email': 'customer@example.com',
},
'external': {
'wallets': ['paytm']
}
};
try {
_razorpay.open(options);
} catch (e) {
debugPrint('Error launching Razorpay checkout: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Razorpay Checkout')),
body: Center(
child: ElevatedButton(
onPressed: _startCheckout,
child: const Text('Pay Now'),
),
),
);
}
}Platform Setup Notes
Depending on target platforms and Android/iOS build configurations, review these setup prerequisites:
- Android ProGuard Configuration: If using code obfuscation (R8/ProGuard) on Android, verify that standard Razorpay retention rules are preserved as specified in the official package documentation.
- iOS Deployment Target: Ensure your iOS minimum deployment target matches or exceeds the platform requirements specified on pub.dev.
- Server-Side Order Creation: Always generate the official Razorpay
order_idvia your secure backend API rather than trusting client-side price values. Pass thisorder_idinside the options map.
Common Pitfalls and Best Practices
Warning: Never hardcode production API secret keys in your Flutter source code. Your API secret belongs strictly on your backend server.
- Forgetting to call clear(): Memory leaks and duplicate callback triggers occur if you do not invoke
_razorpay.clear()when disposing your widget or service state. - Skipping Server Signature Verification: Receiving
EVENT_PAYMENT_SUCCESSon the client device is not sufficient proof of payment authorization. Always verify the backend signature hash using your API secret. - Tight Coupling: Avoid instantiating and handling Razorpay direct logic deep inside UI widgets. Encapsulate implementation details inside a service provider or state manager (e.g., Bloc, Riverpod, or Provider).
Searchable Developer Terms
When researching solutions or debugging implementation steps, developers frequently search for:
- razorpay_flutter payment gateway integration
- Flutter Razorpay event listeners payment success error
- Razorpay payment SDK setup Flutter Android iOS
- Flutter accept UPI card payments Razorpay
Frequently Asked Questions
What is the primary purpose of the razorpay_flutter package?
The razorpay_flutter package allows Flutter developers to integrate native Razorpay payment checkout workflows into Android and iOS applications.
How do I handle successful or failed payments in razorpay_flutter?
You attach listeners to the Razorpay instance using .on() for Razorpay.EVENT_PAYMENT_SUCCESS, Razorpay.EVENT_PAYMENT_ERROR, and Razorpay.EVENT_EXTERNAL_WALLET.
Why should I clear the Razorpay instance?
Calling _razorpay.clear() unregisters native event listeners, preventing memory leaks and duplicate callback execution when widgets unmount.
Is client-side payment confirmation enough for order processing?
No. You should always transmit paymentId, orderId, and signature to your secure backend to verify HMAC SHA256 signatures before fulfilling an order.