Flutter PayPal Payment Gateway Integration

At the time of writing, PayPal does not provide an SDK/package for their Paypal payment Integration in Flutter 

We will cover how to integrate PayPal into a flutter project using web-view. We must take a few actions to do this.

What is PayPal ?

PayPal is a payment platform featuring a website and a phone app that allows for online money transactions between parties.

PayPal is a highly secure banking service that employs some of the most cutting-edge end-to-end encryption technology available. You should also activate two-factor authentication and erase any inactive bank accounts or email addresses.

Because PayPal is not presently providing an SDK/package for their payment gateway integration in Flutter, I successfully implemented PayPal using WebView. I’ve used several of PayPal’s payment Web services that are available for integration in websites all around the world, so I decided to test it in a flutter to reach my aim.

First, we’ll make a PayPal application.

In this example, PayPal Sandbox is used to test the payment integration.

What is the PayPal sandbox?

The PayPal sandbox is a virtual testing environment that is segregated from the actual PayPal production environment. The PayPal sandbox mimics the functionality accessible on PayPal’s production servers. While several PayPal features, such as account termination, monthly statement creation, preserving shipping preferences, and PayPal Shops support, are not available in the paypal sandbox, it does have the same PayPal API feature set as the live environment. You may test your PayPal procedures in the sandbox. Processes behave precisely as they do on production servers in the sandbox.

PayPal developer dashboard

Now. Go to the PayPal developer account dashboard to start utilizing PayPal with Flutter.

Account for PayPal sandbox testing

You’ll see a sidebar in the SANDBOX option where you may pick the accounts and obtain this screen.

Make a PayPal application.

Select My Apps & Credentials from the left panel as shown in this image, then click the “Build App” button to create an app in PayPal.

Include appName, appType, and sandbox account information.

Include this page in your app’s Name, AppType, and Sandbox Business Accounts, as instructed by PayPal, and then click the “Create App” button to acquire the app credentials.

This screen contains the secret id and client id.

After successfully constructing the application, you must retrieve the secret id and client id by clicking on the application detail.

Implementation of Paypal In Flutter App:

Download/Install dependencies.

Add the required dependencies in pubspec.yaml file as shown below.

http_auth:^any
http:^any
webview_flutter:^any

Code implement

To begin, we’ll develop a PaypalHomeScreen and populate it with our simple sample UI and Navigation to pay the payment .

 final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     backgroundColor: Colors.white,
     key: _scaffoldKey,
     appBar: AppBar(
       centerTitle: true,
       backgroundColor: Colors.white,
       title: const Text(
         'Paypal Payment',
         style: TextStyle(
           fontSize: 18.0,
           color: Colors.black,
           fontWeight: FontWeight.bold,
         ),
       ),
     ),
     body: SizedBox(
         width: MediaQuery.of(context).size.width,
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.center,
           mainAxisAlignment: MainAxisAlignment.center,
           children: <Widget>[
             Column(
               children: const [
                 Text(
                   "Items in your Cart",
                   style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
                 ),
                 ListTile(
                   title: Text(
                     "Product: One plus 10",
                     style:
                         TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
                   ),
                   subtitle: Text(
                     "Quantity: 1",
                     style:
                         TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
                   ),
                   trailing: Text(
                     "\$100",
                     style:
                         TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
                   ),
                 )
               ],
             ),
             RaisedButton(
               color: Colors.red,
               onPressed: () {
                 // make PayPal payment
                 Navigator.of(context).push(
                   MaterialPageRoute(
                     builder: (BuildContext context) => Payment(
                       onFinish: (number) async {
                         // payment done
                         final snackBar = SnackBar(
                           content: const Text("Payment done Successfully"),
                           duration: const Duration(seconds: 5),
                           action: SnackBarAction(
                             label: 'Close',
                             onPressed: () {
                               // Some code to undo the change.
                             },
                           ),
                         );
                         _scaffoldKey.currentState!.showSnackBar(snackBar);
                       },
                     ),
                   ),
                 );
               },
               child: const Text(
                 'Pay with Paypal',
                 textAlign: TextAlign.center,
                 style: TextStyle(color: Colors.white),
               ),
             ),
           ],
         )),
   );
 }

The next step is to establish the PayPalService page, from which we will use the PayPal APIs; for now, because we are testing, we will use the URL https://api.sandbox.paypal.com . If you wish to make an actual transaction, replace that with https://api.paypal.com .

Note : In testing mode, a sandbox account is used, but in live mode, a genuine PayPal account is used.

We will now create a PaypalService.dart screen.

PaypalService.dart

class PaypalServices {
 String domain = "https://api.sandbox.paypal.com";

 /// for testing mode
//String domain = "https://api.paypal.com"; /// for production mode

 /// Change the clientId and secret given by PayPal to your own.
 String clientId =
     'Here add clientId';
 String secret =
     'Here add secretId';

 /// for obtaining the access token from Paypal
 Future<String?> getAccessToken() async {
   try {
     var client = BasicAuthClient(clientId, secret);
     var response = await client.post(
         Uri.parse('$domain/v1/oauth2/token?grant_type=client_credentials'));
     if (response.statusCode == 200) {
       final body = convert.jsonDecode(response.body);
       return body["access_token"];
     }
     return null;
   } catch (e) {
     rethrow;
   }
 }

 // for generating the PayPal payment request
 Future<Map<String, String>?> createPaypalPayment(
     transactions, accessToken) async {
   try {
     var response = await http.post(Uri.parse("$domain/v1/payments/payment"),
         body: convert.jsonEncode(transactions),
         headers: {
           "content-type": "application/json",
           'Authorization': 'Bearer ' + accessToken
         });

     final body = convert.jsonDecode(response.body);
     if (response.statusCode == 201) {
       if (body["links"] != null && body["links"].length > 0) {
         List links = body["links"];

         String executeUrl = "";
         String approvalUrl = "";
         final item = links.firstWhere((o) => o["rel"] == "approval_url",
             orElse: () => null);
         if (item != null) {
           approvalUrl = item["href"];
         }
         final item1 = links.firstWhere((o) => o["rel"] == "execute",
             orElse: () => null);
         if (item1 != null) {
           executeUrl = item1["href"];
         }
         return {"executeUrl": executeUrl, "approvalUrl": approvalUrl};
       }
       return null;
     } else {
       throw Exception(body["message"]);
     }
   } catch (e) {
     rethrow;
   }
 }

 /// for carrying out the payment process
 Future<String?> executePayment(url, payerId, accessToken) async {
   try {
     var response = await http.post(url,
         body: convert.jsonEncode({"payer_id": payerId}),
         headers: {
           "content-type": "application/json",
           'Authorization': 'Bearer ' + accessToken
         });

     final body = convert.jsonDecode(response.body);
     if (response.statusCode == 200) {
       return body["id"];
     }
     return null;
   } catch (e) {
     rethrow;
   }
 }
}

To submit the order and payment details to PayPal, we will now create a payment screen.

payment screen

GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
 String? checkoutUrl;
 String? executeUrl;
 String? accessToken;
 PaypalServices services = PaypalServices();

 // You may alter the default value to whatever you like.
 Map<dynamic, dynamic> defaultCurrency = {
   "symbol": "USD ",
   "decimalDigits": 2,
   "symbolBeforeTheNumber": true,
   "currency": "USD"
 };

 bool isEnableShipping = false;
 bool isEnableAddress = false;

 String returnURL = 'return.example.com';
 String cancelURL = 'cancel.example.com';

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

   Future.delayed(Duration.zero, () async {
     try {
       accessToken = await services.getAccessToken();

       final transactions = getOrderParams();
       final res =
           await services.createPaypalPayment(transactions, accessToken);
       if (res != null) {
         setState(() {
           checkoutUrl = res["approvalUrl"];
           executeUrl = res["executeUrl"];
         });
       }
     } catch (ex) {
       final snackBar = SnackBar(
         content: Text(ex.toString()),
         duration: const Duration(seconds: 10),
         action: SnackBarAction(
           label: 'Close',
           onPressed: () {
             // Some code for undoing the alteration.
           },
         ),
       );
       _scaffoldKey.currentState!.showSnackBar(snackBar);
     }
   });
 }

 // item name, price and quantity here
 String itemName = 'One plus 10';
 String itemPrice = '100';
 int quantity = 1;

 Map<String, dynamic> getOrderParams() {
   List items = [
     {
       "name": itemName,
       "quantity": quantity,
       "price": itemPrice,
       "currency": defaultCurrency["currency"]
     }
   ];

   // Checkout Invoice Specifics
   String totalAmount = '100';
   String subTotalAmount = '100';
   String shippingCost = '0';
   int shippingDiscountCost = 0;
   String userFirstName = 'john';
   String userLastName = 'smith';
   String addressCity = 'USA';
   String addressStreet = "i-10";
   String addressZipCode = '44000';
   String addressCountry = 'Pakistan';
   String addressState = 'Islamabad';
   String addressPhoneNumber = '+1 223 6161 789';

   Map<String, dynamic> temp = {
     "intent": "sale",
     "payer": {"payment_method": "paypal"},
     "transactions": [
       {
         "amount": {
           "total": totalAmount,
           "currency": defaultCurrency["currency"],
           "details": {
             "subtotal": subTotalAmount,
             "shipping": shippingCost,
             "shipping_discount": ((-1.0) * shippingDiscountCost).toString()
           }
         },
         "description": "The payment transaction description.",
         "payment_options": {
           "allowed_payment_method": "INSTANT_FUNDING_SOURCE"
         },
         "item_list": {
           "items": items,
           if (isEnableShipping && isEnableAddress)
             "shipping_address": {
               "recipient_name": userFirstName + " " + userLastName,
               "line1": addressStreet,
               "line2": "",
               "city": addressCity,
               "country_code": addressCountry,
               "postal_code": addressZipCode,
               "phone": addressPhoneNumber,
               "state": addressState
             },
         }
       }
     ],
     "note_to_payer": "Contact us for any questions on your order.",
     "redirect_urls": {"return_url": returnURL, "cancel_url": cancelURL}
   };
   return temp;
 }

 @override
 Widget build(BuildContext context) {
   print(checkoutUrl);

   if (checkoutUrl != null) {
     return Scaffold(
       appBar: AppBar(
         backgroundColor: Theme.of(context).backgroundColor,
         leading: GestureDetector(
           child: const Icon(Icons.arrow_back_ios),
           onTap: () => Navigator.pop(context),
         ),
       ),
       body: WebView(
         initialUrl: checkoutUrl,
         javascriptMode: JavascriptMode.unrestricted,
         navigationDelegate: (NavigationRequest request) {
           if (request.url.contains(returnURL)) {
             final uri = Uri.parse(request.url);
             final payerID = uri.queryParameters['PayerID'];
             if (payerID != null) {
               services
                   .executePayment(executeUrl, payerID, accessToken)
                   .then((id) {
                 widget.onFinish!(id);
                 Navigator.of(context).pop();
               });
             } else {
               Navigator.of(context).pop();
             }
             Navigator.of(context).pop();
           }
           if (request.url.contains(cancelURL)) {
             Navigator.of(context).pop();
           }
           return NavigationDecision.navigate;
         },
       ),
     );
   } else {
     return Scaffold(
       key: _scaffoldKey,
       appBar: AppBar(
         leading: IconButton(
             icon: const Icon(Icons.arrow_back),
             onPressed: () {
               Navigator.of(context).pop();
             }),
         backgroundColor: Colors.black12,
         elevation: 0.0,
       ),
       body: const Center(child: CircularProgressIndicator()),
     );
   }
 }

Your desired output is 👍

flutter paypal github complete code

https://github.com/kevalv001/paypal_demo.git

Conclusion

This was a brief overview of the PayPal services; I covered the service in the post; you may modify the code to suit your needs. I believe you now have enough information from this blog to experiment with PayPal in your flutter projects.

Thank you very much!!Have a Good day…..