Mobile Development

Razorpay Integration in Flutter: A Complete Developer Guide (2025)

Razorpay is the most popular payment gateway for Indian apps. This is the complete, production-ready guide to integrating Razorpay into a Flutter app — including order creation, payment verification, and handling edge cases.

Team DevXAI Technologies · DevXAI Technologies June 15, 2025 11 min read
Razorpay Integration in Flutter: A Complete Developer Guide (2025)

Why Razorpay for Flutter Apps?

Razorpay is the dominant payment gateway in India, supporting UPI, net banking, cards, EMI, and wallets. For Flutter apps targeting Indian users, Razorpay is almost always the right choice. The official Flutter plugin (razorpay_flutter) is well-maintained and supports Android and iOS. This guide covers a production-ready integration — not just a quick start.

Architecture: Server-Side Order Creation is Non-Negotiable

The single most common security mistake in payment integrations: creating orders and verifying payments client-side. Never do this. The correct flow is:

  1. Client sends a payment request to your server
  2. Your server creates a Razorpay Order via the Razorpay API using your secret key
  3. Server returns the Order ID to the client
  4. Client opens the Razorpay checkout with the Order ID
  5. After payment, Razorpay sends a webhook to your server
  6. Your server verifies the payment signature using your secret key
  7. Only after verification does your server fulfil the order

Your Razorpay secret key must never touch the client. Anyone with your secret key can create fraudulent orders.

Setup

1. Add the dependency

# pubspec.yaml
dependencies:
  razorpay_flutter: ^1.3.6

2. Android configuration

# android/app/build.gradle
android {
    defaultConfig {
        minSdkVersion 19  // Razorpay requires API 19+
    }
}

3. iOS configuration

Add to ios/Runner/Info.plist:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>upi</string>
    <string>phonepe</string>
    <string>gpay</string>
    <string>paytm</string>
</array>

Server-Side: Creating a Razorpay Order (Node.js)

const Razorpay = require('razorpay');
const crypto = require('crypto');

const razorpay = new Razorpay({
  key_id: process.env.RAZORPAY_KEY_ID,
  key_secret: process.env.RAZORPAY_KEY_SECRET,
});

// Create order endpoint
app.post('/api/create-order', async (req, res) => {
  const { amount, currency = 'INR', receipt } = req.body;

  const order = await razorpay.orders.create({
    amount: amount * 100,  // Razorpay uses paise
    currency,
    receipt,
  });

  res.json({ orderId: order.id, amount: order.amount, currency: order.currency });
});

// Verify payment endpoint
app.post('/api/verify-payment', (req, res) => {
  const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = req.body;

  const body = razorpay_order_id + '|' + razorpay_payment_id;
  const expectedSignature = crypto
    .createHmac('sha256', process.env.RAZORPAY_KEY_SECRET)
    .update(body)
    .digest('hex');

  if (expectedSignature === razorpay_signature) {
    // Payment verified — fulfil the order
    res.json({ success: true });
  } else {
    res.status(400).json({ success: false, error: 'Invalid signature' });
  }
});

Flutter Client: Complete Integration

import 'package:razorpay_flutter/razorpay_flutter.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

class PaymentService {
  late Razorpay _razorpay;

  void init() {
    _razorpay = Razorpay();
    _razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
    _razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
    _razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
  }

  Future<void> startPayment({
    required double amount,
    required String userName,
    required String userEmail,
    required String userPhone,
    required String description,
  }) async {
    // Step 1: Create order on your server
    final response = await http.post(
      Uri.parse('https://yourapi.com/api/create-order'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'amount': amount, 'receipt': 'order_${DateTime.now().millisecondsSinceEpoch}'}),
    );
    final orderData = jsonDecode(response.body);

    // Step 2: Open Razorpay checkout
    var options = {
      'key': 'rzp_live_YOUR_KEY_ID',  // Use rzp_test_ for testing
      'amount': orderData['amount'],
      'currency': 'INR',
      'order_id': orderData['orderId'],
      'name': 'Your Business Name',
      'description': description,
      'prefill': {
        'contact': userPhone,
        'email': userEmail,
        'name': userName,
      },
      'external': {
        'wallets': ['paytm', 'phonepe']
      }
    };

    _razorpay.open(options);
  }

  void _handlePaymentSuccess(PaymentSuccessResponse response) async {
    // Verify on server before fulfilling order
    final verifyRes = await http.post(
      Uri.parse('https://yourapi.com/api/verify-payment'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'razorpay_order_id': response.orderId,
        'razorpay_payment_id': response.paymentId,
        'razorpay_signature': response.signature,
      }),
    );

    if (jsonDecode(verifyRes.body)['success'] == true) {
      // Show success UI, update order status
    }
  }

  void _handlePaymentError(PaymentFailureResponse response) {
    // Handle cancellation or failure
    // response.code: error code
    // response.message: human-readable message
  }

  void _handleExternalWallet(ExternalWalletResponse response) {
    // User chose an external wallet
  }

  void dispose() {
    _razorpay.clear();
  }
}

Handling Webhooks (Recommended for Production)

Don't rely solely on client-side payment callbacks for order fulfilment. Network issues can cause the client to never call your verify endpoint even after a successful payment. Always configure a Razorpay webhook that calls your server on payment.captured events. This ensures orders are fulfilled even if the user's app crashes after payment.

We've integrated Razorpay into 20+ Flutter apps at DevXAI Technologies. If you're building a payment feature and need help with the integration, get in touch.