Flutter Embed
The PortOne Flutter SDK offers merchants a seamless way to integrate the PortOne Payment Gateway into their Flutter applications, enabling them to accept payments securely and efficiently. This SDK serves as a bridge between a merchant's app and the PortOne Payment Gateway, providing a comprehensive set of tools and features tailored specifically for handling payment transactions.
The PortOne Flutter SDK empowers merchants to unlock the full potential of their Flutter applications by seamlessly integrating a reliable and secure payment gateway, enhancing user experience, and driving business growth through efficient payment processing capabilities
Video Tutorial
Sample App
Check the sample app to integrate on GitHub
Prerequisites
- Create an account on PortOne:
Before proceeding with the integration, ensure you have created an account on PortOne to access their services and functionalities. - Enable Payment Channels and Methods:
Customize and enable the specific payment channels and methods that align with your business requirements and preferences. - Access API Keys
Login to the portone portal where you can access the API Keys ( portone key and secret key) for integrations under Settings -> API tab. - Flutter application for the integration:
You will need an Flutter application in which you intend to integrate the PortOne Flutter SDK for payment processing capabilities.
Integration
Steps to integrate your Flutter application with PortOne Flutter SDK.
- Configure the Flutter SDK with the Flutter App
- Set the Intent Filters in the manifests
- Add a listener to listen the payment status
- Setup to Obtain JWT Token from the Server
- Generate a Signature Hash for Payload
1. Configure the Flutter SDK with the Flutter App
-
Retrieve the Flutter package distributed by the PortOne team and ensure it is placed at the same directory level as your Flutter application within the folder structure.
-
To integrate the necessary dependencies in your Flutter project, you can update the
pubspec.yaml
file with the following configuration:dependencies: flutter: sdk: flutter portone_flutter_package: path: /Users/flutter_app_sdk/flutter_sdk app_links: ^6.1.1
Parameters Description portone_flutter_package This is the package where the portone flutter sdk lies and it also has one param name path which requires the path of the sdk.
In above code the given path is dummy please put the path where your portone sdk lies.app_links: ^6.1.1 The app_links package plays a crucial role in your application by enabling the reception of intents from deep links or other applications. Its functionality is essential for capturing payment status updates seamlessly within your Flutter app
2. Enable deep links
-
For Android:
-
Change the project structure to Android from Project or open the android module as project in IDE
-
To add an Intent Filter to the activity in your AndroidManifest.xml file so that users are navigated to a specific activity (default being Checkout Activity) after payment completion
<activity android:name=".CheckoutActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="portone" android:host="checkout" /> </intent-filter> </activity>
In this setup:
- TheÂ
<intent-filter>
 block defines the conditions under which the activity should be launched. - TheÂ
<data>
 tag specifies the scheme and host required in the incoming Intent for it to be directed to this activity after payment completion. - TheÂ
<activity>
 tag specifies the activity to which the Intent Filter applies.
- TheÂ
Update the activity name (e.g.,
.CheckoutActivity
) as per your actual activity name and place this Intent Filter configuration within the corresponding<activity>
tag in the AndroidManifest.xml file to handle post-payment navigation effectively.By configuring the scheme as "
portone
" and host as "checkout
" within the<data>
tag of the Intent Filter, your Android application will be able to intercept the redirection URL with the format "portone://checkout" and navigate the user to the specified activity (e.g., CheckoutActivity) after payment completion. Adjust the activity name in the configuration according to your actual activity name for proper redirection handling. -
-
For iOS:
-
To open your application, add the url schemes to the app, Go to ProjectSettings -> info
-
Add url schemes and identifier inside the URL types.
You can see the scheme and identifier details in info.plist as below:
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleTypeRole</key> <string>Editor</string> <key>CFBundleURLName</key> <string>checkout</string> <key>CFBundleURLSchemes</key> <array> <string>portone</string> </array> </dict> </array>
-
To open the other applications, should include the url schemes in info.plist
<key>LSApplicationQueriesSchemes</key> <array> <string>itms-appss</string> <string>zalopay</string> <string>line</string> <string>ascendmoney</string> </array>
LSApplicationQueriesSchemes - Specifies the URL schemes you want the app to be able to use with the canOpenURL: method of the UIApplication class.
-
3. Add a listener to listen the payment status by the callback to initState()
initState()
-
Receiving Payment Status:
a. Set up app-to-app communication to receive a deep link via intent post-checkout.
b. In the root stateful widget, implement
initState()
anddispose()
methods.c. Declare variables:
late AppLinks _appLinks; StreamSubscription<Uri>? _linkSubscription;
-
Initialization in
initState()
:a. Initialize
initState()
method to handle payment status reception:@override void initState() { super.initState(); initDeepLinks(); } Future<void> initDeepLinks() async { _appLinks = AppLinks(); _linkSubscription = _appLinks.uriLinkStream.listen((uri) { portone.processPaymentStatus(uri,$environment); }); }
-
Dispose Method Handling:
a. To cancel the subscription and avoid memory leaks, implement
dispose()
:@override void dispose() { _linkSubscription?.cancel(); super.dispose(); }
-
Adding Payment Status Listener:
a. Implement the following method to capture checkout status post payment completion:
portone.setPaymentStatusListener( callback: (Map<String, dynamic> paymentStatus) { print('PortOne_PaymentStatus-> $paymentStatus'); });
4. Have a setup to get JWT token from the server
The PortOne SDK requires a JWT token for authentication. You need to implement a server-side process to generate this token and retrieve it in your Android app.
Steps:
- Implement server logic to generate a JWT token.
- In your Android app, fetch the token to process the checkout.
The process for generating a JWT token can be found in detail here
5. Generate Signture Hash
To generate a signature hash, create it on the server side using a secret key that will be included in the payload. This ensures secure processing of transactions.
Steps:
- Implement server logic to generate a signature hash.
- In your Android app, fetch the signature hash to process the checkout.
The process for generating a Signature Hash can be found in detail here
Flutter Embed
PortOne's Checkout offers a streamlined integration experience, simplifying the process for merchants. This variant involves calling a single method with the essential payload, which results in the PortOne SDK opening a webpage seamlessly. By handling the user interface within the SDK, merchants can focus on the payment flow without concerns about UI intricacies.
Video Tutorial
Implementation
This is the method that has been utilised to process the web checkout.
portone.checkoutUsingWeb(token,
portoneKey, WebCheckoutRequest());
Parameters | Data Type | |
---|---|---|
token | String | mandatory |
portoneKey | String | mandatory |
request | WebCheckoutRequest | mandatory |
WebCheckoutRequest()
WebCheckoutRequest()
All of the web checkout request's parameters are listed here, along with the appropriate data type.
Parameters | Data Type | |
---|---|---|
portoneKey | String | mandatory |
merchantDetails | CheckoutPaymentDto.MerchantDetails | |
merchantOrderId | String | mandatory |
signatureHash | String | mandatory |
amount | Double | mandatory |
currency | String | mandatory |
countryCode | String | mandatory |
billingDetails | CheckoutPaymentDto.BillingDetails | Optional |
shippingDetails | CheckoutPaymentDto.ShippingDetails | Optional |
orderDetails | List<CheckoutPaymentDto.OrderDetail> | Optional |
successUrl | String | mandatory |
failureUrl | String | mandatory |
expiryHours | Int | mandatory |
source | String | mandatory |
description | String | Optional |
showShippingDetails | Boolean | Optional |
showBackButton | Boolean | Optional |
defaultGuestCheckout | Boolean | Optional |
isCheckoutEmbed | Boolean | Optional |
redirectUrl | String | mandatory |
environment | String | mandatory |
MerchantDetails
MerchantDetails
Parameters | Data Type | |
---|---|---|
name | String | Optional |
logo | String | Optional |
backUrl | String | Optional |
promoCode | String | Optional |
promoDiscount | Int | Optional |
shippingCharges | Double | Optional |
CheckoutPaymentDto.BillingDetails
CheckoutPaymentDto.BillingDetails
Parameters | Data Type | |
---|---|---|
shippingName | String | Optional |
shippingEmail | String | Optional |
shippingPhone | String | Optional |
shippingAddress | CheckoutPaymentDto.Address | Optional |
CheckoutPaymentDto.ShippingDetails
CheckoutPaymentDto.ShippingDetails
Parameters | Data Type | |
---|---|---|
billingName | String | Optional |
billingEmail | String | Optional |
billingPhone | String | Optional |
billingAddress | CheckoutPaymentDto.Address | Optional |
CheckoutPaymentDto.Address
CheckoutPaymentDto.Address
Parameters | Data Type | |
---|---|---|
city | String | Optional |
countryCode | String | Optional |
locale | String | Optional |
line_1 | String | Optional |
line_2 | String | Optional |
postal_code | String | Optional |
state | String | Optional |
CheckoutPaymentDto.OrderDetail
CheckoutPaymentDto.OrderDetail
Parameters | Data Type | |
---|---|---|
id | String | Optional |
price | Double | Optional |
name | String | Optional |
quantity | Int | Optional |
image | String (in the form of web url) | Optional |
After the payment completion the payment status will be received on paymentStatus listener which we have already added while integration.
Response:
Receiving the payment status within the override method paymentStatus listener is a common practice in integration to handle payment callbacks. By implementing this method during the integration process, developers can capture and process the payment status information returned by the payment gateway or SDK. This allows for real-time feedback on the payment's success or failure, enabling further actions to be taken based on the outcome of the transaction.
Possible Error Scenarios:
INVALID_UNAUTHORIZED_JWT_TOKEN_ERROR
INVALID_UNAUTHORIZED_JWT_TOKEN_ERROR
- Ensure that the PortOne Key and Secret Key belong to the same account.
- Confirm that the Secret Key has not been altered.
- Verify that theÂ
Bearer
 keyword precedes the generated token with a space. Example:ÂBearer $jwtToken
. - Check if the token expiration time is after the current time.
INVALID_UNAUTHORIZED_TRANSACTION_SIGNATURE_ERROR
INVALID_UNAUTHORIZED_TRANSACTION_SIGNATURE_ERROR
- Validate if all parameters align with the payload/request.
- Ensure that the PortOne key matches with the payload and the account.
INVALID_UNAUTHORIZED_TRANSACTION_IAMPORTKEY_ERROR
INVALID_UNAUTHORIZED_TRANSACTION_IAMPORTKEY_ERROR
- Confirm that the PortOne key matches with the payload and the account.
INVALID_PAYMENT_CHANNEL
INVALID_PAYMENT_CHANNEL
- Validate that the payment channels and methods included in the payload are enabled in the PortOne portal.
INVALID_ENVIRONMENT
INVALID_ENVIRONMENT
- Verify that an environment (
sandbox
 orÂlive
) has been specified.
Summation of order value, tax, duties, shipping, and discount should equal the total amount
Summation of order value, tax, duties, shipping, and discount should equal the total amount
- If items are provided, ensure that the values match the total amount calculation formula:Â
sum(items price * items quantity) + shipping charge - discount = amount
. - Mandatory parameters in the payload:
- price
- promo_discount (0 accepted)
- shipping_charges (0 accepted)
Updated about 12 hours ago