payfast_flutter 0.0.4 copy "payfast_flutter: ^0.0.4" to clipboard
payfast_flutter: ^0.0.4 copied to clipboard

Flutter SDK for PayFast payment gateway integration with Android, iOS, and Web support.

PayFast Flutter SDK #

πŸš€ Pakistan’s First PayFast Flutter SDK #

Pakistan’s first Flutter SDK designed to simplify PayFast payment gateway integration for modern Flutter apps on Android, iOS, and Web.

🎯 Features #

  • Production-Ready: Fully tested and production-ready SDK
  • Clean API: Simple, Stripe-like interface for easy integration
  • Secure Token Authentication: SHA256 signature generation for secure transactions
  • Cross-Platform Checkout: WebView on Android/iOS and HTML form POST checkout on Flutter Web
  • Customizable Configuration: Full control over payment parameters
  • Error Handling: Comprehensive error handling and user feedback
  • Support for Multiple Currencies: Flexible currency support (default: PKR)
  • Redirect Monitoring: Success/failure URL monitoring with callback support
  • Nullable Safety: Fully null-safe Dart code

πŸ“‹ Requirements #

  • Flutter SDK: >=3.10.0
  • Dart SDK: >=3.0.0 <4.0.0
  • Active PayFast merchant account

πŸ“¦ Installation #

Add this to your pubspec.yaml:

dependencies:
  payfast_flutter:
    path: ../  # For local development

Then run:

flutter pub get

πŸš€ Quick Start #

Basic Implementation (3 steps) #

import 'package:flutter/material.dart';
import 'package:payfast_flutter/payfast_flutter.dart';

class CheckoutPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Checkout')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => _startPayment(context),
          child: Text('Pay 100 PKR'),
        ),
      ),
    );
  }

  void _startPayment(BuildContext context) {
    final config = PayFastConfig(
      merchantId: "XXXX",   
      securedKey: "XXXX",
      basketId: "ORDER123",
      amount: "100",
      successUrl: "https://example.com/success",
      failureUrl: "https://example.com/failure",
      checkoutUrl: "https://example.com/ipn",
    );

    PayFast.startPayment(
      context: context,
      config: config,
      onResult: (result) {
        if (result.success) {
          print('βœ“ Payment successful!');
          print('Transaction ID: ${result.transactionId}');
        } else {
          print('βœ— Payment failed: ${result.message}');
        }
      },
    );
  }
}

πŸ“š API Reference #

PayFastConfig #

Configuration class for payment parameters.

Required Parameters

PayFastConfig(
  merchantId: "241665",           // Your PayFast merchant ID
  securedKey: "XXXX",             // Your secure key
  basketId: "ORDER123",           // Unique order ID
  amount: "100.00",               // Amount in decimal format
  successUrl: "https://...",      // Redirect on success
  failureUrl: "https://...",      // Redirect on failure
  checkoutUrl: "https://...",     // IPN endpoint
)

Optional Parameters

PayFastConfig(
  // ... required params ...
  currency: "PKR",                // Default: "PKR"
  txnDesc: "Product Purchase",    // Default: "Payment Transaction"
  customerEmail: "user@example.com",
  customerMobile: "03001234567",
  environment: "sandbox",         // Default: "sandbox"
  additionalDescription: "Order details", // Default: "Flutter Payment"
)

Available Properties

Property Type Default Description
merchantId String Required PayFast merchant ID
securedKey String Required Secure key for authentication
basketId String Required Unique transaction ID
amount String Required Payment amount (decimal)
successUrl String Required Success redirect URL
failureUrl String Required Failure redirect URL
checkoutUrl String Required IPN checkout URL
currency String "PKR" Currency code
txnDesc String "Payment Transaction" Transaction description
customerEmail String? null Customer email (optional)
customerMobile String? null Customer phone (optional)
environment String "sandbox" "sandbox" or "live"
additionalDescription String "Flutter Payment" Additional description

PayFast #

Main SDK class for initiating payments.

startPayment()

Initiates a complete payment flow.

PayFast.startPayment({
  required BuildContext context,
  required PayFastConfig config,
  required Function(PayFastResult result) onResult,
});

Parameters:

  • context: BuildContext for navigation
  • config: PayFastConfig instance with payment details
  • onResult: Callback function that receives PayFastResult

Flow:

  1. βœ“ Requests access token from PayFast API
  2. βœ“ Opens WebView on Android/iOS or a secure popup checkout on Web
  3. βœ“ Auto-submits form to PayFast
  4. βœ“ Monitors for success/failure redirects
  5. βœ“ Returns result via callback

PayFastResult #

Result model returned from payment callback.

class PayFastResult {
  final bool success;           // Payment successful?
  final String message;         // Status message
  final String? transactionId;  // Transaction ID (if successful)
}

Example:

(result) {
  if (result.success) {
    print('Transaction: ${result.transactionId}');
    print('Message: ${result.message}');
  }
}

PayFastService #

Low-level service for API communications.

getAccessToken()

Requests an access token from PayFast API.

final token = await PayFastService.getAccessToken(
  config: payFastConfig,
);

PayFastSignature #

Utility for generating SHA256 signatures.

final signature = PayFastSignature.generate(
  securedKey: "XXXX",
  basketId: "ORDER123",
  amount: "100.00",
);

πŸ’‘ Advanced Usage #

Complete Example #

import 'package:flutter/material.dart';
import 'package:payfast_flutter/payfast_flutter.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'PayFast SDK Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: PaymentDemo(),
    );
  }
}

class PaymentDemo extends StatefulWidget {
  @override
  State<PaymentDemo> createState() => _PaymentDemoState();
}

class _PaymentDemoState extends State<PaymentDemo> {
  String _paymentStatus = "Ready";
  PayFastResult? _lastResult;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('PayFast Payment Demo')),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Status Display
            Card(
              child: Padding(
                padding: EdgeInsets.all(16),
                child: Column(
                  children: [
                    Text('Payment Status', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                    SizedBox(height: 8),
                    Text(_paymentStatus),
                    if (_lastResult != null) ...[
                      SizedBox(height: 16),
                      Container(
                        padding: EdgeInsets.all(12),
                        decoration: BoxDecoration(
                          color: _lastResult!.success ? Colors.green[100] : Colors.red[100],
                          borderRadius: BorderRadius.circular(8),
                        ),
                        child: Column(
                          children: [
                            Text(
                              _lastResult!.success ? 'βœ“ Success' : 'βœ— Failed',
                              style: TextStyle(
                                fontSize: 16,
                                fontWeight: FontWeight.bold,
                                color: _lastResult!.success ? Colors.green : Colors.red,
                              ),
                            ),
                            SizedBox(height: 8),
                            Text(_lastResult!.message),
                            if (_lastResult!.transactionId != null) ...[
                              SizedBox(height: 8),
                              Text('ID: ${_lastResult!.transactionId}', style: TextStyle(fontSize: 12)),
                            ]
                          ],
                        ),
                      ),
                    ]
                  ],
                ),
              ),
            ),
            SizedBox(height: 24),
            
            // Payment Button
            ElevatedButton.icon(
              onPressed: () => _initiatePayment(),
              icon: Icon(Icons.payment),
              label: Text('Start Payment'),
              style: ElevatedButton.styleFrom(
                padding: EdgeInsets.symmetric(vertical: 16),
              ),
            ),
          ],
        ),
      ),
    );
  }

  void _initiatePayment() {
    final config = PayFastConfig(
      merchantId: "241665",
      securedKey: "XXXX",
      basketId: "ORD-${DateTime.now().millisecondsSinceEpoch}",
      amount: "100.00",
      successUrl: "https://example.com/success",
      failureUrl: "https://example.com/failure",
      checkoutUrl: "https://example.com/ipn",
      currency: "PKR",
      txnDesc: "Product Purchase",
      customerEmail: "customer@example.com",
      customerMobile: "03001234567",
    );

    setState(() => _paymentStatus = "Processing...");

    PayFast.startPayment(
      context: context,
      config: config,
      onResult: (result) {
        setState(() {
          _lastResult = result;
          _paymentStatus = result.success ? "Completed" : "Failed";
        });

        // Show snackbar
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text(result.message),
            backgroundColor: result.success ? Colors.green : Colors.red,
          ),
        );
      },
    );
  }
}

Dynamic Amount Calculation #

String calculateAmount(List<Item> items) {
  double total = items.fold(0, (sum, item) => sum + item.price);
  return total.toStringAsFixed(2);
}

final config = PayFastConfig(
  // ... other params ...
  amount: calculateAmount(cartItems),
);

Custom Error Handling #

PayFast.startPayment(
  context: context,
  config: config,
  onResult: (result) {
    if (!result.success) {
      // Show custom error dialog
      showDialog(
        context: context,
        builder: (context) => AlertDialog(
          title: Text('Payment Failed'),
          content: Text(result.message),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: Text('Retry'),
            ),
          ],
        ),
      );
    }
  },
);

🌐 Flutter Web Notes #

Flutter Web is supported through a real HTML form submission to PayFast:

  • The SDK opens a popup window on user interaction.
  • It creates a hidden HTML form and POSTs the payment fields to PayFast.
  • The popup is polled until PayFast redirects back to your app.
  • The PayFast access token should be generated on your backend and supplied through accessTokenProvider.

Important web requirements #

For Flutter Web:

  • successUrl and failureUrl must use the same origin as your web app.
  • Use accessTokenProvider to fetch the PayFast access token from your backend.
  • Do not expose your PayFast securedKey directly in browser requests in production.

Example when running locally:

final successUrl = Uri.base.resolve('/payfast-success').toString();
final failureUrl = Uri.base.resolve('/payfast-failure').toString();
final checkoutUrl = Uri.base.resolve('/payfast-ipn').toString();

PayFast.startPayment(
  context: context,
  config: config,
  accessTokenProvider: (config) async {
    final response = await http.post(
      Uri.parse('http://localhost:8080/api/payfast/access-token'),
      headers: const {'Content-Type': 'application/json'},
      body: jsonEncode({
        'merchantId': config.merchantId,
        'securedKey': config.securedKey,
        'basketId': config.basketId,
        'amount': config.amount,
        'currencyCode': config.currency,
      }),
    );

    final data = jsonDecode(response.body) as Map<String, dynamic>;
    return data['accessToken'] as String?;
  },
  onResult: (result) {
    // handle result
  },
);

If you use a different redirect domain on web, the browser will block the SDK from safely detecting the final redirect.

πŸ”’ Security #

  • βœ“ SHA256 signature generation for request verification
  • βœ“ Token-based authentication
  • βœ“ Support for sandbox and live environments
  • βœ“ HTTPS-only communication
  • βœ“ No sensitive data stored locally
  • βœ“ Null-safe Dart code

🌍 Supported Currencies #

Currently supported currencies:

  • PKR (Pakistani Rupee) - Default

More currencies can be added via configuration.

πŸ“± Platform Support #

  • βœ… Android
  • βœ… iOS
  • βœ… Web
  • ⚠️ Windows: not implemented
  • ⚠️ macOS: not implemented

πŸ“– Examples #

A complete example app is available in the example folder.

For Flutter Web, start the local token proxy first:

cd example
dart run tool/payfast_token_server.dart

Then, in a second terminal:

cd example
flutter run -d chrome

For mobile:

cd example
flutter run

πŸ› Troubleshooting #

Issue: "Failed to get access token" #

Solution: Check that your credentials are correct:

  • Verify merchantId
  • Verify securedKey
  • Ensure internet connectivity
  • Test in sandbox mode first
  • On Flutter Web, verify your backend accessTokenProvider or token proxy is running and returning ACCESS_TOKEN

Issue: Payment page doesn't load #

Solution:

  • On Android/iOS, check WebView initialization and connectivity
  • On Web, make sure the browser allowed the payment popup
  • Verify the PayFast endpoint and token are valid
  • Check the browser console or app logs for errors

Issue: Success/Failure redirect not triggered #

Solution:

  • Verify successUrl and failureUrl are correct
  • On Flutter Web, ensure both URLs use the same origin as Uri.base
  • Keep the redirect routes reachable by your app
  • Ensure proper URL encoding

πŸ“ Dependencies #

  • flutter: sdk
  • http: ^1.2.0
  • webview_flutter: ^4.7.0
  • crypto: ^3.0.3

πŸ“„ API Endpoints #

Purpose Endpoint
Get Token https://ipg1.apps.net.pk/Ecommerce/api/Transaction/GetAccessToken
Process Payment https://ipg1.apps.net.pk/Ecommerce/api/Transaction/PostTransaction

πŸ“„ License #

MIT License - See LICENSE file for details

Copyright (c) 2026 Abdullah Ghaffar

🀝 Contributing #

Contributions are welcome! Please feel free to submit pull requests.

πŸ’¬ Support #

If this package helps you and you'd like to say thanks, or if you want to work with us on a custom project, here are the best ways to connect:

Replace YOUR_COFFEE_URL with your real public support link before publishing.

πŸŽ“ Learn More #


Built with ❀️ for Flutter developers

6
likes
145
points
148
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter SDK for PayFast payment gateway integration with Android, iOS, and Web support.

Repository (GitHub)
View/report issues

Topics

#payfast #payment #flutter-payment #pakistan-payment

Documentation

API reference

License

unknown (license)

Dependencies

crypto, flutter, http, webview_flutter

More

Packages that depend on payfast_flutter