
How to Accept Payments in Your Flutter Application
By Rexford A. Nyarko
Technological innovations have made it very easy to own an online shop or e-commerce business and to integrate products or services into websites or mobile apps. One thing you need to ensure if you’re an online seller is that you’re offering your customers or users a range of payment options.
TheRapyd Collect API is a service offered byRapyd that allows you to collect payments from customers online or within your app, including one-time, recurring, subscription, or business-to-business payments.
It provides flexibility for your customers by offering access to almost any payment method in almost any country, without the need to set up or manage extra infrastructure.
In this article, you’ll learn how to integrate payments into a Flutter app using the Rapyd Collect API via their Hosted Checkout Page. The only prerequisite for the integration is having a Rapyd account.
The example app used in this tutorial is a simple Flutter mobile application that allows users to donate money to a cause, which was built using aUI design from dribbble artistEmir Abiyyu.
As your use case might be different, this article focuses mainly on the integration and not the building of the entire app from scratch. The complete source code can be foundon GitHub.
Setting Up Your Rapyd Account
As stated earlier, the only prerequisite for integrating the Collect API into your application is a Rapyd account.
Sign Up
You first need to go through the simple process ofsetting up your Rapyd account. You’ll need to verify your email by clicking on the confirmation link sent to the email address provided and also complete multifactor authentication with a mobile number.
Enable Sandbox Mode
After you create your Rapyd account and log in, you have to enable sandbox mode. This provides a sandbox environment to explore Rapyd’s functions and products, including tests and simulations you can try without altering your account.
To enable the sandbox mode, flip the sandbox switch at the bottom of the main navigation on the left side of the dashboard as shown in this image.
Access and Secret Keys
To use any of Rapyd's APIs, you’ll need the access and secret keys as part of the authentication credentials. To find these keys, from the navigation menu, go toDevelopers > Credential Details on the left. Copy and save them for use later in this tutorial.
Creating and Customizing a Rapyd Checkout Page
To ensure users have a seamless transition between your website and the checkout page, you should customize your Rapyd checkout page to match the theme of your website. You may want to add your company logo or the app logo and thematic color for the buttons. Rapyd provides basic customizations to help you achieve this. These customizations can be found in the settings menu on the left navigation of the dashboard underBranding.
There are various options to customize the look and feel of your checkout page, andRapyd has an extensive guide to customizations.
For this tutorial, a logo was added, the payment options were changed to remove “bank redirect” and “cash”, a color preference for the buttons to match the mobile app was set, and the wording for the call to action was changed from "Place your order" to "Donate".
The following image is the final mobile view after the changes.
Creating or Preparing the Flutter App for Integration
If you already have a Flutter application you want to work with, you can skip to the next section. But if you prefer to follow along with the prebuilt dummy for this tutorial, please continue reading.
Clone App
From your terminal or command prompt with Git installed, run the command below to clone the project files from GitHub:
$git clone https://github.com/Rapyd-Samples/flutter-donation
Change Branch
The default branch for this repo is thedev
branch, which contains the completed code for this tutorial, but to follow along you can switch to thebasic
branch, which only contains the basic app code without the Collect API integrated:
$git checkout basic
Initial App Run
You can run the application or any supported connected device with the following command:
$flutter run
You should see a user interface identical to the one below.
Understanding the Current Basic App
As you can see from the previous screenshots, the app consists of three main screens, the main or home screen, theDetails screen, and theDonate screen.The app is not dynamic or data-driven; it’s just a bunch of widgets created to build the UI as in the artwork referenced earlier. The only functionality here is the ability to navigate between screens.
From the main screen, tapping on the main widget takes you to theDetails screen. TheDetails screen presents more information about the cause. Again, the only functional thing on this screen is theDonate Now button at the bottom, which takes you to theDonate page.
TheDonate screen provides four donation value options, which you can easily select by tapping, or you can directly enter an amount in theEnter Price Manually text box below the options.
ThePay & Confirm button (currently just capturing the values) will later take you to the checkout screen where you can see the Rapyd Collect API in action; however, the checkout page has not yet been created in this part of the tutorial and is the focus of the next section.
Generating the Rapyd Checkout Page
To start with the integration, you first need to make a basic HTTP POST request to the Collect API to create the checkout page and then display it. In this section, you’ll write the necessary code to make that request.
Creating a Class
You create a directory calledpayment
under thelib
directory of your project, and in that directory, create a new filerapyd.dart
. In the following lines of code, replace the keys with the respective values from your dashboard, and place the code into the file to create a class and declare some constants that are needed:
import‘dart:convert’;Import‘dart:math’;classRapyd{// Declaring variablesfinalString_ACCESS_KEY="YOUR-ACCESS-KEY";finalString_SECRET_KEY="YOUR-SECRET-KEY";finalString_BASEURL="https://sandboxapi.rapyd.net";finaldoubleamount;Rapyd(this.amount);}
The constructor of this class requiresamount
to be passed to it. This will be the amount selected or typed on theDonate screen of the app.
Adding the Necessary Packages
You need to add the following packages to your app:http
for making the request,crypto
to access and run some cryptographic algorithms, andconvert
for text encoding functions:
- Add the
http
package to your application:
$flutter pub add"http";
- Add the
crypto
package to the application:
$flutter pub add"crypto";
- Add the
convert
package:
$flutter pub add"convert";
- Add the imports for the packages to the top of the
rapyd.dart
file:
import'package:convert/convert.dart';import'package:http/http.dart'ashttp;import'package:crypto/crypto.dart';
Generating Random String for Salt
According to the documentation, requests are accompanied by a random eight to sixteen character string containing digits, letters, and special characters. This is achieved with the code below, which you need to paste in the class definition right after the constructor:
//1. Generating random string for each request with specific length as saltString_getRandString(intlen){varvalues=List<int>.generate(len,(i)=>Random.secure().nextInt(256));returnbase64Url.encode(values);}
Building the Request Body
The body will hold various key value pairs that will be passed along in the HTTP request and used to configure the checkout page you're creating. You can paste the following code snippet below the previous method:
//2. Generating bodyMap<String,String>_getBody(){return<String,String>{"amount":amount.toString(),"currency":"USD","country":"US","complete_checkout_url":"https://www.rapyd.net/cancel","cancel_checkout_url":"https://www.rapyd.net/cancel"};}
Here, you specify theamount
,currency
, andcountry
as required by the API. Two non-required options are also defined,cancel_checkout_url
andcomplete_checkout_url
, which determine the pages that the user will be redirected to when they either cancel or complete the transaction. You can also define this from the client portal.
Note that there’s a completelist of options that can be specified when creating the checkout page.
Generating the Signature
The Rapyd API documentation provides information about securing requests by signing them using a signature that’s generated by a number of characters, encoding functions, and cryptographic functions.
Below is the entire code snippet on each step to get this working properly:
//3. Generating SignatureString_getSignature(StringhttpMethod,StringurlPath,Stringsalt,Stringtimestamp,StringbodyString){//concatenating string values together before hashing string according to Rapyd documentationStringsigString=httpMethod+urlPath+salt+timestamp+_ACCESS_KEY+_SECRET_KEY+bodyString;//passing the concatenated string through HMAC with the SHA256 algorithmHmachmac=Hmac(sha256,utf8.encode(_SECRET_KEY));Digestdigest=hmac.convert(utf8.encode(sigString));varss=hex.encode(digest.bytes);//base64 encoding the results and returning it.returnbase64UrlEncode(ss.codeUnits);}
Building the Headers
The various values generated earlier are put together to build a set of request headers to help authenticate and securely undertake the request in the snippet below:
//4. Generating HeadersMap<String,String>_getHeaders(StringurlEndpoint,{Stringbody=""}){//generate a random string of length 16Stringsalt=_getRandString(16);//calculating the unix timestamp in secondsStringtimestamp=(DateTime.now().toUtc().millisecondsSinceEpoch/1000).round().toString();//generating the signature for the request according to the docsStringsignature=_getSignature("post",urlEndpoint,salt,timestamp,body);//Returning a map containing the headers and generated valuesreturn<String,String>{"access_key":_ACCESS_KEY,"signature":signature,"salt":salt,"timestamp":timestamp,"Content-Type":"application/json",};}
Making the Request to Create the Checkout Page
Finally, you write the function to make the HTTP request. When successful, the method is expected to return aMap
with the created checkout page details. If the request fails, the function will throw an error with aMap
of error details from the API service. Both are used later in this tutorial:
//5. making post requestFuture<Map>createCheckoutPage()async{finalresponseURL=Uri.parse("$_BASEURL/v1/checkout");finalStringbody=jsonEncode(_getBody());//making post request with headers and body.varresponse=awaithttp.post(responseURL,headers:_getHeaders("/v1/checkout",body:body),body:body,);MaprepBody=jsonDecode(response.body)asMap;//return data if request was successfulif(response.statusCode==200){returnrepBody["data"]asMap;}//throw error if request was unsuccessfulthrowrepBody["status"]asMap;}
Retrieving and Displaying the Rapyd Checkout Page
After successfully creating the checkout page, you need to display the page. This can be done by allowing the user to complete the process in a web browser on the same device running the application, or you can embed a web view in the application to provide a seamless feel and more control, as well as to keep the user in your app.
Create the CheckoutScreen Widget
In thescreens
directory in thelib
directory of your project, there’s an empty file calledCheckoutScreen.dart
.
In this file, you can use the following snippet to create a stateful widget that accepts an instance of theRapyd
class and returns aScaffold
widget:
import'package:donation/payment/rapyd.dart';import'package:donation/widgets/back_button.dart';import'package:flutter/material.dart';import'package:webview_flutter/webview_flutter.dart';classCheckOutScreenextendsStatefulWidget{finalRapydrapyd;constCheckOutScreen({super.key,requiredthis.rapyd});@overrideState<StatefulWidget>createState(){return_CheckOutScreenState();}}class_CheckOutScreenStateextendsState<CheckOutScreen>{@overrideWidgetbuild(BuildContextcontext){returnScaffold(resizeToAvoidBottomInset:true,appBar:AppBar(leading:CustomBackButton(),title:constAlign(child:Text("Checkout",textAlign:TextAlign.center,style:TextStyle(color:Colors.black,fontWeight:FontWeight.bold)),),backgroundColor:Colors.white,actions:const[SizedBox(width:55,),],elevation:0,),);}}
Initialize Request to Create Checkout Page
In the_CheckoutScreenState
, declare a variable of typeFuture<Map>
and initialize it by calling thecreateCheckoutPage()
method of theRapyd
object passed to this widget.
This means that once theCheckoutScreen
is launched, the request to create the checkout page is executed and the results are stored in the created checkout page variable. This can be implemented with the following code snippet:
...lateFuture<Map>createdCheckoutPage;@overridevoidinitState(){super.initState();createdCheckoutPage=widget.rapyd.createCheckoutPage();}...
Adding Navigation to the Open Checkout Page
Once you've created the basic widgets for the checkout screen, you need to modify the button on theDonateScreen
widget to also navigate to theCheckoutScreen
widget when clicked, passing on the value to be paid in an instance of theRapyd
class as a parameter to theCheckoutScreen
widget.
To do this, first add the following lines of imports to thelib/screens/DonateScreen.dart
file:
import'package:donation/payment/rapyd.dart';import'package:donation/screens/CheckoutScreen.dart';
Next, in the same file, replace theproceed
method of theDonateScreen
widget class with the code in the following snippet:
voidproceed(context){if(selected==0){selectedAmount=double.parse(controller.text);}Rapydrapyd=Rapyd(selectedAmount);Navigator.push(context,MaterialPageRoute(builder:(context)=>CheckOutScreen(rapyd:rapyd)));}
In the same file, you should also modify the definition of theMaterialButton
widget for thePay & Confirm button by passing the context to theproceed
method call as seen below:
...onPressed:(){proceed(context);},...
Using a FutureBuilder
At this point, the users see no indication of the process running to create the checkout page when the checkout screen is launched. Since the API request call may take a few seconds, it’s good practice to display a busy or loading status. You can use a future builder to show the user a progress indicator until that method call completes and returns a result.
The future builder also enables you to show an appropriate widget based on the returned result. For example, if the request is successful, a web page is loaded to continue the process, and if the request is unsuccessful, the user is directed to another widget with an error.
In theCheckoutScreen.dart
file, add the following snippet for thebody
of theScaffold
widget:
body:FutureBuilder(future:createdCheckoutPage,builder:(BuildContextcontext,AsyncSnapshot<dynamic>snapshot){switch(snapshot.connectionState){caseConnectionState.waiting:returnconstCenter(child:CircularProgressIndicator());default:if(snapshot.hasError){returnconstCenter(child:Text('Some error occurred!'));}else{returnText("Success");}}},)
Adding the webview_flutter Package
To display a web page within the app without exiting or navigating outside the app, you use a web view plug-in, which can be added by using the following command:
$flutter pub add"webview_flutter"
For Android builds, you’re required to set the minimumminSdkVersion
inandroid/app/build.gradle
to 19, as seen below:
android{defaultConfig{minSdkVersion19//previously: flutter.minSdkVersion}}
Displaying Page in a Webview
Now add theWebView
widget to display the checkout page by passing theredirect\_url
value from the successful response of the request made earlier. This can be done by replacing thereturn Text("Success");
line with the following:
returnWebView(initialUrl:snapshot.data["redirect_url"].toString(),javascriptMode:JavascriptMode.unrestricted,);
Returning to the App Donate Page from Webview
A user may decide to complete the payment or cancel the payment. Once they cancel or complete the payment you need to return to theDonateScreen
from theCheckoutScreen
. To do this, you can use theonPageStarted
parameter of theWebView
widget to detect changes to the URL during a redirect from the checkout page.
If the URL contains the value of thecancel_checkout_url
or thecomplete_checkout_url
, the app will exit theCheckoutScreen
widget. The value of theonPageStarted
parameter should look like the following:
onPageStarted:(url){//Exit webview widget once the current url matches either checkout completed or canceled urlsif(url.contains(snapshot.data["complete_checkout_url"])){Navigator.pop(context);}elseif(url.contains(snapshot.data["cancel_checkout_url"])){Navigator.pop(context);}},
Running the App
Now, using either a virtual or physically connected device, you can run the app using the following command:
$flutter run
You should now have a functioning app with Rapyd Collect API integrated and working, and a Hosted Checkout Page that looks like the following image.
Conclusion
In this tutorial, you learned how to accept payments from users in your Flutter app using the Rapyd Collect API. You also learned how to customize your checkout page with elements like your logo, color, and payment options. You saw how to generate the signature and headers needed to make secure and authenticated requests to the Rapyd API.
Finally, you learned how to display the checkout web page within your app and how to exit the web page seamlessly, and return to your app screens.
TheRapyd Collect API is a payment solution that provides a plethora of options for your customers or app users to patronize your products and services across the globe without limitations. Integration is simple, secure, and flexible.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse