flutter_paystack_plus
모바일 및 웹에 Paystack을 통합하여 분할 결제 및 구독 기능을 지원합니다.
Paystack를 사용한 결제 구현을 위한 패키지 - Android, iOS 및 웹에서 호환
{"sdk":"flutter"}^1.2.2^4.10.0{"sdk":"flutter"}^2.0.0아래는 영문 원문 스냅샷입니다. 최신 내용은 GitHub에서 확인하세요.
A Flutter plugin for making payments via the Paystack Payment Gateway — compatible with Android, iOS, and Web.
| Feature | Mobile (Android/iOS) | Web |
|---|---|---|
| Card Payment (VISA, Mastercard, etc.) | ✅ | ✅ |
| Bank Transfer | ✅ | ✅ |
| USSD | ✅ | ✅ |
| Mobile Money | ✅ | ✅ |
| QR Code | ✅ | ✅ |
| Split Payments | ✅ | ✅ |
| Subscription / Plan Payments | ✅ | ✅ |
| Server-side initialization & verification | ✅ | — |
Before using this package, make sure you have a Paystack account and have your public key (and optionally your secret key) ready from the dashboard.
Step 1: Create a file at web/paystack_interop.js and paste the following:
function paystackPopUp(publicKey, email, amount, ref, plan, currency, onClosed, callback) {
let handler = PaystackPop.setup({
key: publicKey,
email: email,
amount: amount,
ref: ref,
plan: plan,
currency: currency,
onClose: function () {
onClosed();
},
callback: function (response) {
callback();
},
});
return handler.openIframe();
}
Step 2: In web/index.html, add the Paystack inline script and your interop file inside the <body> tag:
<body>
<script src="https://js.paystack.co/v1/inline.js"></script>
<script src="paystack_interop.js"></script>
...
</body>
Set minSdkVersion to 19 or higher in android/app/build.gradle:
defaultConfig {
applicationId "com.yourapp.id"
minSdkVersion 19
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
No additional setup required.
| Parameter | Required On | Description |
|---|---|---|
customerEmail |
All | Email address of the customer |
amount |
All | Amount multiplied by 100 (e.g. ₦500 → "50000") |
reference |
All | Unique alphanumeric transaction reference |
onSuccess |
All | Callback fired when a transaction completes |
onClosed |
All | Callback fired when the user cancels or payment fails |
publicKey |
Web only | Your Paystack public key |
context |
Mobile only | Flutter BuildContext — required to open the WebView |
callBackUrl |
Mobile only | Redirect URL configured in your Paystack dashboard — helps the WebView detect when to close |
secretKey |
Mobile (Package init) | Your Paystack secret key. Required when you want the package to initialize and verify the transaction. |
authorizationUrl |
Mobile (Server init) | Pre-generated Paystack checkout URL from your own server. Use this instead of secretKey to keep your secret key out of the app. |
currency |
Optional | Payment currency. Defaults to NGN (Naira). See Supported Currencies |
plan |
Optional | Plan code for subscription payments |
metadata |
Optional | Extra key-value data attached to the transaction |
Note: For mobile, you must provide either
secretKeyorauthorizationUrl— but not both.
Paystack supports standard ISO 4217 currency codes. Pass the desired code to the currency parameter (e.g. 'NGN', 'USD'):
| Currency Code | Currency Name | Primary Region / Availability |
|---|---|---|
NGN |
Nigerian Naira | Nigeria (default) |
USD |
United States Dollar | Nigeria & Kenya (for eligible accounts) |
GHS |
Ghanaian Cedi | Ghana |
ZAR |
South African Rand | South Africa |
KES |
Kenyan Shilling | Kenya |
XOF |
West African CFA Franc | Côte d'Ivoire |
EGP |
Egyptian Pound | Egypt |
Note: Available currencies depend on where your Paystack merchant account is registered. Remember that transaction amounts must always be passed in the subunit of the chosen currency (e.g. multiplied by 100 for Kobo/Cents).
The simplest mode. Pass your secretKey and the package will:
/transaction/initialize to get the checkout URL/transaction/verify/{reference} to confirm the resultonSuccess or onClosed accordinglyawait FlutterPaystackPlus.openPaystackPopup(
context: context,
customerEmail: 'customer@example.com',
amount: (amount * 100).toString(), // e.g. 500 * 100 = 50000
reference: DateTime.now().millisecondsSinceEpoch.toString(),
secretKey: 'sk_live_your_secret_key',
callBackUrl: 'https://your-callback-url.com', // from your Paystack dashboard
currency: 'NGN',
onSuccess: () {
debugPrint('Payment successful!');
},
onClosed: () {
debugPrint('Payment cancelled or failed.');
},
);
The more secure approach. Your backend holds the secret key — the app never sees it. You:
authorization_urlauthorizationUrlonSuccess when the flow endsonSuccess, call your server to verify the transaction using the reference// Step 1: Initialize on your server
final authUrl = await myServer.initializePayment(
email: 'customer@example.com',
amount: 50000,
reference: 'unique-ref-123',
);
// Step 2: Open the Paystack WebView
await FlutterPaystackPlus.openPaystackPopup(
context: context,
customerEmail: 'customer@example.com',
amount: '50000',
reference: 'unique-ref-123',
authorizationUrl: authUrl, // from your server
callBackUrl: 'https://your-callback-url.com',
onSuccess: () {
// Step 3: Verify on your server
myServer.verifyPayment('unique-ref-123');
},
onClosed: () {
debugPrint('Payment cancelled.');
},
);
To enable split payments, update your paystack_interop.js handler:
Single subaccount:
let handler = PaystackPop.setup({
// ...existing fields...
subaccount: 'ACCT_osl1da48je0lez6', // required
transaction_charge: '2500', // optional: flat fee override
bearer: 'subaccount', // optional: who bears transaction charges
});
Multiple subaccounts (split code):
let handler = PaystackPop.setup({
// ...existing fields...
split_code: 'SPL_98WF13Eb3w', // required
});
To collect subscription payments, add a plan to your paystack_interop.js handler:
let handler = PaystackPop.setup({
// ...existing fields...
plan: 'PLN_your_plan_code', // required: plan code from your dashboard
quantity: '1', // optional: quantity multiplier for the plan amount
});
For mobile, simply pass the plan parameter directly to openPaystackPopup.
This package stands on the shoulders of great contributors:
Contributions are very welcome! If you experience a bug or want to request a feature, please open an issue and be as descriptive as possible. Thank you! 🙏