HyperPay Payment SDK for Flutter
A Flutter plugin that makes integrating the HyperPay payment gateway into your mobile app quick and straightforward. Supports ready-made and custom payment UIs, Google Pay, Samsung Pay, BIN lookup, and structured error codes.
Built on HyperPay Mobile SDK 7.11.0 (Android & iOS). This release is the mandatory update for the Mastercard 3D Secure certificate renewal — merchants must ship it before 2026-07-07 to keep Mastercard 3DS authentication and transactions working. The native SDK binaries are bundled inside the plugin (Android
.aarfiles and iOS.xcframeworks), so you don't need to add any external HyperPay pod or AAR yourself.
Requirements
| Minimum | |
|---|---|
| Android | JDK 17 · compileSdk 35 · minSdkVersion 24 |
| iOS | Xcode 26 · iOS 13.0 deployment target · CocoaPods or Swift Package Manager (Flutter 3.44+) |
Supported Payment Methods
| Method | Android | iOS |
|---|---|---|
| VISA (ReadyUI & CustomUI) | ✅ | ✅ |
| MasterCard (ReadyUI & CustomUI) | ✅ | ✅ |
| MADA (Saudi Arabia) | ✅ | ✅ |
| STC Pay | ✅ | ✅ |
| Apple Pay | — | ✅ |
| Google Pay | ✅ | — |
| Samsung Pay | ✅ | — |
| Stored Cards (Tokenized) | ✅ | ✅ |
Installation
Add this to your pubspec.yaml:
dependencies:
hyperpay_payment_sdk: ^1.3.0
Then run:
flutter pub get
Android Setup
The HyperPay SDK binaries (oppwa.mobile, ipworks3ds_sdk) are bundled inside
the plugin, so you don't need to add the SDK AARs or HyperPay dependencies
yourself. You only need to meet the build requirements and register the redirect
URL scheme.
1. Build configuration
In android/app/build.gradle, make sure your app targets JDK 17 and the required
SDK levels (the plugin requires minSdkVersion 24):
android {
compileSdk 35
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions { jvmTarget = "17" }
defaultConfig {
minSdkVersion 24
}
}
Build with JDK 17 and Android Gradle Plugin 8.x (Gradle 8.x).
2. Add Intent Filter
Add the intent-filter inside your launcher <activity> in AndroidManifest.xml
and set the activity launchMode to singleTop (or singleTask) so the app is
brought back to the foreground after a redirect:
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
... >
<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="com.testpayment.payment" android:host="result" />
</intent-filter>
</activity>
Important: The
schemevalue must exactly matchInAppPaymentSetting.shopperResultUrl.For ReadyUI on SDK 7.x the checkout activity handles the 3DS challenge and the shopper-result redirect internally — the intent-filter is only needed for the CustomUI / STC Pay flows, but keeping it is harmless.
iOS Setup
The HyperPay SDK frameworks (OPPWAMobile.xcframework and
ipworks3ds_sdk.xcframework) are vendored inside the plugin, so no extra pod
is required.
The plugin ships both dependency managers, and the Flutter tool picks one for you — nothing to configure either way:
| Supported | Notes | |
|---|---|---|
| Swift Package Manager | Flutter 3.44+ | Used automatically; both frameworks are embedded and signed by Xcode |
| CocoaPods | any Flutter version | pod install, use_frameworks! (the Flutter default) |
Requirements: Xcode 26 and an iOS 13.0+ deployment target.
If you are upgrading from an older version, remove any previous HyperPay pod
wiring from your ios/Podfile:
# ❌ Remove these — no longer needed in SDK 7.11.0:
# pod 'hyperpay_sdk', :git => 'https://github.com/MohamedHassan1311/hyperpaysdkIOS.git'
# $static_framework = ['hyperpay_payment_sdk']
# pre_install do |installer| ... end
With CocoaPods:
cd ios
pod install
With Swift Package Manager there is no install step. If your app has already
dropped CocoaPods, you can delete ios/Podfile entirely — the plugin resolves
as the Swift package hyperpay_payment_sdk under Flutter/ephemeral/Packages.
Add a URL Scheme in Xcode
- Open your project in Xcode.
- Select your app Target → go to the Info tab.
- Scroll down to URL Types and click the + button.
- Fill in:
- Identifier: your bundle ID (e.g.
com.testpayment.payment) - URL Schemes: the same value as
InAppPaymentSetting.shopperResultUrl
- Identifier: your bundle ID (e.g.
The URL Scheme must exactly match
InAppPaymentSetting.shopperResultUrl.
Configuration
Define a settings class in your app:
class InAppPaymentSetting {
// Must match the scheme in AndroidManifest and Xcode URL Types
static const String shopperResultUrl = "com.testpayment.payment";
static const String merchantId = "YOUR_MERCHANT_ID"; // Apple Pay only
static const String countryCode = "SA";
static String getLang() {
if (Platform.isIOS) {
return "en"; // use "ar" for Arabic
} else {
return "en_US"; // use "ar_AR" for Arabic
}
}
}
Initialize the plugin:
late FlutterHyperPay flutterHyperPay;
flutterHyperPay = FlutterHyperPay(
shopperResultUrl: InAppPaymentSetting.shopperResultUrl,
paymentMode: PaymentMode.test, // switch to PaymentMode.live for production
lang: InAppPaymentSetting.getLang(),
);
Getting a Checkout ID
Before initiating any payment, fetch a checkout ID from your backend:
Future<String?> getCheckoutId() async {
final url = Uri.parse('https://your-backend.com/checkout');
final response = await http.get(url);
if (response.statusCode == 200) {
return json.decode(response.body)['id'];
}
return null;
}
Usage
Ready UI (Pre-built payment screen)
PaymentResultData result = await flutterHyperPay.readyUICards(
readyUI: ReadyUI(
brandsName: ["VISA", "MASTER", "MADA", "STC_PAY", "APPLEPAY"],
checkoutId: checkoutId,
merchantIdApplePayIOS: InAppPaymentSetting.merchantId,
countryCodeApplePayIOS: InAppPaymentSetting.countryCode,
companyNameApplePayIOS: "My Company",
themColorHexIOS: "#000000",
setStorePaymentDetailsMode: true,
supportedNetworksApplePayIOS: ["visa", "masterCard", "mada"],
),
);
Custom UI (Your own card form)
PaymentResultData result = await flutterHyperPay.customUICards(
customUI: CustomUI(
brandName: "VISA",
checkoutId: checkoutId,
cardNumber: "4111111111111111",
holderName: "John Doe",
month: 12,
year: 2025,
cvv: 123,
enabledTokenization: false,
),
);
STC Pay
PaymentResultData result = await flutterHyperPay.customUISTC(
customUISTC: CustomUISTC(
checkoutId: checkoutId,
phoneNumber: "5055555555",
),
);
Stored Cards (Tokenized payments)
PaymentResultData result = await flutterHyperPay.payWithSoredCards(
storedCards: StoredCards(
brandName: "VISA",
checkoutId: checkoutId,
tokenId: tokenId,
cvv: 123,
),
);
Google Pay (Android only)
Prerequisites
Google Pay support (play-services-wallet) is bundled with the plugin — no extra
dependency is required. Just make sure Google Pay is set up on the test device.
Usage
PaymentResultData result = await flutterHyperPay.googlePayUI(
googlePayUI: GooglePayUI(
checkoutId: checkoutId,
googlePayMerchantId: "YOUR_GOOGLE_PAY_MERCHANT_ID",
gatewayMerchantId: "YOUR_HYPERPAY_ENTITY_ID",
countryCode: "SA",
currencyCode: "SAR",
amount: "10.00",
// optional — defaults shown:
allowedCardNetworks: ["VISA", "MASTERCARD", "MADA"],
allowedCardAuthMethods: ["PAN_ONLY", "CRYPTOGRAM_3DS"],
),
);
if (result.paymentResult == PaymentResult.success) {
// Payment confirmed
} else if (result.paymentResult == PaymentResult.error) {
print("Error: ${result.errorCode} — ${result.errorString}");
}
iOS: Calling
googlePayUI()on iOS returnsPaymentResult.errorwitherrorCode = "PLATFORM_NOT_SUPPORTED". No crash.
Samsung Pay (Android only)
PaymentResultData result = await flutterHyperPay.samsungPayUI(
samsungPayUI: SamsungPayUI(
checkoutId: checkoutId,
merchantName: "My Store",
serviceId: "YOUR_SAMSUNG_PAY_SERVICE_ID",
orderNumber: "ORDER_001",
amount: "10.00",
),
);
iOS: Calling
samsungPayUI()on iOS returnsPaymentResult.errorwitherrorCode = "PLATFORM_NOT_SUPPORTED". No crash.
BIN Lookup / Card Brand Detection
Detect the card brand from a partial card number in real time, without starting a payment session.
final brands = await flutterHyperPay.requestBrands(
checkoutId: checkoutId,
);
if (brands.contains("MADA")) {
// Show MADA logo
} else if (brands.contains("VISA")) {
// Show VISA logo
}
Works on both Android and iOS.
Handling Payment Results
void handleResult(PaymentResultData result) {
switch (result.paymentResult) {
case PaymentResult.success:
print("Payment successful!");
break;
case PaymentResult.sync:
print("Payment is being processed...");
break;
case PaymentResult.error:
print("Error [${result.errorCode}]: ${result.errorString}");
break;
case PaymentResult.noResult:
print("Payment cancelled.");
break;
}
}
Error Codes Reference
| Code | Meaning | Flow |
|---|---|---|
"PLATFORM_NOT_SUPPORTED" |
Feature called on wrong platform | Google Pay / Samsung Pay on iOS |
"GOOGLE_PAY_NOT_AVAILABLE" |
Google Pay not set up on device | Google Pay |
"GOOGLE_PAY_CANCELED" |
User dismissed Google Pay sheet | Google Pay |
"GOOGLE_PAY_ERROR" |
Transaction submission failed | Google Pay |
"SAMSUNG_PAY_NOT_AVAILABLE" |
Samsung Pay not set up on device | Samsung Pay |
"SAMSUNG_PAY_ERROR" |
Transaction submission failed | Samsung Pay |
"BIN_LOOKUP_ERROR" |
Brand validation request failed | requestBrands |
"PAYMENT_ERROR" |
Card payment error | CustomUI / StoredCards |
"STC_ERROR" |
STC Pay transaction error | STC Pay |
Apple Pay — Supported Networks
| Network | Value |
|---|---|
| Visa | "visa" |
| MasterCard | "masterCard" |
| Mada | "mada" |
| American Express | "amex" |
| Maestro | "maestro" |
| Discover | "discover" |
| JCB | "jcb" |
| China UnionPay | "chinaUnionPay" |
Default: ["visa", "masterCard", "mada"]
Customizing ReadyUI Colors (Android)
Open android/app/src/main/res/values/colors.xml and override:
<color name="headerBackground">#000000</color>
<color name="cancelButtonTintColor">#FFFFFF</color>
<color name="listMarkTintColor">#000000</color>
<color name="cameraTintColor">#000000</color>
<color name="checkboxButtonTintColor">#000000</color>
Running the Example App
Clone the repository into a directory named hyperpay_payment_sdk:
git clone https://github.com/MohamedHassan1311/HyperpayPluginFlutter.git hyperpay_payment_sdk
cd hyperpay_payment_sdk/example
flutter run
The directory name matters only here: with Swift Package Manager, Flutter
registers the plugin's Swift package under the checkout directory name, while an
example app's Xcode project also references it under the package name. If the two
differ, Xcode fails with unable to override package 'hyperpay_payment_sdk' because its identity '…' doesn't match override's identity. Apps that depend on
the published package are not affected.
License
MIT License — © 2023 Mohamed Elbaz