The smarter way
  • Getting Started
  • USER GUIDE
    • Payment Gateway
    • Currencies
    • Apple Pay
      • Setup MPGS
      • Setup Cybersource
    • Payment Tracking
      • Payment Transactions Insights
      • Payment Transactions States
      • Notifications, URLs & Timing
    • Plugins
      • Payment Request
      • E-Commerce
      • Bulk payment request
    • Features
      • Refund & Void Access Control
      • Two-Step Refund & Void Authorization
    • Integration
    • Configuration
      • Global Configuration
      • Webhooks Configuration
      • Transaction Report Configuration
      • How to Get API Keys
      • URL Shortener Configuration
    • Notification Communication Channels
      • Email Notifications
      • SMS Notifications
      • WhatsApp Notifications
        • Integrated WhatsApp Channel
        • Manual WhatsApp Channel
      • Notification Templates
      • Notification Process: Automatic and Manual
    • Satellite
    • Real Estate
      • Regular Activities
        • Property management
        • Tenant and Contract Management
          • Tenant & Contract Dashboard
          • Tenant Management
          • Contract Management
            • Add New Contract
            • Contract Action
              • Renew Contract
              • Terminate Contract
              • Manual Payment
              • Suspend Contract
              • Resume Contract
              • Advance Payment
        • Generate Invoice
        • Invoices Management
        • Maintenance
        • Transactions
        • Auditing and Rolling Back Activities
      • Merchant First Journey
  • developer
    • Getting Started
    • Tokenization
    • Authentication
    • Payment Methods
    • Checkout API
    • Operations
    • User Cards
    • Payment Status-Inquiry
    • Auto-Debit
    • Invoice API
    • Message Notifications
    • Upload Attachment
    • Checkout SDK
      • Web
      • iOS
      • Android
      • Flutter
    • Webhooks
      • Payment Notification
      • Operation Notification
      • Signing Mechanism
      • Integration Guides
        • Laravel Webhook Receiver Guide
        • .NET Webhook Receiver Guide
    • Test Cards
Powered by GitBook
On this page
  • Installation
  • Android
  • iOS
  • UI
  • Android
  • SDK Configuration
  • Language
  • Light and Dark Theme
  • SDK Initialization
  • Properties
  • Callbacks
  • Android
  • iOS
  • Example
  • Customization Theme
  • Properties Description
  • Data types description
  • Example
  • Payment Options Display Mode
  • STC Pay
  • KNET - Apple Pay
  • Onsite Checkout
  • Error Reporting
  • Cyber Security Measures
  • Rooting and Jailbreak Detection
  • Screen Capture Prevention
  • FAQ
  1. developer
  2. Checkout SDK

Flutter

The Checkout SDK is a Flutter framework (library) developed by Ottu, designed to seamlessly integrate an Ottu-powered checkout process into Flutter applications for both iOS and Android platforms. This framework functions as a wrapper over the corresponding native SDKs, ensuring a smooth and efficient payment experience.

With the Checkout SDK, both the visual appearance and the forms of payment available during the checkout process can be fully customized to meet specific requirements.

To integrate the Checkout SDK, the library must be added to the Flutter application and initialized with the following parameters:

  • merchant_id

  • session_id

  • API key

Additionally, optional configurations such as the forms of payment to be accepted and the theme styling for the checkout interface can be specified.

Installation

To install the Flutter SDK plugin, the following section must be added to the pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter

  ottu_flutter_checkout:
    # To use ottu_flutter_checkout SDK from a local source, uncomment the line below 
    # and comment out the three lines specifying the Git repository.
    # path: ../ottu_flutter_checkout

    git:
      url: https://github.com/ottuco/ottu-flutter.git
      ref: main

And then run flutter pub get command in the terminal.

After adding the dependency, run the following command in the terminal to fetch the required packages: flutter pub get

Android

Minimum Requirements

The SDK can be used on devices running Android 8 (Android SDK 26) or higher.

iOS

Minimum Requirements

The SDK can be used on devices running iOS 15 or higher.

UI

Android

The SDK UI is embedded as a fragment within any part of an activity in the merchant's application.

Example:

If only one payment option is available and it is a wallet, the UI is automatically minimized.

SDK Configuration

Language

The SDK supports two languages: English and Arabic, with English set as the default.

The SDK automatically applies the language based on the device settings, eliminating the need for manual adjustments within the application.

However, if the transaction is created in a different language and setup preload is enabled, texts retrieved from the backend (such as fee descriptions) will be displayed in the transaction language, regardless of the device’s language settings.

To ensure consistency, the current device language should be taken into account when specifying a language code in the transaction creation request of the Checkout API.

Light and Dark Theme

The SDK supports automatic UI adjustments based on the device's theme settings (light or dark mode).

The appropriate theme is applied during SDK initialization, aligning with the device's configuration. Similar to language settings, no manual adjustments are required within the application.

SDK Initialization

The Checkout SDK is initialized using the CheckoutArguments class, which includes the properties listed below.

To initialize the SDK, an instance of CheckoutArguments must be passed as an argument to the OttuCheckoutWidget object.

For a detailed implementation example, refer to the Example section.

Properties

merchantId string required

It is used to define the Ottu merchant domain and must be set to the root domain of the Ottu account, excluding the https:// or http:// prefix.

For example, if the Ottu URL is https://example.ottu.com, the corresponding merchant_id is example.ottu.com.

This property is required to ensure that the checkout process is correctly linked to the associated Ottu merchant account.

apiKey string required

It is the Ottu API public key, used for authentication when communicating with Ottu's servers during the checkout process.

Ensure that only the public key is used. The private key must remain confidential and must never be shared with any clients.

sessionId string required

It is a unique identifier for the payment transaction associated with the checkout process.

This identifier is automatically generated when a payment transaction is created. For further details on how to use the session_id parameter in the Checkout API, refer to the session_id documentation.

formsOfPayment array optional

The formsOfPayment parameter is used to customize the forms of payment displayed in the checkout process. By default, all forms of payment are enabled.

Available options for formsOfPayment:

  • applePay: The Apple Pay payment method is supported, allowing purchases to be made using Apple Pay-enabled devices.

  • cardOnsite: A direct (onsite) payment method, where customers are required to enter their card details directly within the SDK.

  • tokenPay: A method utilizing tokenization, ensuring that customer payment information is securely stored and processed.

  • redirect: A payment method where customers are redirected to an external payment gateway or a third-party processor to complete the transaction.

  • stcPay: A method where customers enter their mobile number and authenticate using an OTP sent to their mobile device.

setupPreload object optional

An ApiTransactionDetails class object is used to store transaction details. If provided, transaction details will not be requested from the backend, thereby reducing processing time.

theme object optional

A Theme class object is used for UI customization. All fields are optional and may include values for background colors, text colors, and fonts for various UI components.

For more details, refer to Android Customization Theme.

displaySettings object optional

The displaySettings object accepts a PaymentOptionsDisplaySettings configuration, which defines how payment options are presented to the user during checkout. For more details, refer to the Payment Options Display Mode section.

successCallback, errorCallback, and successCallback unit required

Callback functions are used to retrieve the payment status. These must be provided directly to the Checkout initialization function. For more information, please check here.

Callbacks

The callbacks are handled by the native frameworks. Please see the links here:

  • Android Callbacks

  • iOS Callbacks

It is not necessary to modify anything for the callbacks, as they are managed by the native SDK.

However, the following examples demonstrate how they function on both platforms:

Android

The callbacks are defined within the body of the Checkout.init function:

val sdkFragment = Checkout.init(
  context = checkoutView.context,
  builder = builder,
  setupPreload = apiTransactionDetails,
  successCallback = {
    Log.e("TAG", "successCallback: $it")
    showResultDialog(checkoutView.context, it)
  },
  cancelCallback = {
    Log.e("TAG", "cancelCallback: $it")
    showResultDialog(checkoutView.context, it)
  },
  errorCallback = { errorData, throwable ->
    Log.e("TAG", "errorCallback: $errorData")
    showResultDialog(checkoutView.context, errorData, throwable)
  },

iOS

Here is an example of a delegate:

extension CheckoutPlatformView: OttuDelegate {
    
    public func errorCallback(_ data: [String: Any]?) {
        debugPrint("errorCallback\n")
        DispatchQueue.main.async {
            self.paymentViewController?.view.isHidden = true
            self.paymentViewController?.view.setNeedsLayout()
            self.paymentViewController?.view.layoutIfNeeded()
            self._view.heightHandlerView.setNeedsLayout()
            self._view.heightHandlerView.layoutIfNeeded()
            self._view.setNeedsLayout()
            self._view.layoutIfNeeded()
            
            let alert = UIAlertController(
                title: "Error",
                message: data?.debugDescription ?? "",
                preferredStyle: .alert
            )
            alert.addAction(
                UIAlertAction(title: "OK", style: .cancel)
            )
            debugPrint("errorCallback, show alert\n")
            self.paymentViewController?.present(alert, animated: true)
        }
    }
    
    public func cancelCallback(_ data: [String: Any]?) {
        debugPrint("cancelCallback\n")
        DispatchQueue.main.async {
            var message = ""
            
            if let paymentGatewayInfo = data?["payment_gateway_info"] as? [String: Any],
               let pgName = paymentGatewayInfo["pg_name"] as? String,
               pgName == "kpay" {
                message = paymentGatewayInfo["pg_response"].debugDescription
            } else {
                message = data?.debugDescription ?? ""
            }
            
            self.paymentViewController?.view.isHidden = true
            self.paymentViewController?.view.setNeedsLayout()
            self.paymentViewController?.view.layoutIfNeeded()
            self._view.heightHandlerView.setNeedsLayout()
            self._view.heightHandlerView.layoutIfNeeded()
            self._view.setNeedsLayout()
            self._view.layoutIfNeeded()
            
            let alert = UIAlertController(
                title: "Cancel",
                message: message,
                preferredStyle: .alert
            )
            alert.addAction(
                UIAlertAction(title: "OK", style: .cancel)
            )
            debugPrint("cancelCallback, show alert\n")
            self.paymentViewController?.present(alert, animated: true)
        }
    }
    
    public func successCallback(_ data: [String: Any]?) {
        debugPrint("successCallback\n")
        DispatchQueue.main.async {
            self.paymentViewController?.view.isHidden = true
            self._view.paymentSuccessfullLabel.isHidden = false
            self.paymentViewController?.view.setNeedsLayout()
            self.paymentViewController?.view.layoutIfNeeded()
            self._view.heightHandlerView.setNeedsLayout()
            self._view.heightHandlerView.layoutIfNeeded()
            self._view.setNeedsLayout()
            self._view.layoutIfNeeded()
            
            let alert = UIAlertController(
                title: "Success",
                message: data?.debugDescription ?? "",
                preferredStyle: .alert
            )
            alert.addAction(
                UIAlertAction(title: "OK", style: .cancel)
            )
            debugPrint("successCallback, showing alert\n")
            self.paymentViewController?.present(alert, animated: true)
        }
    }
}

Example

final checkoutArguments = CheckoutArguments(
  merchantId: state.merchantId,
  apiKey: state.apiKey,
  sessionId: state.sessionId ?? "",
  amount: amount,
  showPaymentDetails: state.showPaymentDetails,
  paymentOptionsListMode: state.paymentOptionsDisplayMode ?? PaymentOptionsListMode.BOTTOM_SHEET,
  apiTransactionDetails: state.preloadPayload == true ? _apiTransactionDetails : null,
  formsOfPayment: formOfPayments?.isNotEmpty == true ? formOfPayments : null,
  theme: _theme,
);

//

Scaffold(
  appBar: AppBar(
    backgroundColor: Theme.of(context).colorScheme.inversePrimary,
    title: Text(widget.title),
  ),
  body: SingleChildScrollView(
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        SizedBox(height: 46),
        Text(
          "Customer Application",
          textAlign: TextAlign.center,
          style: ts.TextStyle(fontSize: 24),
        ),
        // Start of Merchant content
        const Padding(
          padding: EdgeInsets.all(12.0),
          child: Text(
            "Some users UI elements, Some users UI elements, Some users UI elements, Some users UI elements, Some users UI elements",
          ),
        ),
        // End of Merchant content
        Padding(
          padding: const EdgeInsets.all(12.0),
          child: ValueListenableBuilder<int>(
            builder: (BuildContext context, int height, Widget? child) {
              return SizedBox(
                height: height.toDouble(),
                child: OttuCheckoutWidget(arguments: widget.checkoutArguments),
              );
            },
            valueListenable: _checkoutHeight,
          ),
        ),
        const SizedBox(height: 20),
      ],
    ),
  ),
);

The code samples can be found here.

To access the actual code samples, navigate to the lib directory.

Additionally, the android and ios directories contain platform-specific code relevant to each respective environment.

Customization Theme

The class responsible for defining the theme is called CheckoutTheme. It utilizes additional component classes, including:

  • ButtonComponent

  • LabelComponent

  • TextFieldComponent

The CheckoutTheme class consists of objects representing various UI components. While the component names generally align with those listed above, they also contain platform-specific fields for further customization.

Below is the structure of the Customization Theme class:

class CheckoutTheme extends Equatable {
  @_UiModeJsonConverter()
  final CustomerUiMode uiMode;
  
  final TextStyle? mainTitleText;
  final TextStyle? titleText;
  final TextStyle? subtitleText;
  final TextStyle? feesTitleText;
  final TextStyle? feesSubtitleText;
  final TextStyle? dataLabelText;
  final TextStyle? dataValueText;
  final TextStyle? errorMessageText;

  final TextFieldStyle? inputTextField;

  final ButtonComponent? button;
  final RippleColor? backButton;
  final ButtonComponent? selectorButton;
  final SwitchComponent? switchControl;
  final Margins? margins;

  final ColorState? sdkBackgroundColor;
  final ColorState? modalBackgroundColor;
  final ColorState? paymentItemBackgroundColor;
  final ColorState? selectorIconColor;
  final ColorState? savePhoneNumberIconColor;
}

uiMode

Specifies the device Theme mode, which can be set to one of the following:

  • light – Forces the UI to use light mode.

  • dark – Forces the UI to use dark mode.

  • auto – Adapts the UI based on the device's system settings.

Properties Description

All properties in the CheckoutTheme class are optional, allowing users to customize any of them as needed.

If a property is not set, the default value (as specified in the Figma design here) will be applied automatically.

Texts

General

Property Name
Description
Data Type

mainTitleText

Font and color for all “Captions”

titleText

Font and color for payment options in the list

subtitleText

Font and color for payment options details (like expiration date)

Fees

Property Name
Description
Data Type

feesTitleText

Font and color of fees value in the payment options list

feesSubtitleText

Font and color of fees description in the payment options list

Data

Property Name
Description
Data Type

dataLabelText

Font and color of payment details fields (like “Amount”)

dataValueText

Font and color of payment details values

Other

Property Name
Description
Data Type

errorMessageText

Font and color of error message text in pop-ups

Text Fields

Property Name
Description
Data Type

inputTextField

Font and color of text in any input field (including disabled state)

Colors

Property Name
Description
Data Type

sdkbackgroundColor

The main background of the SDK view component

modalBackgroundColor

The background of any modal window

paymentItemBackgroundColor

The background of an item in payment options list

selectorIconColor

The color of the icon of the payment

savePhoneNumberIconColor

The color of “Diskette” button for saving phone number

Buttons

Property Name
Description
Data Type

button

Background, text color and font for any button

backButton

Color of the “Back” navigation button

selectorButton

Background, text color and font for payment item selection button

Switch

Property Name
Description
Data Type

switch

Colors of the switch background and its toggle in different states (on, off and disabled)

Margins

Property Name
Description
Data Type

margins

Top, left, bottom and right margins between component

Data types description

Color

Property Name
Description
Data Type

color

Main color integer value

Int

colorDisabled

Disabled stated color integer value

Int

RippleColor

Property Name
Description
Data Type

color

Main color integer value

Int

rippleColor

Ripple color integer value

Int

colorDisaled

Disabled stated color integer value

Int

Text

Property Name
Description
Data Type

textColor

Main color integer value

fontType

Font resource ID

Int

TextField

Property Name
Description
Data Type

background

Background color integer value

primaryColor

Text color

focusedColor

Selected text color

text

Text value

error

Text value

Button

Property Name
Description
Data Type

rippleColor

Button background color

fontType

Button text font ID

Int

textColor

Button text color

Switch

Property Name
Description
Data Type

checkedThumbTintColor

Toggle color in checked state

Int

uncheckedThumbTintColor

Toggle color in unchecked state

Int

checkedTrackTintColor

Track color in checked state

Int

uncheckedTrackTintColor

Track color in unchecked state

Int

checkedTrackDecorationColor

Decoration color in checked state

Int

uncheckedTrackDecorationColor

Decoration color in unchecked state

Int

Margin

Property Name
Data Type

left

Int

top

Int

right

Int

bottom

Int

Example

To build the theme, the user must follow similar steps as described in the corresponding file of the test app.

Here is a code snippet demonstrating the process:

final checkoutTheme = ch.CheckoutTheme(
  uiMode: ch.CustomerUiMode.dark,
  titleText: ch.TextStyle(),
  modalBackgroundColor: ch.ColorState(color: Colors.amber));

Payment Options Display Mode

The SDK provides flexible customization for how payment options are displayed. It supports the following optional parameters:

  • mode: Determines the layout style—either BottomSheet (default) or List.

    • BottomSheet: This is the default layout used in previous SDK versions.

    • List: A new layout that shows payment options in a vertical list placed above the Payment Details section and the Pay button.

  • visibleItemsCount: Sets how many payment options are shown at once (default is 5). Applicable only in List mode.

    • This unsigned integer controls how many payment options are visible simultaneously in List mode.

    • If the number of available options is less than visibleItemsCount, the list automatically resizes to fit the actual number of options.

Passing 0 will cause the SDK to throw an exception. This exception must be caught and handled by the parent application.

  • defaultSelectedPgCode: Specifies a payment gateway (PG) code to be pre-selected by default.

    • This field accepts a PG code to auto-select a specific payment option.

    • If the SDK finds a payment method matching the provided PG code, it will be selected by default.

    • If no match is found, no option is selected.

All of these parameters are optional and are demonstrated in the following figures.

Android

The List The List mode is displayed as illustrated in the figure below

A view with a selected payment option

A view with an expanded listExpanded list view

Here is a code sample:

val paymentOptionsDisplayMode =
  if (showPaymentOptionsList) Checkout.PaymentOptionsDisplaySettings.PaymentOptionsDisplayMode.List(
    visiblePaymentItemsCount = paymentOptionsListCount
  ) else Checkout.PaymentOptionsDisplaySettings.PaymentOptionsDisplayMode.BottomSheet
val paymentOptionsDisplaySettings = Checkout.PaymentOptionsDisplaySettings(
  mode = paymentOptionsDisplayMode,
  defaultSelectedPgCode = defaultSelectedPgCode
)

and passed to Checkout.init builder class via the following object:

.paymentOptionsDisplaySettings(paymentOptionsDisplaySettings)

iOS

The List mode looks like the following

Selected item view

Expanded list view

Here is a code sample:

let paymentOptionsDisplaySettings: PaymentOptionsDisplaySettings =
  if arguments.showPaymentOptionsList {
    PaymentOptionsDisplaySettings(
      mode: .list,
      visibleItemsCount: UInt(arguments.paymentOptionsListCount),
      defaultSelectedPgCode: arguments.defaultSelectedPgCode
    )
  } else {
    PaymentOptionsDisplaySettings(
      mode: .bottomSheet,
      defaultSelectedPgCode: arguments.defaultSelectedPgCode
    )
  }

and passed to Checkout.init via the following object:

displaySettings:paymentOptionsDisplaySettings

To see the full function call, please refer the code snippet in the Ottu SDK - Flutter | Example section.

STC Pay

If the STC Pay integration between Ottu and STC Pay has been completed, the Checkout SDK will automatically handle the necessary checks to display the STC Pay button seamlessly.

When the Checkout SDK is initialized with the session_id and payment gateway codes (pg_codes), the SDK will verify the following conditions:

  • The session_id and pg_codes provided during initialization must be associated with the STC Pay Payment Service. This ensures that the STC Pay option is available for the customer.

  • In the Android SDK, the STC Pay button is displayed regardless of whether the customer has entered a mobile number while creating the transaction.

KNET - Apple Pay

Due to compliance requirements, for iOS, the KNET payment gateway requires a popup notification displaying the payment result after each failed payment. This notification is triggered only in the cancelCallback, but only if a response is received from the payment gateway.

As a result, the user cannot retry the payment without manually clicking on Apple Pay again.

The popup notification mentioned above is specific to the KNET payment gateway.Other payment gateways may have different requirements or notification mechanisms, so it is essential to follow the respective documentation for each integration.

To properly handle the KNET popup notification, the following Swift code snippet must be implemented into the payment processing flow:

This is only iOS-related stuff, so the callbacks are native and so they are in Swift language.

func cancelCallback(_ data: [String: Any]?) {
    var message = ""
    
    if let paymentGatewayInfo = data?["payment_gateway_info"] as? [String: Any],
       let pgName = paymentGatewayInfo["pg_name"] as? String,
       pgName == "kpay" {
        message = paymentGatewayInfo["pg_response"].debugDescription
    } else {
        message = data?.debugDescription ?? ""
    }
    
    navigationController?.popViewController(animated: true)
    
    let alert = UIAlertController(
        title: "Cancel",
        message: message,
        preferredStyle: .alert
    )
    
    alert.addAction(UIAlertAction(title: "OK", style: .cancel))
    self.present(alert, animated: true)
}

Function Breakdown

The above code performs the following checks and actions:

  1. Checks if the cancelCallback object contains payment gateway information

    • It verifies whether the payment_gateway_info field is available in the response.

  2. Identifies if the payment gateway used is KNET

    • It checks if the pg_name property equals kpay, confirming that the transaction was processed using KNET.

  3. Check the above two conditions are met by retrieving the payment gateway response

    • If the gateway response (pg_response) is available, it is displayed; otherwise, a default message (Payment was cancelled.) is used.

  4. Navigates back and displays an alert

    • The user is returned to the previous screen (navigationController?.popViewController(animated: true)).

    • A popup notification is displayed using self.present(alert, animated: true), informing the user about the failed payment.

Onsite Checkout

This payment option enables direct payments through the mobile SDK. The SDK presents a user interface where the customer can enter their cardholder details (CHD). If supported by the backend, the user can also save the card for future payments—stored as a tokenized payment method.

The onsite checkout screen appears identical to the native platform version.

Android

iOS

The SDK supports multiple instances of onsite checkout payments. Therefore, for each payment method with a PG code equal to ottu_pg, the card form (as shown above) will be displayed.

Android

iOS

No fees are displayed for onsite checkout instances. This is due to the support for multiple multi-card (omni PG) configurations. The presence of multiple payment icons is used to indicate this multi-card feature.

Error Reporting

The SDK utilizes Sentry for error logging and reporting. It is initialized based on the configuration provided by SDK Studio.

However, since the SDK is a framework embedded within the merchant's app, conflicts may arise if the app also integrates Sentry.

To prevent conflicts, the merchant can disable Sentry within the Checkout SDK by setting the is_enabled flag to false in the configuration.

Cyber Security Measures

Rooting and Jailbreak Detection

The Flutter SDK does not perform rooting or jailbreak detection independently. Instead, these security checks are entirely handled by the native SDKs.

For more details, refer to the following links:

Android

iOS

Screen Capture Prevention

The SDK includes mechanisms to prevent screen capturing (such as screenshots and video recordings) on screens that display sensitive information. The Flutter SDK does not handle this independently; instead, it relies on the logic implemented in the native SDKs for Android and iOS.

Since the implementation differs between the two platforms, please refer to the respective native documentation for more details.

Android

iOS

FAQ

The SDK supports the following forms of payment:

  • tokenPay

  • redirect

  • stcPay

  • cardOnsite

  • applePay (iOS only)

Merchants can configure the forms of payment displayed according to their needs.

For example, to display only the STC Pay button, use:

formsOfPayment = [stcPay]

This ensures that only the STC Pay button is shown. The same approach applies to other payment methods.

The SDK requires a device running:

  • Android 8 or higher (API level 26 or higher)

  • iOS 14 or higher

Yes, customization is supported. For more details, refer to the Customization Theme section.

PreviousAndroidNextWebhooks

Last updated 20 hours ago

What forms of payment are supported by the SDK?

What are the minimum system requirements for SDK integration?

Can I customize the appearance beyond the provided themes?

1️
2️
3️
Text
Text
Text
Text
Text
Text
Text
Text
TextField
Color
Color
Color
Color
Color
Button
RippleColor
Button
Switch
Margin
Color
Color
Color
Color
Text
Text
RippleColor
Color