PlexySDK DOCS

Flutter SDK

Integrate Plexy with Flutter mobile applications

Flutter SDK

The official Plexy SDK for Flutter. Build a full checkout with Drop-in, or compose individual payment Components. Works on both iOS and Android, with the Sessions flow (recommended) or the Advanced flow.

Requirements

  • Flutter 3.16 or later
  • Dart 3.2 or later
  • iOS 12 or later
  • Android API level 21 (Android 5.0) or later
  • Plexy Checkout API v2 or later

Installation

Add the package to your app:

flutter pub add plexy_checkout

Or add it manually to pubspec.yaml:

dependencies:
  plexy_checkout: ^2.0.0

Then run flutter pub get.

Platform Setup

Android

  1. Set minSdkVersion to 21 in android/app/build.gradle:
android {
    defaultConfig {
        minSdkVersion 21
    }
}
  1. Make sure your project uses Kotlin 1.8.22 or later and Android Gradle Plugin 8.1 or later.

  2. Change your MainActivity to extend FlutterFragmentActivity — the native Plexy Android SDK requires it:

// android/app/src/main/kotlin/.../MainActivity.kt
import io.flutter.embedding.android.FlutterFragmentActivity

class MainActivity: FlutterFragmentActivity()

iOS

  1. Set the iOS deployment target to 12.0 or later in ios/Podfile:
platform :ios, '12.0'
  1. Add a custom URL scheme for your return URL in ios/Runner/Info.plist:
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>com.yourcompany.yourapp</string>
    </array>
  </dict>
</array>
  1. Forward the return URL to the SDK in ios/Runner/AppDelegate.swift:
override func application(
  _ app: UIApplication,
  open url: URL,
  options: [UIApplication.OpenURLOptionsKey : Any] = [:]
) -> Bool {
  RedirectComponent.applicationDidOpen(from: url)
  return true
}

If you handle other URL schemes in the same AppDelegate, combine the results (e.g. return handledByOther || true) instead of falling through to super, which returns false.

Get the matching return URL at runtime with await PlexyCheckout.instance.getReturnUrl(). Pass this value to your backend when creating a session or payment.

Quick Start: Drop-in with Sessions Flow

The Sessions flow is the simplest way to accept payments. Your backend creates a session, your app renders Drop-in.

1. Create a session on your backend. Call POST /sessions on the Plexy Checkout API with the amount, country, and return URL, and return id and sessionData to your app.

2. Open Drop-in:

import 'package:plexy_checkout/plexy_checkout.dart';

Future<void> startCheckout({
  required String sessionId,
  required String sessionData,
}) async {
  final configuration = DropInConfiguration(
    environment: Environment.test,
    clientKey: 'YOUR_CLIENT_KEY',
    countryCode: 'KZ',
    shopperLocale: 'en-US',
    amount: Amount(currency: 'KZT', value: 10000),
    cardConfiguration: const CardConfiguration(holderNameRequired: true),
  );

  final checkout = await PlexyCheckout.session.create(
    sessionId: sessionId,
    sessionData: sessionData,
    configuration: configuration,
  );

  final result = await PlexyCheckout.session.startDropIn(
    dropInConfiguration: configuration,
    checkout: checkout,
  );

  handleResult(result);
}

See Handling the payment result for handleResult.

Drop-in with Advanced Flow

Use the Advanced flow when you need to control each /payments and /payments/details call yourself.

final configuration = DropInConfiguration(
  environment: Environment.test,
  clientKey: 'YOUR_CLIENT_KEY',
  countryCode: 'KZ',
  amount: Amount(currency: 'KZT', value: 10000),
);

// 1. Fetch payment methods from your backend: POST /paymentMethods
final paymentMethods = await backend.fetchPaymentMethods();

// 2. Wire up callbacks that forward to your backend.
final advancedCheckout = AdvancedCheckout(
  onSubmit: (data, [extra]) async {
    // Backend calls POST /payments, returns the raw response.
    final response = await backend.postPayments(data);
    return Finished(resultCode: response['resultCode'] as String);
    // Return Action(actionResponse: …) if the response requires 3DS/redirect.
  },
  onAdditionalDetails: (details) async {
    final response = await backend.postPaymentsDetails(details);
    return Finished(resultCode: response['resultCode'] as String);
  },
);

final result = await PlexyCheckout.advanced.startDropIn(
  dropInConfiguration: configuration,
  paymentMethods: paymentMethods,
  checkout: advancedCheckout,
);

onSubmit and onAdditionalDetails both return a PaymentEvent:

  • Finished(resultCode) — terminal; Drop-in closes.
  • Action(actionResponse) — Drop-in runs the additional action (3DS, redirect, QR).
  • Update(paymentMethodsJson, orderJson) — refresh Drop-in (used for gift cards / partial payments).
  • Error(errorMessage, reason, dismissDropIn) — show an error.

Configuring Drop-in

DropInConfiguration accepts per-method configs:

final configuration = DropInConfiguration(
  environment: Environment.test,
  clientKey: 'YOUR_CLIENT_KEY',
  countryCode: 'KZ',
  shopperLocale: 'en-US',
  amount: Amount(currency: 'KZT', value: 10000),
  cardConfiguration: CardConfiguration(
    holderNameRequired: true,
    addressMode: AddressMode.postalCode,
    showStorePaymentField: true,
    onBinLookup: (results) { /* co-branded cards, etc. */ },
    onBinValue: (bin) { /* first digits of the PAN */ },
  ),
  applePayConfiguration: ApplePayConfiguration(
    merchantId: 'merchant.com.yourcompany.yourapp',
    merchantName: 'Your Store',
  ),
  googlePayConfiguration: const GooglePayConfiguration(
    googlePayEnvironment: GooglePayEnvironment.test,
    billingAddressRequired: true,
    shippingAddressRequired: false,
  ),
  paymentMethodNames: {'scheme': 'Credit card'},
);

Also available on DropInConfiguration: cashAppPayConfiguration, storedPaymentMethodConfiguration (showing and deleting saved methods), and skipListWhenSinglePaymentMethod. See the plugin source for the full field list of each configuration.

Card Component

Render the Card Component as a Flutter widget inside your own screen. It works with either SessionCheckout or AdvancedCheckout.

final configuration = CardComponentConfiguration(
  environment: Environment.test,
  clientKey: 'YOUR_CLIENT_KEY',
  countryCode: 'KZ',
  shopperLocale: 'en-US',
  cardConfiguration: const CardConfiguration(holderNameRequired: true),
);

final SessionCheckout checkout = await PlexyCheckout.session.create(
  sessionId: sessionId,
  sessionData: sessionData,
  configuration: configuration,
);

// Find the "scheme" payment method inside the session response.
final paymentMethod = (checkout.paymentMethods['paymentMethods'] as List)
    .firstWhere((pm) => pm['type'] == 'scheme') as Map<String, dynamic>;

// …in your widget tree:
PlexyCardComponent(
  configuration: configuration,
  paymentMethod: paymentMethod,
  checkout: checkout,
  onPaymentResult: (result) async {
    Navigator.pop(context);
    handleResult(result);
  },
)

For the Advanced flow, construct an AdvancedCheckout (as shown above) and pass it as checkout. Fetch the list of payment methods from POST /paymentMethods and extract the scheme entry the same way.

Apple Pay Component

final configuration = ApplePayComponentConfiguration(
  environment: Environment.test,
  clientKey: 'YOUR_CLIENT_KEY',
  countryCode: 'KZ',
  applePayConfiguration: ApplePayConfiguration(
    merchantId: 'merchant.com.yourcompany.yourapp',
    merchantName: 'Your Store',
  ),
);

PlexyApplePayComponent(
  configuration: configuration,
  paymentMethod: applePayPaymentMethod, // the "applepay" entry from /paymentMethods or the session
  checkout: checkout,                   // SessionCheckout or AdvancedCheckout
  onPaymentResult: handleResult,
)

Requires the Apple Pay entitlement (Merchant IDs capability) on your iOS app.

Google Pay Component

final configuration = GooglePayComponentConfiguration(
  environment: Environment.test,
  clientKey: 'YOUR_CLIENT_KEY',
  countryCode: 'KZ',
  googlePayConfiguration: const GooglePayConfiguration(
    googlePayEnvironment: GooglePayEnvironment.test,
  ),
);

PlexyGooglePayComponent(
  configuration: configuration,
  paymentMethod: googlePayPaymentMethod, // the "googlepay" entry from /paymentMethods or the session
  checkout: checkout,
  onPaymentResult: handleResult,
)

Google Pay requires Play Services Wallet, which is bundled by the plugin — no extra Gradle changes needed.

Handling the Payment Result

PaymentResult is a sealed class. Switch on it:

void handleResult(PaymentResult result) {
  switch (result) {
    case PaymentSessionFinished(:final resultCode):
      if (resultCode == ResultCode.authorised) {
        // Success. Confirm on your backend via the webhook or GET /sessions/{id}.
      } else {
        // Refused, Cancelled, Error, etc.
      }
    case PaymentAdvancedFinished(:final resultCode):
      // Same resultCode handling as above; confirm via webhook.
    case PaymentCancelledByUser():
      // Shopper dismissed the sheet.
    case PaymentError(:final reason):
      // reason is nullable; may be empty for user-visible errors.
  }
}

ResultCode values: authorised, refused, pending, cancelled, error, received, redirectShopper, identifyShopper, challengeShopper, presentToShopper, partiallyAuthorised, authenticationFinished, authenticationNotRequired, unknown.

Never treat the client-side resultCode as a source of truth for "payment completed" — always confirm on the server via webhooks or a GET /sessions/{id} poll.

Return URL

Pass the value returned by PlexyCheckout.instance.getReturnUrl() into the returnUrl field of your POST /sessions or POST /payments request. On iOS this value matches the URL scheme you registered in Info.plist; on Android the plugin uses an auto-generated scheme.

final returnUrl = await PlexyCheckout.instance.getReturnUrl();

Debugging

Enable plugin console logging in debug builds:

PlexyCheckout.instance.enableConsoleLogging(enabled: true);

The call is a no-op in release builds.

On this page