mpesa_sdk_mz 3.0.0
mpesa_sdk_mz: ^3.0.0 copied to clipboard
A Dart package for M-Pesa API (Mozambique), maintained by ultramarcante and usable in any Dart framework because it is written in plain Dart.
mpesa_sdk_mz #
A Dart SDK for integrating with the M-Pesa Mozambique API, with explicit
support for sandbox and production.
This package is designed to be easy to start with and safe to configure:
- explicit environments
- separate credentials per environment
- typed requests
- raw HTTP responses plus typed parsers
- support for
C2B,B2C,B2B,Reversal,Transaction Status, andQuery Customer Masked Name
Table of Contents #
- Overview
- Quick Start
- How It Works
- Environment Configuration
- Basic Usage
- Responses
- API Summary
- Best Practices
- License
Overview #
This SDK wraps the authentication and HTTP calls needed to work with the M-Pesa Mozambique APIs in Dart or Flutter applications.
You still get access to the original http.Response, but the package also
provides typed requests and typed response parsers.
Before integrating, check the official documentation: https://developer.mpesa.vm.co.mz/documentation/
Quick Start #
1. Install the package #
dependencies:
mpesa_sdk_mz: <latest_version>
2. Import it #
import 'package:mpesa_sdk_mz/mpesa_sdk_mz.dart';
3. Export environment variables #
export MPESA_ENV=sandbox
export MPESA_API_KEY=YOUR_API_KEY
export MPESA_PUBLIC_KEY='YOUR_PUBLIC_KEY'
export MPESA_ORIGIN=developer.mpesa.vm.co.mz
4. Create a client #
final config = MpesaClientConfig(
environment: MpesaEnvironment.sandbox,
credentials: MpesaCredentials(
apiKey: Platform.environment['MPESA_API_KEY']!,
publicKey: Platform.environment['MPESA_PUBLIC_KEY']!,
),
origin: Platform.environment['MPESA_ORIGIN']!,
requestTimeout: const Duration(seconds: 30),
);
final transaction = MpesaTransaction(config);
5. Make a C2B call #
const payload = PaymentRequest(
inputTransactionReference: 'T12344C',
inputCustomerMsisdn: '25884xxxxxxx',
inputAmount: '10',
inputThirdPartyReference: '11114',
inputServiceProviderCode: '171717',
);
final response = await transaction.c2b(payload);
final parsed = transaction.parsePaymentResponse(response);
print(response.statusCode);
print(parsed.outputResponseDesc);
How It Works #
The main SDK flow is:
- Choose the active environment with
MpesaEnvironment. - Provide that environment's credentials with
MpesaCredentials. - Create
MpesaTransactionusingMpesaClientConfig. - Build a typed request and send the operation.
- Use the raw
http.Responseor a typed parser from the SDK.
If you need the bearer token separately:
final token = MpesaConfig.getBearerToken(
'API_KEY_HERE',
'PUBLIC_KEY_HERE',
);
Environment Configuration #
The SDK supports two environments:
MpesaEnvironment.sandboxMpesaEnvironment.production
Hosts are resolved automatically by the SDK:
sandbox→api.sandbox.vm.co.mzproduction→api.vm.co.mz
Each environment should have:
- its own
apiKey - its own
publicKey - its own
origin
Do not reuse credentials across environments.
Sandbox #
final config = MpesaClientConfig(
environment: MpesaEnvironment.sandbox,
credentials: MpesaCredentials(
apiKey: Platform.environment['MPESA_API_KEY']!,
publicKey: Platform.environment['MPESA_PUBLIC_KEY']!,
),
origin: Platform.environment['MPESA_ORIGIN']!,
requestTimeout: const Duration(seconds: 30),
);
Production #
final config = MpesaClientConfig(
environment: MpesaEnvironment.production,
credentials: MpesaCredentials(
apiKey: Platform.environment['MPESA_API_KEY']!,
publicKey: Platform.environment['MPESA_PUBLIC_KEY']!,
),
origin: Platform.environment['MPESA_ORIGIN']!,
requestTimeout: const Duration(seconds: 30),
);
Basic Usage #
C2B #
const payload = PaymentRequest(
inputTransactionReference: 'T12344C',
inputCustomerMsisdn: '25884xxxxxxx',
inputAmount: '10',
inputThirdPartyReference: '11114',
inputServiceProviderCode: '171717',
);
final response = await transaction.c2b(payload);
final parsed = transaction.parsePaymentResponse(response);
B2C #
const payload = PaymentRequest(
inputTransactionReference: 'T12344C',
inputCustomerMsisdn: '25884xxxxxxx',
inputAmount: '10',
inputThirdPartyReference: '11114',
inputServiceProviderCode: '171717',
);
await transaction.b2c(payload);
B2B #
const payload = TransferRequest(
inputTransactionReference: 'T12344C',
inputAmount: '10',
inputThirdPartyReference: '11114',
inputPrimaryPartyCode: '171717',
inputReceiverPartyCode: '979797',
);
await transaction.b2b(payload);
Reversal #
const payload = ReversalRequest(
inputTransactionID: '49XCDF6',
inputSecurityCredential: 'Mpesa2019',
inputInitiatorIdentifier: 'MPesa2018',
inputThirdPartyReference: '11114',
inputServiceProviderCode: '171717',
inputReversalAmount: '10',
);
await transaction.reversal(payload);
Query Transaction Status #
final response = await transaction.getTransactionStatus(
const TransactionStatusRequest(
inputThirdPartyReference: '11114',
inputQueryReference: '5C1400CVRO',
inputServiceProviderCode: '171717',
),
);
final parsed = transaction.parseTransactionStatusResponse(response);
Query Customer Masked Name #
final response = await transaction.getCustomerMaskedName(
const CustomerNameRequest(
inputCustomerMsisdn: '25884xxxxxxx',
inputThirdPartyReference: '11114',
inputServiceProviderCode: '171717',
),
);
final parsed = transaction.parseCustomerNameResponse(response);
Responses #
All operations return http.Response.
Requests use a default timeout of 30 seconds. If the request does not finish
in time, the SDK throws MpesaTimeoutException.
This allows you to:
- inspect
statusCode - inspect
headers - use the raw
body - convert the response with the SDK's typed parsers
Example:
final response = await transaction.c2b(payload);
if (response.statusCode == 200 || response.statusCode == 201) {
final parsed = transaction.parsePaymentResponse(response);
print(parsed.outputTransactionID);
} else {
print(response.body);
}
Network Error Handling #
Network failures are surfaced as SDK exceptions so callers can distinguish transport problems from API responses:
MpesaTimeoutException: the request exceededrequestTimeoutMpesaNetworkException: socket or HTTP client transport failureMpesaResponseParseException: response body could not be parsedMpesaConfigurationException: bearer token generation failed before sending
Example:
try {
final response = await transaction.c2b(payload);
final parsed = transaction.parsePaymentResponse(response);
print(parsed.outputResponseDesc);
} on MpesaTimeoutException catch (error) {
print(error.message);
} on MpesaNetworkException catch (error) {
print(error.message);
} on MpesaResponseParseException catch (error) {
print(error.body);
}
API Summary #
| Operation | HTTP Method | Request Type | Recommended parser |
|---|---|---|---|
| C2B | POST |
PaymentRequest |
parsePaymentResponse |
| B2C | POST |
PaymentRequest |
parsePaymentResponse |
| B2B | POST |
TransferRequest |
parsePaymentResponse |
| Reversal | PUT |
ReversalRequest |
parseOutputResponse |
| Transaction Status | GET |
TransactionStatusRequest |
parseTransactionStatusResponse |
| Query Customer Masked Name | GET |
CustomerNameRequest |
parseCustomerNameResponse |
Best Practices #
- Use
sandboxbefore going live in production. - Do not mix credentials between environments.
- Load
apiKey,publicKey, andoriginfrom environment variables or a secure secret manager instead of hardcoding them. - Always set
originexplicitly for the active environment. - Tune
requestTimeoutfor your deployment instead of relying on unbounded I/O. - Check
response.statusCodebefore assuming success. - Use the typed parsers when you want to read official response fields with less manual JSON handling.
License #
This project is licensed under the MIT License. See LICENSE.