McTaba Labs logo
Software EngineeringThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book Call

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
McTaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Our Work

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2027 McTaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. Paystack for African Developers
  3. Accept Payments with Paystack in Flutter
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Accept Payments with Paystack in Flutter

Flutter apps cannot call the Paystack API directly with a secret key. Create a backend endpoint that initializes a transaction and returns the authorization_url. Open that URL in a WebView (using the paystack_flutter package or webview_flutter). When Paystack redirects to your callback_url, detect the URL change, extract the reference, and verify on your backend.

In this article

  1. 1. Flutter + Paystack Architecture
  2. 2. Add Dependencies
  3. 3. Backend: Initialize Transaction
  4. 4. Flutter: WebView Checkout
  5. 5. Learn More

Flutter + Paystack Architecture

Payment flow for a Flutter app:

  1. Flutter app calls your backend API (not Paystack directly)
  2. Backend initializes transaction with Paystack secret key, returns authorization_url
  3. Flutter opens the authorization_url in a WebView
  4. Customer completes payment on Paystack-hosted page
  5. Paystack redirects to your callback_url
  6. Flutter detects the redirect, extracts the reference
  7. Flutter calls your backend to verify the transaction
  8. Backend verifies with Paystack, returns result to Flutter

Your Flutter app never touches the Paystack secret key. It only knows the transaction reference.

Add Dependencies

# pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  webview_flutter: ^4.0.0  # For custom WebView approach
  http: ^1.2.0               # For API calls to your backend

For Android, add internet permission to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

Backend: Initialize Transaction

Your backend receives the request from Flutter and calls Paystack:

// Node.js/Express example backend
app.post('/api/pay/initialize', async (req, res) => {
  var { email, amount } = req.body;
  var reference = 'flutter_' + Date.now();

  var response = await fetch('https://api.paystack.co/transaction/initialize', {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      email,
      amount: Math.round(amount * 100),
      reference,
      callback_url: 'https://yourapp.com/payment/callback',
    }),
  });

  var data = await response.json();
  if (!data.status) return res.status(400).json({ error: data.message });

  res.json({
    authorization_url: data.data.authorization_url,
    reference: data.data.reference,
  });
});

Flutter: WebView Checkout

// lib/payment_screen.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

class PaymentScreen extends StatefulWidget {
  final String email;
  final double amount;

  const PaymentScreen({super.key, required this.email, required this.amount});

  @override
  State<PaymentScreen> createState() => _PaymentScreenState();
}

class _PaymentScreenState extends State<PaymentScreen> {
  String? _authUrl;
  String? _reference;
  bool _loading = true;
  late WebViewController _controller;

  @override
  void initState() {
    super.initState();
    _initializePayment();
  }

  Future<void> _initializePayment() async {
    var response = await http.post(
      Uri.parse('https://your-backend.com/api/pay/initialize'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'email': widget.email, 'amount': widget.amount}),
    );

    var data = jsonDecode(response.body);

    if (data['authorization_url'] != null) {
      setState(() {
        _authUrl = data['authorization_url'];
        _reference = data['reference'];
        _loading = false;
      });
      _setupWebView();
    }
  }

  void _setupWebView() {
    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setNavigationDelegate(NavigationDelegate(
        onNavigationRequest: (request) {
          // Detect callback URL redirect
          if (request.url.startsWith('https://yourapp.com/payment/callback')) {
            var uri = Uri.parse(request.url);
            var reference = uri.queryParameters['reference'] ??
                            uri.queryParameters['trxref'];

            if (reference != null) {
              Navigator.of(context).pop({'reference': reference, 'success': true});
            }
            return NavigationDecision.prevent;
          }
          return NavigationDecision.navigate;
        },
      ))
      ..loadRequest(Uri.parse(_authUrl!));
  }

  @override
  Widget build(BuildContext context) {
    if (_loading) {
      return const Scaffold(
        body: Center(child: CircularProgressIndicator()),
      );
    }

    return Scaffold(
      appBar: AppBar(
        title: const Text('Complete Payment'),
        leading: IconButton(
          icon: const Icon(Icons.close),
          onPressed: () => Navigator.of(context).pop({'success': false}),
        ),
      ),
      body: WebViewWidget(controller: _controller),
    );
  }
}

Open the payment screen and handle the result:

// In your checkout page
Future<void> _startPayment() async {
  var result = await Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) => PaymentScreen(
        email: userEmail,
        amount: 5000.0,  // NGN 5,000
      ),
    ),
  );

  if (result != null && result['success'] == true) {
    await _verifyPayment(result['reference']);
  }
}

Future<void> _verifyPayment(String reference) async {
  var response = await http.get(
    Uri.parse('https://your-backend.com/api/pay/verify?reference=' + reference),
  );
  var data = jsonDecode(response.body);

  if (data['verified'] == true) {
    // Show success screen, update order status
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Payment successful!')),
    );
  }
}

Learn More

This guide is part of the Paystack integration guides by language and framework series.

Next: Verify Paystack Payments in Flutter

Sign up for the McTaba newsletter

Key Takeaways

  • ✓Never put your Paystack secret key in Flutter code. Always initialize transactions from your backend.
  • ✓Use paystack_flutter package for an easy setup, or webview_flutter for a custom WebView approach.
  • ✓After the WebView redirects to your callback URL, extract the reference and verify on your backend.
  • ✓Amounts must be in the smallest currency unit (kobo for NGN) — always multiply by 100 on the backend.
  • ✓The popup approach works in Flutter by loading the Paystack hosted checkout in a WebView.
  • ✓Add INTERNET permission to AndroidManifest.xml and configure NSAppTransportSecurity in iOS Info.plist.

Frequently Asked Questions

Should I use paystack_flutter package or a custom WebView?
The paystack_flutter package handles the WebView setup for you and is maintained by the community. A custom WebView with webview_flutter gives you more control. For most apps, paystack_flutter is faster to set up. For custom checkout experiences, use the WebView approach in this guide.
Can I use Paystack Inline.js popup in Flutter?
Not directly. Flutter renders on a canvas, not a web browser. You must use a WebView to display any web-based Paystack UI. The WebView approach in this guide loads the Paystack hosted checkout page, which is effectively the same user experience.
How do I handle the callback URL on mobile?
Set your callback_url to a real HTTPS URL on your server. In the WebView NavigationDelegate, intercept requests that start with your callback URL. Extract the reference query parameter and close the WebView. You do not need to handle the callback on the server for mobile — just extract the reference from the URL and verify on your backend.
Does Paystack work for both Android and iOS Flutter apps?
Yes. The WebView approach using webview_flutter works on both platforms. Ensure you add INTERNET permission on Android and configure NSAppTransportSecurity in iOS Info.plist to allow HTTPS connections to paystack.co.

Learn Paystack Integration

KES 2,999

The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.

Start Paystack Course

Not ready? Create Free Account

Keep reading

Paystack Integration Guides by Language and Framework

A complete directory of Paystack integration guides organized by programming language and framework. Each guide covers accepting payments, verifying transactions, handling webhooks, and building subscriptions in your specific stack.

Read more

Verify Paystack Payments in Flutter

After a Paystack checkout in Flutter, verify the transaction by calling your backend, which calls the Paystack verify API. This guide shows the full verification flow from the WebView callback to showing the result to the user.

Read more

Handle Paystack Webhooks in Flutter

Paystack webhooks arrive at your server, not your Flutter app. This guide covers building the backend webhook handler and three patterns for pushing webhook events to Flutter: polling, push notifications, and WebSockets.

Read more

Build Paystack Subscriptions in Flutter

Add Paystack subscription billing to a Flutter mobile app. This guide covers the subscription flow from Flutter, checking subscription status from your backend, displaying plan information, and handling subscription management actions.

Read more

Paystack Redirect Checkout vs Inline Checkout: Choosing Correctly

Paystack gives you two ways to present the checkout page: a full-page redirect to checkout.paystack.com, or an inline popup that overlays your site. Both collect payment identically. The difference is user experience, implementation complexity, and how you handle the post-payment flow.

Read more

Understanding Kobo, Pesewa and Cents: Paystack Amount Handling

Paystack expects amounts in the smallest currency unit: kobo for Naira, pesewas for Cedis, cents for Rand, Shillings, and Dollars. This guide covers the conversion rules, the floating-point traps that cause wrong charges, and the helper functions that keep your amounts correct.

Read more

Explore related topics

M-Pesa & African Stack

M-Pesa Daraja API tutorials, USSD development, and WhatsApp Business API guides. The African Stack that global bootcamps do not teach.

Learn to Code in Kenya

Everything a Kenyan needs to know before writing their first line of code. Career paths, real costs, hardware requirements, and honest answers about what it takes.

Learning to Code

Roadmaps, language guides, and practical advice for learning to code and launching a programming career.

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

The African Stack: Skills for This Market

The skills that make Kenyan developers hard to replace: M-Pesa, USSD, WhatsApp, fintech, and building for the African market.

Bonaventure Ogeto

Bonaventure Ogeto

Founder, McTaba Labs

Bonaventure is the founder of McTaba Labs, a coding bootcamp in Nairobi, Kenya. He has spent years building products for the African market and mentoring the next generation of developers across the continent.