Flutter SDKs

You can easily integrate your Apps with our Flutter SDKs

Introduction

The Taly Flutter SDK enables you to integrate the Taly Payment Gateway into your Flutter application for both Android and iOS platforms. It exposes a clean Dart API backed by native platform channels, so your Flutter code remains fully cross-platform while Taly's native iOS and Android SDKs handle all payment logic under the hood.

The typical integration workflow is:

  1. Initialize — Authenticate with your merchant credentials before your app renders any UI.
  2. Initiate Payment — Build an order model and hand it off to the SDK to launch the native payment screen.
  3. Handle Results — Listen to onPaymentSuccess, onPaymentFailure, and onPaymentError callbacks.
  4. Banner (optional) — Drop TalyBannerView onto any product screen to show "split into 4 payments" messaging automatically.

Requirements

RequirementMinimum Version
Flutter>=3.10.0
Dart SDK>=3.0.0 <4.0.0
iOS deployment target13.0+
Android minSdkVersion21+

Installation

Add sdk_flutter to your project's pubspec.yaml:

dependencies:
  sdk_flutter:
    git:
      url: https://github.com/taly-io/taly-flutter-sdk.git
      ref: main

Then fetch the package:

flutter pub get

iOS — Additional Setup

The Taly Flutter SDK wraps the native Taly iOS SDK (.xcframework). After running flutter pub get, navigate to the ios directory and install the CocoaPods dependencies:

cd ios && pod install

If the native framework requires manual embedding, open ios/Runner.xcworkspace in Xcode:

  1. Drag & drop TalySdk.xcframework into your project's target.
  2. Set the embedding to Embed & Sign in the target's Frameworks, Libraries, and Embedded Content section.

Android — Additional Setup

No additional steps are required for Android. The Taly Android SDK dependency is resolved automatically through the plugin's build.gradle.


Setup SDK

Import the Package

In every Dart file where you use the SDK, add the import:

import 'package:sdk_flutter/sdk_flutter.dart';

Usage

The example app bundled with the SDK (example/lib/main.dart) is a simple online shopping demo that highlights end-to-end integration. The steps below mirror that workflow.

1. Initialize TalyFlutterSdk

Call TalyFlutterSdk.initialize() once, as early as possible — ideally before runApp() in main(). You need:

  • userName — Your merchant username for authentication.
  • password — Your merchant password for authentication.
  • environmentEnvironment.development for testing, Environment.production for live.
import 'package:flutter/material.dart';
import 'package:sdk_flutter/sdk_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await TalyFlutterSdk.initialize(
    userName:    'YOUR_USER_NAME',
    password:    'YOUR_PASSWORD',
    environment: Environment.development, // or Environment.production
  );

  runApp(const MyApp());
}

Note for iOS only: The oauthGrantType and oauthScope parameters correspond to the iOS native TokenRequest (grantType: "password", scope: "api"). Android sets OAuth internally and ignores these values. The defaults ('password' and 'api') match the Taly iOS SDK requirements and do not need to be changed under normal circumstances.


2. Register Payment Callbacks

After initialization, assign the static callback handlers so your app receives payment outcomes. These can be set anywhere — initState() of your checkout screen is a common place:

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

  TalyFlutterSdk.onPaymentSuccess = (PaymentSuccess result) {
    // Handle successful payment
    print('Payment succeeded: ${result.talyOrderId}');
  };

  TalyFlutterSdk.onPaymentFailure = (PaymentFailure failure) {
    // Handle a failed payment (e.g. user cancelled, card declined)
    print('Payment failed: ${failure.status}');
  };

  TalyFlutterSdk.onPaymentError = (PaymentError error) {
    // Handle SDK/network errors
    print('Payment error: ${error.message}');
  };
}

3. Initiate Payment

Build an InitiatePaymentModel and call TalyFlutterSdk.initiatePayment(). The SDK will launch the native Taly payment screen on top of your Flutter app.

Full Example (all fields)

await TalyFlutterSdk.initiatePayment(
  InitiatePaymentModel(
    merchantOrderId:    DateTime.now().millisecondsSinceEpoch.toString(),
    language:           'en',
    merchantBranch:     'main',
    subTotal:            15.000,
    totalAmount:         15.000,
    currency:            'KWD',
    discountAmount:      0.0,
    taxAmount:           0.0,
    deliveryAmount:      0.0,
    deliveryMethod:      'home delivery',
    otherFees:           0.0,
    isDigitalOrder:      false,
    merchantRedirectUrl: 'https://yourmerchant.com/checkout/',
    postBackUrl:         'https://yourmerchant.com/yourWebhookEndpoint/',
    merchantLogo:        'https://www.yourmerchant.com/media/merchantLogo.png',
    psp: const PSP(
      isPspOrder:      true,
      pspProvider:     'Tap',
      subMerchantId:   1234,
      subMerchantName: 'My Store',
    ),
    orderItems: [
      OrderItem(
        sku:                   '23433312436',
        type:                  'physical',
        name:                  'Blue Shirt',
        nameArabic:            'القميص الأزرق',
        currency:              'KWD',
        itemDescription:       'T-shirt made of cotton',
        itemDescriptionArabic: 'تي شيرت مصنوع من القطن',
        quantity:               1,
        itemPrice:              15.000,
        imageUrl:              'https://www.merchantwebsite.com/item1image.jpg',
        itemUrl:               'https://www.merchantwebsite.com/item1.html',
        itemUnit:              'gm',
        itemSize:              '32',
        itemColor:             'blue',
        itemGender:            'men',
        itemBrand:             'Adidas',
        itemCategory:          'Men>Men\'s Wear>Running',
      ),
    ],
    customerDetails: const CustomerDetails(
      firstName:       'Ahmad',
      lastName:        'Ali',
      gender:          'Male',
      countryCode:     '+965',
      phoneNumber:     '55555333',
      customerEmail:   '[email protected]',
      registeredSince: '2022-10-26',
      loyaltyMember:   true,
      loyaltyLevel:    'VIP',
    ),
    deliveryAddress: const DeliveryAddress(
      city:          'Hawalli',
      area:          'Salmiya',
      fullAddress:   'Hawalli, Salmiya, block 5, building 5, floor 2, flat 6',
      phoneNumber:   '502223333',
      customerEmail: '[email protected]',
    ),
  ),
);

Minimal Example (required fields only)

await TalyFlutterSdk.initiatePayment(
  InitiatePaymentModel(
    merchantOrderId:    DateTime.now().millisecondsSinceEpoch.toString(),
    subTotal:            15.000,
    totalAmount:         15.000,
    currency:            'KWD',
    deliveryMethod:      'home delivery',
    merchantRedirectUrl: 'https://yourmerchant.com/checkout/',
    orderItems: [
      OrderItem(
        sku:        '23433312436',
        name:       'Blue Shirt',
        nameArabic: 'القميص الأزرق',
        currency:   'KWD',
        quantity:    1,
        itemPrice:   15.000,
      ),
    ],
  ),
);

4. Product Banner View

TalyBannerView is a Flutter widget you can embed in any product detail screen. It automatically fetches installment data from the Taly API and displays a "Split into 4 payments of KWD X.XXX" message, reinforcing Taly as a payment option at the point of consideration.

TalyBannerView(
  amount:   '15.000',   // Product price as a string
  currency: 'KWD',
  name:     'Blue Shirt',  // optional product name
  quantity: 1,             // optional quantity
  onInfoClicked: (String url) {
    // Called when the user taps the ⓘ info button
    // url is always 'https://Taly.io/how-it-works'
    // Open a WebView, launch a URL, or show a dialog
    launchUrl(Uri.parse(url));
  },
)

The widget manages its own state and automatically re-fetches when amount, currency, or quantity props change. It renders one of three states:

StateDescription
LoadingA circular progress indicator while fetching
BannerInstallment messaging with the Taly logo
ErrorAn error icon with a "Something went wrong" message

Prerequisite: TalyFlutterSdk.initialize() must be called before rendering TalyBannerView.


5. Fetch Installments (Manual)

If you need raw installment data to build your own custom banner UI, call fetchInstallments() directly:

final List<InstallmentModel> installments = await TalyFlutterSdk.fetchInstallments(
  name:     'Blue Shirt',
  quantity: 1,
  amount:   '15.000',
  currency: 'KWD',
);

for (final inst in installments) {
  print('Installment ${inst.nbOfInstallment}: ${inst.currency} ${inst.amount} on ${inst.dueDate}');
}

API Reference

TalyFlutterSdk

The main entry point of the SDK. All members are static — do not instantiate this class.

class TalyFlutterSdk { ... }

Static Callbacks

PropertyTypeDescription
onPaymentSuccessvoid Function(PaymentSuccess)?Invoked when a payment completes successfully.
onPaymentFailurevoid Function(PaymentFailure)?Invoked when a payment fails (e.g. card declined, user cancelled).
onPaymentErrorvoid Function(PaymentError)?Invoked when an SDK or network error occurs during the payment process.

Static Methods

initialize()

Authenticates with the Taly platform and sets up the native SDK on both iOS and Android. Must be awaited before calling any other SDK method.

static Future<void> initialize({
  required String userName,
  required String password,
  Environment environment = Environment.production,
  String oauthGrantType = 'password',
  String oauthScope = 'api',
})
ParameterTypeRequiredDefaultDescription
userNameStringYour merchant username.
passwordStringYour merchant password.
environmentEnvironmentEnvironment.productionTarget environment.
oauthGrantTypeString'password'iOS only — OAuth grant type for TokenRequest.
oauthScopeString'api'iOS only — OAuth scope for TokenRequest.

initiatePayment()

Launches the native Taly payment screen. Results are delivered via the onPaymentSuccess, onPaymentFailure, and onPaymentError callbacks.

static Future<void> initiatePayment(InitiatePaymentModel model)
ParameterTypeRequiredDescription
modelInitiatePaymentModelThe full order details. See InitiatePaymentModel.

fetchInstallments()

Retrieves the installment schedule for a given product and amount. Used internally by TalyBannerView and available for building custom banner UI.

static Future<List<InstallmentModel>> fetchInstallments({
  required String name,
  required int    quantity,
  required String amount,
  required String currency,
})
ParameterTypeRequiredDescription
nameStringProduct name.
quantityintProduct quantity. Must be > 0.
amountStringProduct price as a string (e.g. '15.000').
currencyStringCurrency code (e.g. 'KWD').

Returns: Future<List<InstallmentModel>> — An ordered list of installment details.


setPrimaryColor()

Overrides the primary accent color used in the Taly native payment screen.

static Future<void> setPrimaryColor(int colorInt)
ParameterTypeDescription
colorIntintARGB integer color value. Use Color.value from Flutter's Color class.

Example:

await TalyFlutterSdk.setPrimaryColor(const Color(0xFF1565C0).value);

setLanguageCode()

Sets the display language for the native Taly payment screen.

static Future<void> setLanguageCode(String code)
ParameterTypeDescription
codeStringBCP 47 language code. Supported values: 'en' (English), 'ar' (Arabic).

Example:

await TalyFlutterSdk.setLanguageCode('ar');

setLogLevel()

Controls the verbosity of SDK log output. Called automatically with LogLevel.verbose after initialize().

static Future<void> setLogLevel(LogLevel level)
ParameterTypeDescription
levelLogLevelDesired log verbosity. See LogLevel.

Example:

await TalyFlutterSdk.setLogLevel(LogLevel.error); // production builds

TalyBannerView (Widget)

A Flutter StatefulWidget that displays a Taly installment banner on product screens. Internally calls TalyFlutterSdk.fetchInstallments() and re-fetches whenever its props change.

class TalyBannerView extends StatefulWidget {
  const TalyBannerView({
    super.key,
    this.name = '',
    this.quantity = 1,
    required this.amount,
    required this.currency,
    this.onInfoClicked,
  });
}

Properties

PropertyTypeRequiredDefaultDescription
amountStringProduct price as a string (e.g. '15.000').
currencyStringCurrency code (e.g. 'KWD').
nameString''Product name, passed to the installments API.
quantityint1Product quantity, passed to the installments API.
onInfoClickedvoid Function(String url)?nullCalled when the user taps the ⓘ icon. The url parameter is always 'https://Taly.io/how-it-works'.

Models

InitiatePaymentModel

Represents a complete order passed to TalyFlutterSdk.initiatePayment().

const InitiatePaymentModel({
  required String merchantOrderId,
  required double subTotal,
  required double totalAmount,
  required String currency,
  required String deliveryMethod,
  required List<OrderItem> orderItems,
  required String merchantRedirectUrl,
  String?  language,            // default: 'en'
  String?  merchantBranch,      // default: 'main'
  double   discountAmount,      // default: 0.0
  double   taxAmount,           // default: 0.0
  double   deliveryAmount,      // default: 0.0
  double?  otherFees,
  bool?    isDigitalOrder,      // default: false
  String?  postBackUrl,
  String?  merchantLogo,
  PSP      psp,                 // default: PSP()
  CustomerDetails customerDetails, // default: CustomerDetails()
  DeliveryAddress deliveryAddress, // default: DeliveryAddress()
})
FieldTypeRequiredDefaultDescription
merchantOrderIdStringYour unique order ID. Recommended: DateTime.now().millisecondsSinceEpoch.toString().
subTotaldoubleOrder subtotal before discounts/fees.
totalAmountdoubleFinal order total charged to the customer.
currencyStringISO 4217 currency code (e.g. 'KWD').
deliveryMethodStringDelivery method description (e.g. 'home delivery').
orderItemsList<OrderItem>One or more items in the order.
merchantRedirectUrlStringURL the SDK redirects to after payment completion.
languageString?'en'Language code for the payment screen ('en' or 'ar').
merchantBranchString?'main'Merchant branch identifier.
discountAmountdouble0.0Total discount applied to the order.
taxAmountdouble0.0Tax amount.
deliveryAmountdouble0.0Shipping / delivery fee.
otherFeesdouble?nullAny additional fees.
isDigitalOrderbool?falseSet to true for digital goods orders.
postBackUrlString?nullWebhook endpoint for server-to-server order status notifications.
merchantLogoString?nullPublicly accessible URL of your merchant logo shown on the payment screen.
pspPSPPSP()Payment Service Provider details.
customerDetailsCustomerDetailsCustomerDetails()Customer demographic information.
deliveryAddressDeliveryAddressDeliveryAddress()Customer delivery address.

OrderItem

Represents a single product in an order.

FieldTypeRequiredDefaultDescription
skuStringStock Keeping Unit — unique product identifier.
nameStringProduct name in English.
nameArabicStringProduct name in Arabic.
currencyStringCurrency code for this item (e.g. 'KWD').
quantityintNumber of units.
itemPricedoubleUnit price.
typeString?'physical'Item type: 'physical' or 'Digital'.
itemDescriptionString?nullProduct description in English.
itemDescriptionArabicString?nullProduct description in Arabic.
imageUrlString?nullPublicly accessible product image URL.
itemUrlString?nullProduct page URL on your website.
itemUnitString?nullUnit of measure (e.g. 'gm', 'kg').
itemSizeString?nullProduct size.
itemColorString?nullProduct color.
itemGenderString?nullTarget gender (e.g. 'men', 'women', 'kids').
itemBrandString?nullBrand name (e.g. 'Adidas').
itemCategoryString?nullCategory path (e.g. 'Men>Men\'s Wear>Running').

CustomerDetails

Optional customer information sent with an order for fraud detection and analytics.

FieldTypeRequiredDescription
firstNameString?Customer's first name.
lastNameString?Customer's last name.
genderString?Customer's gender (e.g. 'Male', 'Female').
countryCodeString?Phone country code (e.g. '+965').
phoneNumberString?Customer's phone number (without country code).
customerEmailString?Customer's email address.
registeredSinceString?Date the customer registered, ISO 8601 format (e.g. '2022-10-26').
loyaltyMemberbool?Whether the customer is in a loyalty programme.
loyaltyLevelString?Loyalty tier name (e.g. 'VIP', 'Gold').

DeliveryAddress

Optional delivery address sent with an order.

FieldTypeRequiredDescription
cityString?Delivery city (e.g. 'Hawalli').
areaString?Delivery area / district (e.g. 'Salmiya').
fullAddressString?Full street address.
phoneNumberString?Contact phone number for delivery.
customerEmailString?Contact email for delivery.

PSP

Payment Service Provider information for PSP-routed orders.

FieldTypeRequiredDefaultDescription
isPspOrderbool?falseSet to true if this order is routed through a PSP.
pspProviderString?nullPSP provider name (e.g. 'Tap').
subMerchantIdint?nullSub-merchant ID assigned by the PSP.
subMerchantNameString?nullSub-merchant name.

PaymentSuccess

Returned via onPaymentSuccess when a payment completes successfully.

FieldTypeDescription
orderTokenString?Taly order token.
talyOrderIdint?Taly's internal order ID.
merchantOrderIdString?Your original merchant order ID.
statusString?Order status string (e.g. 'approved').
totalAmountdouble?Total amount charged.
currencyString?Currency code.
paymentPlanIdString?ID of the selected Taly payment plan.
paymentPlanNameString?Name of the selected Taly payment plan.
orderDateString?ISO 8601 order creation timestamp.
merchantIdint?Your merchant ID on the Taly platform.
merchantNameString?Your merchant name on the Taly platform.
branchIdint?Branch ID associated with the order.
branchNameString?Branch name.
branchTypeString?Branch type.
settlementTypeString?Settlement method.
settlementStatusString?Settlement status.
totalReturnAmountdouble?Total amount returned (refunds).
totalRefundAmountdouble?Total amount refunded.
redirectUrlString?The merchant redirect URL the order was completed on.
postBackUrlString?Webhook URL used for this order.
merchantLogoString?Merchant logo URL used during checkout.
pspPaymentSuccessPsp?PSP details echoed back from the order.
toJson()String

Serializes the result to a JSON string for logging or server forwarding.


PaymentFailure

A type alias for PaymentSuccess:

typedef PaymentFailure = PaymentSuccess;

The same fields are available. Inspect status to determine the reason for failure.


PaymentError

Returned via onPaymentError when an SDK or network error prevents the payment from being processed.

FieldTypeDescription
statusString?HTTP status or error category.
messageString?Human-readable error message.
errorsList<String>List of detailed error strings (may be empty).
errorCodeString?Machine-readable error code.
merchantOrderIdString?The merchant order ID that triggered the error (if available).
toJson()String

Serializes the error to a JSON string.


InstallmentModel

Represents a single installment in the payment schedule returned by fetchInstallments().

FieldTypeDescription
amountdoubleAmount due for this installment.
currencyStringCurrency code.
dueDateStringISO 8601 due date for this installment.
dueDateDescStringHuman-readable due date description.
nbOfInstallmentintInstallment number (1-based, e.g. 1 = first installment).
noOfInstallmentDescStringDescription of installment position (e.g. '1st').
statusStringInstallment status.
finalAmountdoubleFinal total after all installments are paid.

Enums

Environment

Controls which Taly backend the SDK communicates with.

ValueDescription
Environment.developmentDevelopment / sandbox environment — use for testing.
Environment.productionProduction environment — use for live merchant transactions.
await TalyFlutterSdk.initialize(
  userName:    'YOUR_USER_NAME',
  password:    'YOUR_PASSWORD',
  environment: Environment.production,
);

LogLevel

Controls the verbosity of SDK log output.

ValueDescription
LogLevel.verboseAll messages, including detailed trace output. (Default after initialize())
LogLevel.debugDebug messages and above.
LogLevel.infoInformational messages and above.
LogLevel.warningWarnings and above.
LogLevel.errorErrors only. Recommended for production builds.
LogLevel.noneNo log output.
// Development
await TalyFlutterSdk.setLogLevel(LogLevel.verbose);

// Production
await TalyFlutterSdk.setLogLevel(LogLevel.error);

Customization

Primary Color

Override the SDK's primary accent color to match your brand:

// Use Flutter's Color.value (ARGB integer)
await TalyFlutterSdk.setPrimaryColor(const Color(0xFF1565C0).value);

Language

Switch the payment screen language. Must match a locale supported by your app:

await TalyFlutterSdk.setLanguageCode('ar'); // Arabic
await TalyFlutterSdk.setLanguageCode('en'); // English (default)

For Arabic, ensure your Flutter app declares ar as a supported locale:

MaterialApp(
  supportedLocales: const [
    Locale('en'),
    Locale('ar'),
  ],
  localizationsDelegates: const [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  ...
)

Error Handling

The SDK surfaces errors through three mechanisms:

1. Payment Callbacks

Register onPaymentError to catch SDK-level errors (authentication failures, network timeouts, invalid order data):

TalyFlutterSdk.onPaymentError = (PaymentError error) {
  // Log for diagnostics
  debugPrint('Taly error [${error.errorCode}]: ${error.message}');
  // Show user-friendly message
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('Payment could not be completed. Please try again.')),
  );
};

2. try / catch on fetchInstallments()

fetchInstallments() and other SDK methods are async and may throw. Wrap them in try/catch:

try {
  final installments = await TalyFlutterSdk.fetchInstallments(
    name:     'Blue Shirt',
    quantity: 1,
    amount:   '15.000',
    currency: 'KWD',
  );
  // use installments
} catch (e) {
  debugPrint('Failed to fetch installments: $e');
  // Gracefully degrade — hide the banner, show a fallback, etc.
}

3. TalyBannerView Error State

TalyBannerView handles its own errors internally and renders an error icon if fetchInstallments() fails. No additional error handling is required in the host widget.

Common Error Scenarios

ScenarioCallback / ExceptionRecommended Action
Wrong credentialsonPaymentErrorerrorCode: 'auth_failed'Verify userName / password.
initialize() not calledException thrown from initiatePayment()Always call initialize() before any other SDK method.
Network unavailableonPaymentErrorShow a connectivity error message and retry.
Invalid order dataonPaymentErrorValidate all required fields in InitiatePaymentModel.
Quantity ≤ 0 in bannerBanner renders error stateEnsure quantity > 0 before displaying TalyBannerView.
Empty amount in bannerBanner renders error stateEnsure amount is a non-empty, positive numeric string.

Best Practices

  1. Initialize once, early. Call TalyFlutterSdk.initialize() in main() before runApp(). Avoid calling it multiple times.

  2. Use Environment.development during development. Switch to Environment.production only in release builds. Consider using Dart's compilation flags or a flavors setup to select the environment automatically.

  3. Generate unique merchantOrderId values. Using DateTime.now().millisecondsSinceEpoch.toString() is a reliable approach. Duplicate order IDs may cause unexpected behavior.

  4. Set LogLevel.error in production. LogLevel.verbose is useful during development but generates significant output in production.

    await TalyFlutterSdk.setLogLevel(
      kReleaseMode ? LogLevel.error : LogLevel.verbose,
    );
  5. Assign callbacks before navigating to checkout. Set onPaymentSuccess, onPaymentFailure, and onPaymentError before calling initiatePayment() to guarantee you never miss a result.

  6. Dispose controllers alongside callbacks. Callback references are static. If your widget is disposed, avoid using context inside the callback without checking mounted:

    TalyFlutterSdk.onPaymentSuccess = (result) {
      if (!mounted) return;
      // safe to use context here
    };
  7. Show TalyBannerView only when a valid amount is available. Conditionally render the banner widget to avoid unnecessary API calls:

    if (amount.isNotEmpty)
      TalyBannerView(amount: amount, currency: 'KWD')
  8. Provide postBackUrl for server-side verification. Always verify payment status server-to-server via the webhook before fulfilling an order — do not rely solely on the client-side callback.

  9. Supply customerDetails and deliveryAddress when possible. These fields improve Taly's risk scoring and increase approval rates for your customers.

  10. Handle both onPaymentFailure and onPaymentError. Failure indicates a completed transaction that was declined; error indicates the transaction could not be submitted. Both require different UX responses.