├── lib ├── mpesadaraja.dart └── src │ ├── endpoints.dart │ └── lipa_na_mpesa.dart ├── CHANGELOG.md ├── analysis_options.yaml ├── .metadata ├── pubspec.yaml ├── example └── example.dart ├── test └── mpesadaraja_test.dart ├── .gitignore ├── LICENSE └── README.md /lib/mpesadaraja.dart: -------------------------------------------------------------------------------- 1 | library mpesadaraja; 2 | 3 | export 'src/lipa_na_mpesa.dart'; 4 | 5 | /// 6 | /// 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | ## 0.1.1 3 | ## 0.1.2 4 | ## 0.1.3 5 | ## 0.1.4 6 | ## 0.1.5 7 | 8 | * STK-PUSH for mpesa daraja api 9 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /lib/src/endpoints.dart: -------------------------------------------------------------------------------- 1 | class Endpoint { 2 | static const String authorization = 3 | "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials"; 4 | static const String mpesaExpresSandbox = 5 | "https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest"; 6 | } 7 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: mpesadaraja 2 | description: M-pesa daraja api library for flutter and dart. M-Pesa is a mobile phone-based money transfer. 3 | version: 0.1.5 4 | homepage: https://github.com/flavian-anselmo/mpesa-daraja-plugin-flutter-dart 5 | 6 | environment: 7 | sdk: ">=2.17.0 <3.0.0" 8 | flutter: ">=1.17.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | http: ^0.13.4 14 | 15 | 16 | dev_dependencies: 17 | flutter_test: 18 | sdk: flutter 19 | flutter_lints: ^2.0.0 20 | 21 | 22 | flutter: 23 | -------------------------------------------------------------------------------- /example/example.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:mpesadaraja/src/lipa_na_mpesa.dart'; 3 | 4 | Future main() async { 5 | final stk = MpesaDaraja( 6 | consumerKey: 'Dm4oJgziMyOT7WTmJzQfEZS6jjzg1Frd', 7 | consumerSecret: 'RGRvsUGkO4jc3NuW', 8 | passKey: 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919', 9 | ); 10 | 11 | await stk.lipaNaMpesaStk( 12 | "174379", 13 | 1, 14 | "254798071520", 15 | "174379", 16 | "254798071520", 17 | "https://mydomain.com/path", 18 | "accountReference", 19 | "transactionDesc", 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /test/mpesadaraja_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | import 'package:mpesadaraja/mpesadaraja.dart'; 4 | 5 | Future main() async { 6 | final stk = MpesaDaraja( 7 | consumerKey: 'Dm4oJgziMyOT7WTmJzQfEZS6jjzg1Frd', 8 | consumerSecret: 'RGRvsUGkO4jc3NuW', 9 | passKey: 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919', 10 | ); 11 | 12 | await stk.lipaNaMpesaStk( 13 | "174379", 14 | 1, 15 | "254798071510", 16 | "174379", 17 | "254798071510", 18 | "https://mydomain.com/path", 19 | "accountReference", 20 | "transactionDesc", 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 flavian-anselmo 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /lib/src/lipa_na_mpesa.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:http/http.dart' as http; 3 | import 'package:mpesadaraja/src/endpoints.dart'; 4 | 5 | class MpesaDaraja { 6 | late String consumerKey; 7 | late String consumerSecret; 8 | late String passKey; 9 | 10 | /// the keys are required fields 11 | MpesaDaraja({ 12 | required this.consumerKey, 13 | required this.consumerSecret, 14 | required this.passKey, 15 | }); 16 | 17 | late String _accessToken; 18 | //late String _expiresIN; 19 | 20 | String _generateAuth() { 21 | /// authorization 22 | /// --- Basic Auth Over https this is a base64 encoded string 23 | /// of apps consumerKey and consumer secret 24 | /// 25 | /// grant_type 26 | /// client_credentials grant_type is supported (under query parameters) 27 | //String consumerKey = "Dm4oJgziMyOT7WTmJzQfEZS6jjzg1Frd"; 28 | //String consumerSecret = "RGRvsUGkO4jc3NuW"; 29 | 30 | /// 31 | /// MTc0Mzc5K2JmYjI3OWY5YWE5YmRiY2YxNThlOTdkZDcxYTQ2N2NkMmUwYzg5MzA1OWIxMGY3OGU2YjcyYWRhMWVkMmM5MTkrMjAyMjA2MjAyMzUzMjY= 32 | /// MTc0Mzc5YmZiMjc5ZjlhYTliZGJjZjE1OGU5N2RkNzFhNDY3Y2QyZTBjODkzMDU5YjEwZjc4ZTZiNzJhZGExZWQyYzkxOTIwMjIwNjIxMDAwOTQ1 33 | 34 | String b64secret = base64Url.encode( 35 | ("$consumerKey:$consumerSecret").codeUnits, 36 | ); 37 | 38 | return b64secret; 39 | } 40 | 41 | Future _validateTimeBoundedAceessToken() async { 42 | /*** 43 | * the access key will be used to make requests when making a stk push 44 | * 45 | */ 46 | String b64secret = _generateAuth(); 47 | var response = await http.get( 48 | Uri.parse(Endpoint.authorization), 49 | headers: {"Authorization": "Basic $b64secret"}, 50 | ); 51 | 52 | if (response.statusCode == 200) { 53 | var jsonresponse = jsonDecode(response.body); 54 | //pick the access key to be used in other requets 55 | _accessToken = jsonresponse["access_token"]; 56 | // _expiresIN = jsonresponse["expires_in"]; 57 | return await jsonresponse; 58 | } else { 59 | return throw Exception("Error"); 60 | } 61 | } 62 | 63 | String _getTimeStamp() { 64 | /** 65 | * timestamp is the ime the transaction is taking place 66 | * The time stamp is usually in a particular order yyyymmddhhmmss 67 | * 68 | */ 69 | DateTime now = DateTime.now(); 70 | final tmstmp = 71 | "${now.year}${now.month.toString().padLeft(2, '0')}${now.day.toString().padLeft(2, '0')}${now.hour.toString().padLeft(2, '0')}${now.minute.toString().padLeft(2, '0')}${now.second.toString().padLeft(2, '0')}"; 72 | return tmstmp; 73 | } 74 | 75 | String _generatePassword(String shortcode) { 76 | /// base64.encode(Shortcode+Passkey+Timestamp) 77 | /*** 78 | * the password is combination btwn the business short code, passkey and timestamp 79 | * 80 | */ 81 | String shortCode = shortcode; // busimess short code 82 | String timeStamp = _getTimeStamp(); 83 | //before encoding 84 | String raw = shortCode + passKey + timeStamp; 85 | final bytespswd = utf8.encode(raw); 86 | //base64 encoded password 87 | return base64Encode(bytespswd); 88 | } 89 | 90 | Future lipaNaMpesaStk( 91 | String businessShortCode, 92 | int amount, 93 | String partyA, 94 | String partyB, 95 | String phoneNumber, 96 | String callbackUrl, 97 | String accountReference, 98 | String transactionDesc, 99 | ) async { 100 | await _validateTimeBoundedAceessToken(); 101 | String password = _generatePassword(businessShortCode); 102 | String timestamp = _getTimeStamp(); 103 | var body = { 104 | "BusinessShortCode": businessShortCode, 105 | "Password": password, 106 | "Timestamp": timestamp, 107 | "TransactionType": "CustomerPayBillOnline", 108 | "Amount": amount.toString(), 109 | "PartyA": partyA, 110 | "PartyB": businessShortCode, 111 | "PhoneNumber": phoneNumber, 112 | "CallBackURL": callbackUrl, 113 | "AccountReference": accountReference, 114 | "TransactionDesc": transactionDesc, 115 | }; 116 | 117 | var response = await http.post( 118 | Uri.parse(Endpoint.mpesaExpresSandbox), 119 | headers: { 120 | "Authorization": "Bearer $_accessToken", 121 | "Content-Type": "application/json", 122 | }, 123 | body: jsonEncode(body), 124 | ); 125 | 126 | return response.body; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 13 | # mpesa-daraja-plugin-flutter-dart 14 | 15 | dart wrapper for mpesa daraja api by safaricom. M-Pesa is a mobile phone-based money transfer, financing and microfinancing service, launched in 2007 by Vodafone for Safaricom and Vodacom the largest mobile network operators in Kenya and Tanzania. 16 | 17 | 18 | ## Features 19 | 20 | 1. [+]Lipa na mpesa 21 | 2. [inprogress] C2B 22 | 3. [inprogress] B2B 23 | 4. [inprogress] C2B 24 | 5. [inprogress] B2C 25 | 6. [inprogress] TRANSACTION STATUS 26 | 7. [inprogress] ACCOUNT BALANCE 27 | 8. [inprogress] REVERSAL 28 | ## Getting started 29 | 30 | You Will need a few things from Safaricom before development. 31 | 32 | 1. Consumer Key 33 | 2. Consumer Secret 34 | 3. Test Credentials for Development/Sanbox environment 35 | - Login or Register as a Safaricom developer here if you haven't. 36 | - Add a new App [here](https://developer.safaricom.co.ke/MyApps) 37 | - You will be issued with a ``Consumer Key`` and ``Consumer Secret``. You will use these to initiate an Mpesa Instance. 38 | - Obtain Test Credentials [here](https://developer.safaricom.co.ke/TestCredentials). 39 | - The Test Credentials Obtained Are only valid in Sandbox/Development environment. Take note of them. 40 | - To run in Production Environment you will need real Credentials. 41 | - To go Live and be issued with real credentials,please refer to this guide 42 | 43 | 4. Add dependancy in pubspec.yaml 44 | ```dart 45 | dependencies: 46 | mpesadaraja: ^0.1.5 47 | ``` 48 | 49 | 50 | 51 | ## Lipa Na MPesa Online 52 | LIPA NA M-PESA ONLINE also known as ``M-PESA express`` ``(STK Push)`` is a Merchant/Business initiated ``C2B`` (Customer to Business) Payment. This process it takes as described in the detailed sequence diagram below is: 53 | 54 | Once you, our merchant integrates to the API, you will be able to send a payment prompt on the customers phone (Popularly known as STK Push Prompt) to your customer's M-PESA registered phone number requesting them to enter their M-PESA pin to authorize and complete a payment. 55 | 56 | 1. create ``MpesaDaraja`` object and pass the following parameters: 57 | ```dart 58 | MpesaDaraja stkpush = MpesaDaraja( 59 | consumerKey:<> 60 | consumerSecret:<> 61 | passKey:<> 62 | ) 63 | ``` 64 | or make it a ``final`` as shown below: 65 | 66 | ```dart 67 | final stkpush = MpesaDaraja( 68 | consumerKey:<> 69 | consumerSecret:<> 70 | passKey:<> 71 | ) 72 | 73 | ``` 74 | 1. cosumerKey: 75 | 2. consumerSecret 76 | 3. passKey 77 | - The keys are generated when you create an app at [Daraja 2.0] website 78 | [Click here](https://developer.safaricom.co.ke/MyApps) to create your keys 79 | 80 | - The keys are a secret, so be sure to use them as environment variables in production code 81 | 82 | 2. Use the object created to call ``lipaNaMpesaStk()`` function to initialize the process 83 | - if the function is inside anaother be sure to use a ``Future`` with ``await`` when caloing the function 84 | - pass the required parameters in the function as shwon below 85 | ```dart 86 | await stk.lipaNaMpesaStk( 87 | , 88 | , 89 | , 90 | , 91 | , 92 | , 93 | , 94 | , 95 | ); 96 | 97 | ``` 98 | #### Parameters passed in lipaNaMpesaStk() function 99 | 1. ``BusinessShortCode``: This is organizations shortcode (Paybill or Buygoods - A 5 to 7 digit account number) used to identify an organization and receive the transaction. 100 | 101 | 2. ``Amount``: This is the Amount transacted normaly a numeric value. Money that customer pays to the Shorcode. Only whole numbers are supported. 102 | 103 | 3. ``PartyA``: The phone number sending money. The parameter expected is a Valid Safaricom Mobile Number that is M-Pesa registered in the format 2547XXXXXXXX 104 | 4. ``PartyB``: The organization receiving the funds. The parameter expected is a 5 to 7 digit as defined on the Shortcode description above. This can be the same as BusinessShortCode value above. 105 | 5. ``PhoneNUmber``: The Mobile Number to receive the STK Pin Prompt. This number can be the same as PartyA value above. 106 | 6. ``CallBackUrl``: A CallBack URL is a valid secure URL that is used to receive notifications from M-Pesa API. It is the endpoint to which the results will be sent by M-Pesa A 107 | 7. ``AccountReference``: Account Reference: This is an Alpha-Numeric parameter that is defined by your system as an Identifier of the transaction for CustomerPayBillOnline transaction type. Along with the business name, this value is also displayed to the customer in the STK Pin Prompt message. Maximum of 12 characters. 108 | 8. ``TransactionDescription``: This is any additional information/comment that can be sent along with the request from your system. Maximum of 13 Characters. 109 | 110 | 111 | #### N/B: Do not use my demo keys below since they will not work. 112 | 113 | ```dart 114 | Future main() async { 115 | final stk = MpesaDaraja( 116 | consumerKey: 'Dm4oJgziMyOT7WTmJzQfEZS6jjzg1Fkd', 117 | consumerSecret: 'RGRvsUGkO4jc3NuW', 118 | passKey: 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919', 119 | ); 120 | 121 | await stk.lipaNaMpesaStk( 122 | "174379", 123 | 1, 124 | "254798071520", 125 | "174379", 126 | "254798071520", 127 | "https://mydomain.com/path", 128 | "accountReference", 129 | "transactionDesc", 130 | ); 131 | } 132 | 133 | ``` 134 | 135 | ### Contributers 136 | 137 | 1. [Anselmo.Jr](https://github.com/flavian-anselmo) 138 | 2. [Joel](https://github.com/JoelKanyi) 139 | 3. [sav4ner](https://github.com/sav4ner) 140 | 141 | 142 | 143 | ## Demo 144 | - coming soon .... 145 | 146 | 147 | --------------------------------------------------------------------------------