Skip to main content

Integrating Payment Gateways in Flutter : A Beginner’s Guide

Updated 8 min readMarkdown

Integrating Payment Gateways in Flutter : A Beginner’s Guide

Integrating a payment gateway into your Flutter app is an essential step for any developer building an application that requires in-app purchases or financial transactions. Payment gateways like Stripe and PayPal provide secure and reliable payment processing solutions that can be easily incorporated into your app. In this guide, I’ll walk you through the steps of integrating a payment gateway in Flutter using Cubit, Freezed, and Injectable, covering both UI elements and backend logic with a detailed example to ensure a smooth implementation.

Step 1: Choosing the Right Payment Gateway

For this guide, we’ll focus on Stripe and PayPal. Stripe is popular for its developer-friendly API and robust features, while PayPal is widely recognized and trusted by users around the world. Both gateways are excellent choices, and you can apply similar principles to other gateways like Razorpay.

Stripe allows for easy integration, supports multiple currencies, and provides security features such as PCI compliance and tokenization. PayPal also offers a well-established platform with robust security features and supports transactions globally, making it another great choice for developers looking to integrate payment processing into their app. To use Stripe in a Flutter app, we’ll use the flutter_stripe package.

Step 2: Setting Up Stripe Account and API Keys

To get started, you need to sign up for a Stripe account. Once your account is set up, navigate to the Dashboard to get your API keys (Publishable Key and Secret Key).

These keys will be used for secure communication between your Flutter app and Stripe’s servers.

Step 3: Adding Dependencies

To integrate PayPal, you can use the paypal_sdk package (or a similar package available) for Flutter. For Stripe, we'll use the flutter_stripe package.

Add the required dependencies to your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  flutter_stripe: ^7.0.0
  dio: ^5.0.0 # For communicating with the backend
  flutter_bloc: ^8.0.0
  freezed_annotation: ^2.0.0
  injectable: ^2.0.0
dev_dependencies:
  build_runner: ^2.0.0
  freezed: ^2.0.0
  injectable_generator: ^2.0.0

Run flutter pub get to install the new dependencies.

Step 4: Backend Setup

The backend plays a significant role in payment processing as it handles sensitive operations like creating payment intents and confirming payments securely.

In this example, we’ll create a simple backend using Node.js and Express that interacts with the Stripe API. You can use any server-side technology (such as Firebase, Python Flask, etc.), but we’ll stick with Node.js for this guide.

Backend Code (Node.js)

  1. Create a new folder for your backend and run npm init to initialize a new Node.js project.
  2. Install the necessary packages:
npm install express stripe dotenv
  1. Create a .env file to store your secret key securely:
STRIPE_SECRET_KEY=sk_test_yourSecretKeyHere
  1. Create an index.js file for your server:
    that for full satck only …..
const express = require('express');
const Stripe = require('stripe');
require('dotenv').config();

const app = express();
const stripe = Stripe(process.env.STRIPE_SECRET_KEY);
app.use(express.json());
app.post('/create-payment-intent', async (req, res) => {
  try {
    const { amount, currency } = req.body;
    const paymentIntent = await stripe.paymentIntents.create({
      amount,
      currency,
    });
    res.status(200).send({ clientSecret: paymentIntent.client_secret });
  } catch (error) {
    res.status(500).send({ error: error.message });
  }
});
app.listen(3000, () => console.log('Server is running on port 3000'));

This backend will create a Payment Intent with Stripe, which is a representation of what you want to charge a customer.

Step 5: Creating Cubit for Payment Logic

We’ll be creating separate Cubits for Stripe and PayPal to handle their respective payment flows.

We’ll be creating separate Cubits for Stripe and PayPal to handle their respective payment flows.

We’ll use Cubit to manage the payment state, Freezed for state management, and Injectable for dependency injection.

Step 5.1: Creating Payment State with Freezed

Create a new file named payment_state.dart:

import 'package:freezed_annotation/freezed_annotation.dart';
part 'payment_state.freezed.dart';

@freezed
class PaymentState with _$PaymentState {
  const factory PaymentState.initial() = _Initial;
  const factory PaymentState.loading() = _Loading;
  const factory PaymentState.success() = _Success;
  const factory PaymentState.failure(String error) = _Failure;
}

This PaymentState class will represent the different states of the payment process, including initial, loading, success, and failure.

Step 5.2: Creating Payment Cubit

Creating Stripe Payment CubitCreating Stripe Payment Cubit

Create a new file named payment_cubit.dart:

import 'package:bloc/bloc.dart';
import 'package:injectable/injectable.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:dio/dio.dart';
import 'dart:convert';
import 'payment_state.dart';

@injectable
class PaymentCubit extends Cubit<PaymentState> {
  PaymentCubit() : super(const PaymentState.initial());
  Future<void> startPayment() async {
    emit(const PaymentState.loading());
    try {
      // Step 1: Call Backend to Create Payment Intent
      final response = await Dio().post(
        'http://localhost:3000/create-payment-intent',
        data: {
          'amount': 5000, // Amount in cents (e.g., $50.00)
          'currency': 'usd',
        },
      );
      if (response.statusCode == 200) {
        final paymentIntentData = jsonDecode(response.data);
        final clientSecret = paymentIntentData['clientSecret'];
        // Step 2: Confirm the Payment Intent using flutter_stripe
        await Stripe.instance.initPaymentSheet(paymentSheetParameters: SetupPaymentSheetParameters(
          paymentIntentClientSecret: clientSecret,
          applePay: true,
          googlePay: true,
          style: ThemeMode.light,
          merchantCountryCode: 'US',
          merchantDisplayName: 'Demo Merchant',
        ));
        // Step 3: Present the Payment Sheet
        await Stripe.instance.presentPaymentSheet();
        emit(const PaymentState.success());
      } else {
        emit(PaymentState.failure('Failed to create payment intent'));
      }
    } catch (e) {
      emit(PaymentState.failure(e.toString()));
    }
  }
}
##### Creating PayPal Payment Cubit
Create a new file named `paypal_payment_cubit.dart`:
```dart
import 'package:bloc/bloc.dart';
import 'package:injectable/injectable.dart';
import 'package:dio/dio.dart';
import 'dart:convert';
import 'payment_state.dart';
@injectable
class PayPalPaymentCubit extends Cubit<PaymentState> {
  PayPalPaymentCubit() : super(const PaymentState.initial());
  Future<void> startPayPalPayment() async {
    emit(const PaymentState.loading());
    try {
      // Step 1: Create a Payment Request (in real app, use PayPal SDK to create it)
      final response = await Dio().post(
        'http://localhost:3000/create-paypal-payment',
        data: {
          'amount': 50.00, // Amount in dollars (e.g., $50.00)
          'currency': 'USD',
        },
      );
      if (response.statusCode == 200) {
        // Handle PayPal-specific payment approval and execute steps here
        emit(const PaymentState.success());
      } else {
        emit(PaymentState.failure('Failed to create PayPal payment request'));
      }
    } catch (e) {
      emit(PaymentState.failure(e.toString()));
    }
  }
}

This Cubit handles the payment process by interacting with the backend, updating the state based on whether the payment succeeds or fails.

Step 6: Injecting Payment Cubit into Your Widget Tree

We will use Injectable to manage dependencies. First, ensure you configure injectable by creating a configuration file:

Create a file named configure_dependencies.dart:

import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
import 'configure_dependencies.config.dart';

final getIt = GetIt.instance;
@InjectableInit()
Future<void> configureDependencies() async => $initGetIt(getIt);

Run the command to generate the necessary code:

flutter pub run build_runner build

Step 7: Flutter UI for Payment

We’ll create two separate pages for Stripe and PayPal payments.

Create a new file named payment_page.dart to implement the payment UI and integrate it with the PaymentCubit:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'configure_dependencies.dart';
import 'payment_cubit.dart';
import 'payment_state.dart';

class PaymentPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final paymentCubit = getIt<PaymentCubit>();
    return BlocProvider<PaymentCubit>(
      create: (context) => paymentCubit,
      child: Scaffold(
        appBar: AppBar(
          title: Text('Stripe Payment Integration'),
        ),
        body: BlocBuilder<PaymentCubit, PaymentState>(
          builder: (context, state) {
            if (state is _Loading) {
              return Center(child: CircularProgressIndicator());
            } else if (state is _Success) {
              return Center(child: Text('Payment Successful!'));
            } else if (state is _Failure) {
              return Center(child: Text('Payment Failed: ${state.error}'));
            } else {
              return Center(
                child: ElevatedButton(
                  onPressed: () => paymentCubit.startPayment(),
                  child: Text('Pay Now'),
                ),
              );
            }
          },
        ),
      ),
    );
  }
}

Step 8: Testing the Payment

PayPal Payment Page Implementation

Create a new file named paypal_payment_page.dart to implement the PayPal payment UI and integrate it with the PayPalPaymentCubit:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'configure_dependencies.dart';
import 'paypal_payment_cubit.dart';
import 'payment_state.dart';

class PayPalPaymentPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final payPalPaymentCubit = getIt<PayPalPaymentCubit>();
    return BlocProvider<PayPalPaymentCubit>(
      create: (context) => payPalPaymentCubit,
      child: Scaffold(
        appBar: AppBar(
          title: Text('PayPal Payment Integration'),
        ),
        body: BlocBuilder<PayPalPaymentCubit, PaymentState>(
          builder: (context, state) {
            if (state is _Loading) {
              return Center(child: CircularProgressIndicator());
            } else if (state is _Success) {
              return Center(child: Text('PayPal Payment Successful!'));
            } else if (state is _Failure) {
              return Center(child: Text('PayPal Payment Failed: ${state.error}'));
            } else {
              return Center(
                child: ElevatedButton(
                  onPressed: () => payPalPaymentCubit.startPayPalPayment(),
                  child: Text('Pay with PayPal'),
                ),
              );
            }
          },
        ),
      ),
    );
  }
}

Summary

Integrating both Stripe and PayPal payment gateways in a Flutter app using Cubit, Freezed, and Injectable involves several steps, including backend setup, creating payment intents, managing state with Cubit, and injecting dependencies with Injectable. This guide walked you through setting up both a simple Node.js backend and the corresponding Flutter UI to complete the payment flow for each gateway.

By following these steps, you can add secure and reliable payment processing to your app, providing users with a seamless experience. Payment integration is critical for e-commerce, subscription services, or any app dealing with monetary transactions, and Stripe and PayPal make this process relatively easy and secure.

Feel free to expand on this implementation for your specific use case, such as saving user card details, handling subscription payments, or integrating additional payment methods like Google Pay or Apple Pay.


Originally published on Medium on November 13, 2024.

About the author

  • Software Engineer FullStack Developer " nest-js & nuxt js (vue.js) & Flutter"Mobile" "

No comments yet. Be the first to comment.

More from this blog