|
1 |
| -# flutter_paystack |
| 1 | +# Paystack Plugin for Flutter |
2 | 2 |
|
3 |
| -A Flutter plugin for Paystack Payment Gateway. |
| 3 | +[](https://pub.dartlang.org/packages/flutter_paystack) |
4 | 4 |
|
5 |
| -## Getting Started |
| 5 | +A Flutter plugin for making payments via Paystack Payment Gateway. Completely supports Android and iOS. |
6 | 6 |
|
7 |
| -For help getting started with Flutter, view our online |
8 |
| -[documentation](https://flutter.io/). |
| 7 | +## Installation |
| 8 | +To use this plugin, add `flutter_paystack` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). |
| 9 | + |
| 10 | +Then initialize the plugin preferably in the `initState` of your widget. |
| 11 | + |
| 12 | +``` dart |
| 13 | +import 'package:flutter_paystack/paystack_plugin.dart' |
| 14 | +
|
| 15 | +class PaymentPage extends StatefulWidget { |
| 16 | + @override |
| 17 | + State<StatefulWidget> createState() => new _PaymentPageState(); |
| 18 | +} |
| 19 | +
|
| 20 | +class _PaymentPageState extends State<PaymentPage> { |
| 21 | + var paystackPublicKey = '[YOUR_PAYSTACK_PUBLIC_KEY]'; |
| 22 | +
|
| 23 | + @override |
| 24 | + void initState() { |
| 25 | + PaystackPlugin.initialize(publicKey: paystackPublicKey); |
| 26 | + super.initState(); |
| 27 | + } |
| 28 | +
|
| 29 | + @override |
| 30 | + Widget build(BuildContext context) { |
| 31 | + // Return your widgets |
| 32 | + } |
| 33 | +} |
| 34 | +``` |
| 35 | + |
| 36 | +No other configuration required - the plugin should work out of the box. |
| 37 | + |
| 38 | +## Making Payments |
| 39 | + |
| 40 | +You can choose to initialize the payment locally or via Paystack's backend. |
| 41 | + |
| 42 | +### 1. Initialize Via Paystack (Recommended) |
| 43 | +1.a. This starts by making a HTTP POST request to `https://api.paystack.co/transaction/initialize` |
| 44 | +with the amount(in kobo), reference, etc in the request body and your paystack secret key in request header. |
| 45 | +The request looks like this: |
| 46 | + |
| 47 | +``` dart |
| 48 | +// Required imports |
| 49 | +import 'dart:async'; |
| 50 | +import 'dart:convert'; |
| 51 | +import 'package:http/http.dart' as http; |
| 52 | +
|
| 53 | + initTransaction() async { |
| 54 | + var url = 'https://api.paystack.co/transaction/initialize'; |
| 55 | +
|
| 56 | + Map<String, String> headers = { |
| 57 | + 'Authorization': 'Bearer $[YOUR_PAYSTACK_SECRET_KEY]', |
| 58 | + 'Content-Type': 'application/json' |
| 59 | + }; |
| 60 | +
|
| 61 | + Map<String, String> body = { |
| 62 | + 'reference': '[YOUR_GENERATED_REFERENCE]', |
| 63 | + 'amount': 500000.toString(), |
| 64 | + 'email': 'user@email.com' |
| 65 | + }; |
| 66 | +
|
| 67 | + http.Response response = |
| 68 | + await http.post(url, body: body, headers: headers); |
| 69 | + // Charge card |
| 70 | + _chargeCard(response.body); |
| 71 | + } |
| 72 | +``` |
| 73 | +Please check the [official documentation](https://developers.paystack.co/reference#initialize-a-transaction) for the full details of payment initialization. |
| 74 | + |
| 75 | +1.b If everything goes well, the initialization request returns a response with an `access_code`. |
| 76 | +You can then create a `Charge` object with the access code and card details. The `charge` is in turn passed to the ` PaystackPlugin.chargeCard()` function for payment: |
| 77 | + |
| 78 | +```dart |
| 79 | + PaymentCard _getCardFromUI() { |
| 80 | + // Using just the must-required parameters. |
| 81 | + return PaymentCard( |
| 82 | + number: cardNumber, |
| 83 | + cvc: cvv, |
| 84 | + expiryMonth: expiryMonth, |
| 85 | + expiryYear: expiryYear, |
| 86 | + ); |
| 87 | +
|
| 88 | + // Using Cascade notation (similar to Java's builder pattern) |
| 89 | +// return PaymentCard( |
| 90 | +// number: cardNumber, |
| 91 | +// cvc: cvv, |
| 92 | +// expiryMonth: expiryMonth, |
| 93 | +// expiryYear: expiryYear) |
| 94 | +// ..name = 'Segun Chukwuma Adamu' |
| 95 | +// ..country = 'Nigeria' |
| 96 | +// ..addressLine1 = 'Ikeja, Lagos' |
| 97 | +// ..addressPostalCode = '100001'; |
| 98 | +
|
| 99 | + // Using optional parameters |
| 100 | +// return PaymentCard( |
| 101 | +// number: cardNumber, |
| 102 | +// cvc: cvv, |
| 103 | +// expiryMonth: expiryMonth, |
| 104 | +// expiryYear: expiryYear, |
| 105 | +// name: 'Ismail Adebola Emeka', |
| 106 | +// addressCountry: 'Nigeria', |
| 107 | +// addressLine1: '90, Nnebisi Road, Asaba, Deleta State'); |
| 108 | + } |
| 109 | +
|
| 110 | + _chargeCard(http.Response response) { |
| 111 | + Map<String, dynamic> responseBody = json.decode(response.body); |
| 112 | + var charge = Charge() |
| 113 | + ..accessCode = responseBody['access_code'] |
| 114 | + ..card = _getCardFromUI(); |
| 115 | +
|
| 116 | + PaystackPlugin.chargeCard(context, |
| 117 | + charge: charge, |
| 118 | + beforeValidate: (transaction) => handleBeforeValidate(transaction), |
| 119 | + onSuccess: (transaction) => handleOnSuccess(transaction), |
| 120 | + onError: (error, transaction) => handleOnError(error, transaction)); |
| 121 | + } |
| 122 | +
|
| 123 | + handleBeforeValidate(Transaction transaction) { |
| 124 | + // This is called only before requesting OTP |
| 125 | + // Save reference so you may send to server if error occurs with OTP |
| 126 | + } |
| 127 | +
|
| 128 | + handleOnError(Object e, Transaction transaction) { |
| 129 | + // If an access code has expired, simply ask your server for a new one |
| 130 | + // and restart the charge instead of displaying error |
| 131 | + } |
| 132 | +
|
| 133 | +
|
| 134 | + handleOnSuccess(Transaction transaction) { |
| 135 | + // This is called only after transaction is successful |
| 136 | + } |
| 137 | +``` |
| 138 | + |
| 139 | + |
| 140 | + |
| 141 | +### 2. Initialize Locally |
| 142 | +Just send the payment details to `PaystackPlugin.chargeCard` |
| 143 | +```dart |
| 144 | + // Set transaction params directly in app (note that these params |
| 145 | + // are only used if an access_code is not set. In debug mode, |
| 146 | + // setting them after setting an access code would throw an error |
| 147 | + Charge charge = Charge(); |
| 148 | + charge.card = _getCardFromUI(); |
| 149 | + charge |
| 150 | + ..amount = 2000 |
| 151 | + ..email = 'user@email.com' |
| 152 | + ..reference = _getReference() |
| 153 | + ..putCustomField('Charged From', 'Flutter PLUGIN'); |
| 154 | + _chargeCard(); |
| 155 | +``` |
| 156 | + |
| 157 | + |
| 158 | +## Validating Card Details |
| 159 | +You are expected to build the UI for your users to enter their payment details. |
| 160 | +For easier validation, wrap the **TextFormField**s inside a **Form** widget. Please check this article on |
| 161 | +[validating forms on Flutter](https://medium.freecodecamp.org/how-to-validate-forms-and-user-input-the-easy-way-using-flutter-e301a1531165) |
| 162 | +if this is new to you. |
| 163 | + |
| 164 | +You can validate the fields with these methods: |
| 165 | +#### card.validNumber |
| 166 | +This method helps to perform a check if the card number is valid. |
| 167 | + |
| 168 | +#### card.validCVC |
| 169 | +Method that checks if the card security code is valid. |
| 170 | + |
| 171 | +#### card.validExpiryDate |
| 172 | +Method checks if the expiry date (combination of year and month) is valid. |
| 173 | + |
| 174 | +#### card.isValid |
| 175 | +Method to check if the card is valid. Always do this check, before charging the card. |
| 176 | + |
| 177 | + |
| 178 | +#### card.getType |
| 179 | +This method returns an estimate of the string representation of the card type(issuer). |
| 180 | + |
| 181 | + |
| 182 | +## chargeCard |
| 183 | +Charging with the **PaystackPlugin** is quite straightforward. It requires the following arguments. |
| 184 | +1. `context`: your UI **BuildContext**. It's used by the plugin for showing dialogs for the user to take a required action, e.g inputting OTP. |
| 185 | +2. `charge`: You provide the payment details (`PaymentCard`, `amount` `email` etc) to an instance of the `Charge` object. |
| 186 | +3. `beforeValidate`: Pre-validation callback. |
| 187 | +4. `onSuccess`: callbacks for a successful payment. |
| 188 | +4. `onError`: callback for when an error occurs in the transaction. Provides you with a reference to the error object. |
| 189 | + |
| 190 | + |
| 191 | +## Verifying Transactions |
| 192 | +This is quite easy. Just send a HTTP GET request to `https://api.paystack.co/transaction/verify/$[TRANSACTION_REFERENCE]`. |
| 193 | +Please, check the [official documentaion](https://developers.paystack.co/reference#verifying-transactions) on verifying transactions. |
| 194 | + |
| 195 | +## Testing your implementation |
| 196 | +Paystack provides tons of [payment cards](https://developers.paystack.co/docs/test-cards) for testing. |
| 197 | + |
| 198 | +## Running Example project |
| 199 | +For help getting started with Flutter, view the online [documentation](https://flutter.io/). |
| 200 | + |
| 201 | +An [example project](https://github.com/wilburt/flutter_paystack/tree/master/example) has been provided in this plugin. |
| 202 | +Clone this repo and navigate to the **example** folder. Open it with a supported IDE or execute `flutter run` from that folder in terminal. |
| 203 | + |
| 204 | +## Contributing, Issues and Bug Reports |
| 205 | +The project is open to public contribution. Please feel very free to contribute. |
| 206 | +Experienced an issue or want to report a bug? Please, [report it here](https://github.com/wilburt/flutter_paystack/issues). Remember to be descriptive. |
| 207 | + |
| 208 | +## Credits |
| 209 | +Thanks to the authors of Paystack [iOS](https://github.com/PaystackHQ/paystack-ios) and [Android](https://github.com/PaystackHQ/paystack-android) SDKS. I leveraged on their work to bring this plugin to fruition. |
9 | 210 |
|
10 |
| -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). |
|
0 commit comments