A payment gateway is a digital service that enables businesses to accept, process, and manage transactions securely. It acts as a bridge between your app and financial institutions, making sure fund transfers are smooth and safe.
In this guide, you’ll learn how to integrate payment into your Flutter application using Flutterwave Standard, but before building the application, let’s explore Flutterwave Standard and its advantages.
What is Flutterwave Standard?
Flutterwave Standard is a payment solution that helps businesses accept payments easily without dealing with complicated processing steps. It uses a redirect-based checkout, meaning customers are sent to a secure Flutterwave page to pay and then returned to the business’s website or app.
Key Features of Flutterwave Standard:
- Multiple Payment Options: Supports cards, bank transfers, mobile money (MPesa, Airtel Money), USSD, and digital wallets (Apple Pay and Google Pay).
- Safe Transactions: Uses strong security measures to protect payments.
- Easy to Use: Businesses only need to send payment details through an API, and Flutterwave handles everything.
- Constantly Updated: New payment methods and security improvements happen automatically.
- Custom Checkout: Businesses can add their branding to the payment page.
How Flutterwave Standard Works:
- The merchant initiates a payment request via API, providing transaction details.
- The user is redirected to the Flutterwave-hosted checkout page.
- The user selects a payment method and completes the transaction.
- Flutterwave processes the payment and redirects the user to the merchant’s app with the transaction status.
With that done, let’s get started building the application.
Step 1: Project Set Up
To get started, use your terminal to create a new Flutter project.
flutter create flutter_flw && cd flutter_flw
Next, install the project dependencies by updating the dependencies section in the pubspec.yaml
file.
dependencies:
# Other dependencies go here
flutter_dotenv: ^5.2.1
webview_flutter_wkwebview: ^3.17.0
http: ^1.3.0
Let’s look at what these dependencies are and what they are used for:
flutter_dotenv
is a package for loading environment variables.
webview_flutter_wkwebview
is a package for embedding web view (browser capabilities).
HTTP
is a package for making HTTP requests.
Get the API key and Configure the Environment Variables
First, log into your Flutterwave dashboard and navigate to the API keys section under the Settings menu.
Secondly, create a .env
file in the root of your project and add the snippet below:
FLUTTERWAVE_SECRET_KEY=<REPLACE WITH YOUR SECRET KEY>
FLUTTERWAVE_BASE_URL=https://api.flutterwave.com/v3
Thirdly, update the assets
section of the pubspec.yaml
file so that your Flutter application can read the environment variables.
assets:
- .env
Finally, load the .env
file in the main.dart
file.
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
Future main() async {
await dotenv.load(fileName: ".env");
runApp(const MyApp());
}
// other parts of the main.dart go here.
Step 2: Create a Flutterwave Service Helper
Now that it’s set up, the next step is to create a service file to integrate Flutterwave's payment gateway into your app. To do this, create a flutterwave_service.dart
file inside the lib
directory and add the following code snippet:
import 'dart:convert';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:http/http.dart' as http;
class FlutterwavePayment {
static final String _secretKey = dotenv.get("FLUTTERWAVE_SECRET_KEY");
static final String _baseUrl = dotenv.get("FLUTTERWAVE_BASE_URL");
// Initialize payment
static Future<String> initializePayment({
required String email,
required double amount,
required String currency,
required String txRef,
}) async {
final url = Uri.parse('$_baseUrl/payments');
final response = await http.post(
url,
headers: {
'Authorization': 'Bearer $_secretKey',
'Content-Type': 'application/json',
},
body: jsonEncode({
'tx_ref': txRef,
'amount': amount.toString(),
'currency': currency,
'payment_options': 'card, mobilemoney, ussd',
'redirect_url':
'https://your-callback-url.com/success', // Your dummy callback URL
'customer': {
'email': email,
},
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data\['data'\]['link']; // Payment link
} else {
throw Exception('Failed to initialize payment');
}
}
}
The snippet above does the following:
- Imports the required dependencies.
- Defines the
FlutterwavePayment
class, which retrieves the secret key and base URL from the environment variables file. - Adds an
initializePayment
method (async) that accepts parameters (email
,amount
,currency
, andtxRef
). - Sends a payment request to the Flutterwave Standard endpoint with multiple payment options, a dummy
redirect_url
, and processes the response accordingly.
redirect_url
is the URL where users are redirected after completing or canceling a payment on the Flutterwave-hosted checkout page. In this case, a dummy URL is used because Flutter apps do not rely on schematic URLs for navigation but instead manage screens within the app.
Step 3: Configure Web View to Load the Checkout Page
Since Flutterwave Standard generates a URL with a checkout page for users to complete their payment, you need to configure Flutter to load this page. To do this, create a payment_webview.dart
file and add the following snippet:
import 'package:flutter/material.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
class PaymentWebView extends StatefulWidget {
final String paymentUrl;
const PaymentWebView({super.key, required this.paymentUrl});
@override
State<PaymentWebView> createState() => PaymentWebViewState();
}
class PaymentWebViewState extends State<PaymentWebView> {
late final PlatformWebViewController _controller;
@override
void initState() {
super.initState();
final PlatformWebViewControllerCreationParams params =
WebKitWebViewControllerCreationParams(
allowsInlineMediaPlayback: true,
mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
);
_controller = PlatformWebViewController(params)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadRequest(
LoadRequestParams(
uri: Uri.parse(widget.paymentUrl),
),
)
..setPlatformNavigationDelegate(
PlatformNavigationDelegate(
const PlatformNavigationDelegateCreationParams(),
)..setOnNavigationRequest(
(NavigationRequest request) async {
// Handle payment success/failure
if (request.url
.contains('https://your-callback-url.com/success')) {
// Other Verification logic from your backend
Navigator.pop(context, 'success');
} else if (request.url
.contains('https://your-callback-url.com/failure')) {
Navigator.pop(context, 'failure');
}
return NavigationDecision.navigate;
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Complete Payment')),
body: PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: _controller),
).build(context),
);
}
}
The snippet above creates a PaymentWebView
class that accepts a payment URL and loads it using the webview_flutter_wkwebview
package. It also performs checks to determine if the returned URL, after the payment is initiated, contains the redirect_url
specified earlier.
Step 4: Putting it Together
Next, update the main.dart
file to use the FlutterwavePayment
service and the PaymentWebView
to make payment.
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_flw/flutterwave_service.dart';
import 'package:flutter_flw/payment_webview.dart';
Future main() async {
await dotenv.load(fileName: ".env");
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _makePayment() async {
try {
final paymentLink = await FlutterwavePayment.initializePayment(
email: 'user@example.com',
amount: 100.0,
currency: 'NGN',
txRef:
'UNIQUE_TRANSACTION_REF_${DateTime.now().millisecondsSinceEpoch}',
);
// Open WebView
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PaymentWebView(paymentUrl: paymentLink),
),
);
if (result == 'success') {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Payment successful')),
);
} else if (result == 'failure') {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Payment failed')),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.black,
),
onPressed: _makePayment,
child: Text("Make Payment of #100",
style: TextStyle(color: Colors.white))),
],
),
),
);
}
}
With that done, start the application using the code editor or run the command below.
flutter run
You can test a card payment with the details below or use any of these testing credentials to simulate other payment methods.
Name | Details |
---|---|
Card Number | 5061460166976054667 |
Expiry Date | 10/29 |
CVV | 564 |
Pin | 3310 |
As a best practice, always verify a transaction on the server before providing value to your user. Flutterwave offers multiple backend SDKs to make this verification seamless.
The complete source code can be found on GitHub.
Wrapping up
This guide covers how to integrate Flutterwave Standard into your Flutter app, enabling you to accept payments securely. Check out the documentation to learn more about Flutterwave Standard and how to handle additional edge cases.
Top comments (0)