Features
🎉 Mobile Money 🎉
🎉 VISA / Mastercard / Verve 🎉
🎉 Bank 🎉
🎉 Bank Transfer 🎉
🎉 USSD 🎉
🎉 QR 🎉
🎉 EFT 🎉
Getting Started
Android
Update android/app/build.gradle:
android {
compileSdkVersion 34 // use latest
defaultConfig {
minSdkVersion 19
}
}
iOS
No extra configuration required.
Basic Usage
import 'package:pay_with_paystack/pay_with_paystack.dart';
final ref = PayWithPayStack().generateUuidV4();
await PayWithPayStack().now(
context: context,
secretKey: 'sk_live_XXXXXXXXXXXXXXXXXXXXX',
customerEmail: 'user@example.com',
reference: ref,
currency: 'GHS',
amount: 50.00, // GHS 50.00 — converted to pesewas automatically
callbackUrl: 'https://your-callback.com',
transactionCompleted: (PaymentData data) {
print('✅ Paid ${data.amountInMajorUnit} ${data.currency}');
print(' Reference : ${data.reference}');
print(' Channel : ${data.channel}');
print(' Customer : ${data.customer?.fullName}');
},
transactionNotCompleted: (String reason) {
print('❌ Payment not completed: $reason');
},
);
Payment Channels (type-safe)
Use the PaystackChannel enum instead of raw strings:
channels: [
PaystackChannel.card,
PaystackChannel.mobileMoney,
PaystackChannel.bankTransfer,
],
| Enum value | API string |
|---|---|
PaystackChannel.card |
card |
PaystackChannel.bank |
bank |
PaystackChannel.ussd |
ussd |
PaystackChannel.qr |
qr |
PaystackChannel.mobileMoney |
mobile_money |
PaystackChannel.bankTransfer |
bank_transfer |
PaystackChannel.eft |
eft |
Customer Prefill
Pre-fill the customer's name and phone on the checkout form so they don't have to type it themselves:
PayWithPayStack().now(
// ...
customerFirstName: 'Daniel',
customerLastName: 'Asare',
customerPhone: '+233244000000',
);
These are automatically added as custom_fields in the transaction metadata so
they also appear on your Paystack Dashboard.
Cart Items
Attach a typed list of cart line items to the transaction. These appear in the transaction metadata on your Paystack Dashboard:
PayWithPayStack().now(
// ...
cartItems: [
PaystackCartItem(name: 'Wireless Headphones', amount: 15.00, quantity: 1),
PaystackCartItem(name: 'Phone Case', amount: 2.50, quantity: 2),
PaystackCartItem(name: 'Charging Cable', amount: 5.00),
],
);
Amounts are in the major currency unit (e.g. GHS 15.00). The plugin converts to pesewas / kobo automatically.
Custom Fields (Dashboard-visible)
Add custom fields that appear on the Paystack Dashboard when viewing the transaction:
PayWithPayStack().now(
// ...
customFields: [
PaystackCustomField(
displayName: 'Order ID',
variableName: 'order_id',
value: '#ORD-1234',
),
PaystackCustomField(
displayName: 'Delivery Zone',
variableName: 'delivery_zone',
value: 'Accra Central',
),
],
);
Split Payments
Route a portion of a payment to a subaccount or a pre-defined split group.
Subaccount split
PayWithPayStack().now(
// ...
subaccount: 'ACCT_xxxxxxxxxx', // your subaccount code
bearer: PaystackBearer.account, // main account bears fees (default)
);
Flat fee override
PayWithPayStack().now(
// ...
subaccount: 'ACCT_xxxxxxxxxx',
transactionCharge: 5.00, // GHS 5.00 flat fee goes to main account
bearer: PaystackBearer.subaccount, // subaccount bears Paystack fees
);
Pre-defined split group
PayWithPayStack().now(
// ...
splitCode: 'SPL_xxxxxxxxxx',
);
| Parameter | Type | Description |
|---|---|---|
subaccount |
String? |
Subaccount code (ACCT_xxx) to split payment |
splitCode |
String? |
Pre-defined split group code (SPL_xxx) |
transactionCharge |
double? |
Flat fee (major unit) for main account |
bearer |
PaystackBearer? |
Who bears Paystack fees |
Subscriptions
PayWithPayStack().now(
// ...
plan: 'PLN_xxxxxxxxxx',
invoiceLimit: 12, // charge 12 times then stop
);
Customising the Checkout UI
PayWithPayStack().now(
// ...
showAppBar: true,
appBarTitle: 'Pay Now',
appBarColor: const Color(0xFF0A0A1A),
appBarTextColor: Colors.white,
// Custom loading screen (replaces default pulsing loader)
loadingWidget: const Center(
child: CircularProgressIndicator(color: Colors.green),
),
// Custom error screen with retry
errorWidget: (String error, VoidCallback retry) => Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(error),
ElevatedButton(onPressed: retry, child: const Text('Retry')),
],
),
),
);
Raw Metadata
Attach any extra key-value data to the transaction:
metadata: {
'cart_id': '12345',
'custom_fields': [
{
'display_name': 'Promo Code',
'variable_name': 'promo_code',
'value': 'SAVE10',
},
],
},
Full Parameter Reference
| Parameter | Type | Required | Default |
|---|---|---|---|
context |
BuildContext |
✅ | — |
secretKey |
String |
✅ | — |
customerEmail |
String |
✅ | — |
reference |
String |
✅ | — |
callbackUrl |
String |
✅ | — |
currency |
String |
✅ | — |
amount |
double |
✅ | — |
transactionCompleted |
Function(PaymentData) |
✅ | — |
transactionNotCompleted |
Function(String) |
✅ | — |
channels |
List<PaystackChannel>? |
❌ | all channels |
plan |
String? |
❌ | null |
invoiceLimit |
int? |
❌ | null |
subaccount |
String? |
❌ | null |
splitCode |
String? |
❌ | null |
transactionCharge |
double? |
❌ | null |
bearer |
PaystackBearer? |
❌ | null |
customerFirstName |
String? |
❌ | null |
customerLastName |
String? |
❌ | null |
customerPhone |
String? |
❌ | null |
customFields |
List<PaystackCustomField>? |
❌ | null |
cartItems |
List<PaystackCartItem>? |
❌ | null |
metadata |
Map<String, dynamic>? |
❌ | null |
showAppBar |
bool |
❌ | true |
appBarTitle |
String |
❌ | "Secure Checkout" |
appBarColor |
Color? |
❌ | dark theme default |
appBarTextColor |
Color? |
❌ | Colors.white |
loadingWidget |
Widget? |
❌ | branded loader |
errorWidget |
Widget Function(String, VoidCallback)? |
❌ | branded error UI |
PaymentData Reference
| Field | Type | Description |
|---|---|---|
id |
int? |
Transaction ID |
status |
String? |
"success", "failed", etc. |
reference |
String? |
Transaction reference |
amount |
int? |
Amount in smallest unit |
requestedAmount |
int? |
Originally requested amount |
currency |
String? |
Currency code |
channel |
String? |
Payment channel used |
fees |
int? |
Fees in smallest unit |
paidAt |
String? |
Payment timestamp |
gatewayResponse |
String? |
Gateway message |
customer |
Customer? |
Customer details |
authorization |
Authorization? |
Card/auth details |
isSuccessful |
bool |
status == "success" |
amountInMajorUnit |
double? |
amount / 100 |
feesInMajorUnit |
double? |
fees / 100 |
Screenshots

Additional Information
For bug reports and feature requests, open an issue on GitHub.
📝 Contributors
A big thank you to all contributors:
- @joelarmah
- @pat64j
- @keezysilencer
- @Princewil
- @richprince23
- @VhiktorBrown
Feel free to contribute — the project is open to the public!
📝 Contributing, 😞 Issues, and 🐛 Bug Reports
Submit a detailed report here.
Support My Work 🙏🏽
Buy me a coffee: here. Thank you for your support!