peachpayments_flutter 1.5.3 copy "peachpayments_flutter: ^1.5.3" to clipboard
peachpayments_flutter: ^1.5.3 copied to clipboard

Peach Payments SDK for Flutter — accept card and alternative payments in your Flutter app with a prebuilt, customisable payment sheet.

peachpayments_flutter #

Peach Payments SDK for Flutter — accept card and alternative payments in your Flutter app with a prebuilt, customisable payment sheet.

Wraps Peach Payments' native Android and iOS SDKs behind a single Dart API.


⚠️ Setup is not just flutter pub add #

Peach Payments' native artefacts are not published to Maven Central or the CocoaPods trunk. Each platform needs one extra repository declared, or your first build will fail:

Platform What you need
Android The Peach Maven registry. No credentials required — it allows anonymous reads, and apply_plugins writes it in for you
iOS The Peach CocoaPods spec repo added as a source in your Podfile

Both are covered in Installation below.

Installation #

1. Add the dependency #

dependencies:
  peachpayments_flutter: ^1.0.0

Optional feature packages — add only what you need, each links an extra native dependency:

  peachpayments_flutter_netcetera_3ds: ^1.0.0  # Netcetera 3-D Secure
  peachpayments_flutter_scancard: ^1.0.0       # card scanning

Then flutter pub get.

2. Android #

Run the helper once. It writes the Gradle plugin and the required Maven repositories into your app's Gradle files:

dart run peachpayments_flutter:apply_plugins

This is a manual step — pub has no post-get hook, so it cannot run automatically. It is safe to re-run: the script is idempotent and will also upgrade an older Gradle plugin version in place.

That is all that is needed. The registry (https://gitlab.com/api/v4/projects/81506485/packages/maven) allows anonymous reads, so no token or credentials are required.

Two optional overrides exist for unusual setups:

Property When you need it
PEACH_MAVEN_URL Point at a different project's registry
PEACH_MAVEN_TOKEN Only if that registry requires authentication

If you do use a token, keep it out of version control — put it in ~/.gradle/gradle.properties or inject it from CI secrets, not the app's android/gradle.properties.

If your app routes dependency resolution through settings.gradle (dependencyResolutionManagement with FAIL_ON_PROJECT_REPOS or PREFER_SETTINGS), Gradle ignores the repositories in android/build.gradle — apply_plugins will warn and print the block to add there instead.

The SDK requires minSdk = 24; apply_plugins sets this for you.

3. iOS #

Add the Peach spec repo to the top of ios/Podfile. A podspec cannot declare its own sources, so every consuming app needs these two lines:

source 'https://github.com/peach-payments/hyperswitch-sdk-ios.git'
source 'https://cdn.cocoapods.org/'

platform :ios, '15.1'

Then cd ios && pod install. Minimum deployment target is iOS 15.1.

Usage #

import 'package:peachpayments_flutter/peachpayments_flutter.dart';

final _peach = PeachPayments();

// 1. Configure the SDK with your publishable key.
_peach.init(PeachPaymentsConfig(publishableKey: publishableKey));

// 2. Open a session against a client secret from your backend.
final session = await _peach.initPaymentSession(
  PaymentMethodParams(
    clientSecret: clientSecret,
    configuration: Configuration(
      merchantDisplayName: 'My Store',
      primaryButtonLabel: 'Pay',
    ),
  ),
);

// 3. Present the payment sheet.
final result = await _peach.presentPaymentSheet(session);

switch (result.status) {
  case Status.completed:
    // payment succeeded
    break;
  case Status.cancelled:
    // customer dismissed the sheet
    break;
  case Status.failed:
    debugPrint(result.error.message);
    break;
}

Errors are surfaced as PeachPaymentsException:

try {
  final session = await _peach.initPaymentSession(params);
} on PeachPaymentsException catch (e) {
  debugPrint('${e.code}: ${e.message}');
}

Saved payment methods (headless) #

To charge a returning customer without showing the sheet:

final saved = await _peach.getCustomerSavedPaymentMethods(session);

// Inspect the default or last-used method before charging.
final method = await _peach.getCustomerLastUsedPaymentMethodData(saved);
if (method is PaymentMethod) {
  final result = await _peach.confirmWithLastUsedPaymentMethod(saved);
}

iOS limitation on confirmWithLastUsedPaymentMethod. If the saved card requires a CVC (requiresCvv), iOS cannot confirm it headlessly — the SDK needs a CVCWidget the customer types into. The call fails with a clear message; use presentPaymentSheet for those cards. Android accepts a null CVC and has no such restriction.

Available calls:

Method Returns
init(PeachPaymentsConfig) —
initPaymentSession(PaymentMethodParams) Session
presentPaymentSheet(Session) PaymentResult
getCustomerSavedPaymentMethods(Session) SavedSession
getCustomerDefaultSavedPaymentMethodData(SavedSession) PaymentMethodResponse
confirmWithCustomerDefaultPaymentMethod(SavedSession) PaymentResult
getCustomerLastUsedPaymentMethodData(SavedSession) PaymentMethodResponse
confirmWithLastUsedPaymentMethod(SavedSession) PaymentResult

Customising the sheet #

Configuration.appearance accepts an Appearance object covering layout, colours, fonts, and the Google Pay / Apple Pay button styles:

Configuration(
  appearance: Appearance(
    layout: Layout.spacedAccordion,
    font: Font(family: 'Montserrat'),
    colors: DynamicColors(
      light: ColorsObject(primary: '#8DBD00', background: '#F5F8F9'),
      dark: ColorsObject(primary: '#8DBD00', background: '#F5F8F9'),
    ),
    primaryButton: PrimaryButton(shapes: Shapes(borderRadius: 32.0)),
  ),
)

Custom fonts must also be declared in your app's pubspec.yaml fonts: section — the native side loads them by family name from your Flutter assets.

Saved payment methods #

Two independent switches control what a returning shopper is offered:

Configuration(
  displaySavedPaymentMethods: false,   // hide saved methods entirely
  displayAddNewPaymentMethod: false,   // keep the shopper on their saved methods
)

displayAddNewPaymentMethod: false removes the "Add new payment method" link from the saved-methods screen. It cannot strand a shopper: when there is nothing saved to stay on, the sheet shows the new-payment form regardless of this setting.

Both default to true.

Billing details #

The payment sheet decides which billing fields to show from your connector configuration, not from anything this package sends. The SDK combines the required_fields returned by /account/payment_methods with a remote field definition, and renders a field when it is marked required and your backend did not already supply a non-empty value for it.

Two consequences worth knowing:

  • Configuration.defaultBillingDetails neither prefills nor hides anything. The native SDK parses it and then never reads it. It is kept for API compatibility; the gap is tracked in references/bug-report-default-billing-details-inert.md.
  • Visibility is all-or-nothing per group. If any one sub-field of the billing address is missing a value, the whole address block is shown. The same applies to the first-name/last-name pair and to the phone pair.

So if billing fields appear when you expect them not to, the fix is to return a non-empty value for every field in that group from your /account/payment_methods response. No client-side option overrides this.

3-D Secure #

3DS is handled entirely by the native SDK; this package does not see the next_action on a confirm response. There are two distinct flows, and which one you get is decided by your connector and the issuer:

next_action.type Flow What it needs
three_ds_invoke Native app-based challenge (Netcetera) the peachpayments_flutter_netcetera_3ds dependency and Configuration.netceteraSDKApiKey
redirect_to_url Browser redirect in an authentication session nothing extra
redirect_inside_popup Browser redirect in an authentication session nothing extra
anything else Browser redirect in an authentication session nothing extra

These do not fall back to one another. If your connector returns three_ds_invoke and the Netcetera dependency is absent, the payment fails with an integration error — the browser redirect is never attempted.

If you support app-based 3DS, add both:

dependencies:
  peachpayments_flutter_netcetera_3ds: ^1.1.2
Configuration(netceteraSDKApiKey: '<your Netcetera API key>')

Before 1.3.0 this could not work on iOS at all. The whole configuration object was being dropped there, so netceteraSDKApiKey never reached the sheet. If you are on an earlier version and your connector returns three_ds_invoke, upgrading is the fix.

Before 1.3.0 the redirect_inside_popup shape never opened a browser. The native SDK read the redirect URL out of next_action.redirect_to_url unconditionally, but that shape carries it in popup_url instead, so the URL came back empty and the authentication session was never presented — no browser, no error. Whether you hit this was decided entirely by which shape your connector returns, which is why it looked like a device-versus-simulator problem. Fixed in peachpayments-hyperswitch-ios 0.7.3 / io.peachpayments:hyperswitch-sdk-android 1.5.4, which this version pins. See references/bug-report-3ds-redirect-silent-failure.md.

Platform differences #

Android iOS
PaymentMethodParams.ephemeralKey ✅ ❌ — see below
PaymentMethodParams.customParams ✅ ❌

iOS SDK 0.7.x builds the payment sheet's top-level props itself and gives a wrapper SDK control only over the configuration object, so there is no way for this package to supply ephemeralKey or customParams on iOS. Customer-scoped saved-payment-method flows that depend on an ephemeral key are Android-only until that is fixed upstream; it is written up in references/bug-report-ios-params-contract.md.

Configuration.customer.ephemeralKeySecret is not an alternative — the native SDK's decoder for that object is commented out on both platforms.

Diagnostics #

Keep telemetry switched on #

The SDK resolves its logging endpoint from the pair (customBackendUrl, customLogUrl). Setting a custom backend without a custom log URL resolves to "no endpoint", and every log event is silently discarded — including the events that would explain a failed payment. This is the usual configuration for a white-labelled integration, so it is easy to end up with an SDK that reports nothing at all.

_peach.init(PeachPaymentsConfig(
  publishableKey: publishableKey,
  customBackendUrl: 'https://<your-backend>/api',
  customLogUrl: 'https://<your-backend>/api/logs/sdk', // <- required, or no logs
));

The package logs a warning if it sees the first without the second.

debugLogging #

Configuration(debugLogging: true) makes both platform plugins print the parameter set they hand to the native sheet — which top-level and configuration keys actually crossed the platform channel, and whether appearance, displaySavedPaymentMethods and netceteraSDKApiKey arrived.

It is opt-in and intended for integration problems you cannot attach a debugger to. Because neither this plugin nor the native SDK decodes the configuration field by field, "did the key reach the SDK at all" is usually the first useful question. Leave it off in production.

Which JavaScript bundle is running (iOS) #

The iOS SDK is React Native underneath, so it is worth knowing where its JavaScript comes from when triaging "works on the simulator, not on the device".

Leave HyperswitchSource unset. With it unset and without the airborne package, the SDK loads the bundle compiled into its own framework — the same bytes for every install of a given pod version, so it cannot be the source of a device-versus-simulator difference. Over-the-air updates are compiled in only when HyperOTA is linked, which happens solely via the airborne subspec.

Do not set the key to LocalBundle in a host app: that branch resolves the bundle from Bundle.main, while the pod delivers it inside the framework bundle, so the lookup returns nil and the sheet fails to load. LocalHosted points at a Metro dev server. Both exist for SDK development, not integration.

debugLogging reports the key's value so you can confirm it is unset.

Payment method logos #

The package bundles SVG logos for the payment methods Peach supports, so you can build your own method pickers or summaries without shipping the artwork yourself:

PeachPaymentMethodLogo(PeachPaymentMethod.capitecPay, height: 24)

// Or straight from an API key such as `pay_shap`; unknown keys render `fallback`.
PeachPaymentMethodLogo.fromKey('pay_shap', height: 24, fallback: Icon(Icons.payment))

// Apple Pay has a white variant for dark backgrounds.
PeachPaymentMethodLogo(PeachPaymentMethod.applePay, height: 24, onDark: true)

PeachPaymentMethod.logoAssetPath() returns the raw asset path if you want to load it with SvgPicture.asset(path, package: 'peachpayments_flutter') yourself. Logos are available for: capitec_pay, pay_shap, peach_eft, payflex, zero_pay, float, happy_pay, mobicred, a_plus, rcs, payjustnow, apple_pay, scan_to_pay, one_for_you, google_pay, money_badger, blink_by_emtel, maucas, mcb_juice, mpesa.

Example #

See apps/example for a complete app, including a sample backend for creating payment intents.

Migrating from flutter_hyperswitch #

This package replaces the upstream flutter_hyperswitch package. The public API is the same shape; the names changed:

Before After
package:flutter_hyperswitch/flutter_hyperswitch.dart package:peachpayments_flutter/peachpayments_flutter.dart
FlutterHyperswitch PeachPayments
HyperConfig PeachPaymentsConfig
HyperParams PeachPaymentsParams
HyperswitchException PeachPaymentsException
FlutterHyperswitchPlatform PeachPaymentsPlatform
MethodChannelFlutterHyperswitch MethodChannelPeachPayments

Method names and payment-domain types (Session, PaymentResult, Configuration, Appearance, …) are unchanged. The native dependencies now resolve to Peach Payments' io.peachpayments Android artefacts and peachpayments-hyperswitch-ios pods, which is why the extra repository setup above is required.

Licence #

Apache-2.0 — see LICENSE and NOTICE. Derived from Juspay's Hyperswitch client SDK.

0
likes
140
points
629
downloads

Documentation

API reference

Publisher

verified publisherpeachpayments.com

Weekly Downloads

Peach Payments SDK for Flutter — accept card and alternative payments in your Flutter app with a prebuilt, customisable payment sheet.

Homepage
Repository (GitLab)
View/report issues

License

Apache-2.0 (license)

Dependencies

flutter, flutter_svg, http, plugin_platform_interface

More

Packages that depend on peachpayments_flutter

Packages that implement peachpayments_flutter