rndwiga/mpesa-sdk
Composer 安装命令:
composer require rndwiga/mpesa-sdk
包简介
An expressive mpesa implementation
README 文档
README
An opinionated fluent Safaricom M-Pesa SDK that provides a simple and elegant way to integrate with the Safaricom M-Pesa API.
Table of Contents
- Tech Stack
- Installation
- Requirements
- Configuration
- Features
- Usage
- Handling Callbacks
- Utilities
- Error Handling
- Custom Implementations
- Examples
- Testing
- Contributing
- License
Tech Stack
Server: Nginx, Apache, PHP 8.1+
Installation
Install the package via Composer:
composer require rndwiga/mpesa-sdk
Or clone the project:
git clone https://github.com/Rndwiga/mpesa-sdk.git
cd mpesa-sdk
composer update
Laravel Integration
This package supports Laravel integration out of the box. After installing the package, the service provider will be automatically registered thanks to Laravel's package auto-discovery feature.
If you're using Laravel < 5.5 or have disabled auto-discovery, add the service provider and facade to your config/app.php file:
'providers' => [ // ... Rndwiga\Mpesa\MpesaServiceProvider::class, ], 'aliases' => [ // ... 'Mpesa' => Rndwiga\Mpesa\Facades\Mpesa::class, ],
Then publish the configuration file:
php artisan vendor:publish --tag=mpesa-config
Requirements
- PHP 8.1 or higher
- phpseclib/phpseclib 2.0 or higher
- psr/log 3.0 or higher (for logging)
- OpenSSL and JSON PHP extensions
Configuration
The SDK requires several environment variables to be set for proper operation:
# M-Pesa API Credentials
MPESA_CONSUMER_KEY=your_consumer_key
MPESA_CONSUMER_SECRET=your_consumer_secret
MPESA_INITIATOR_NAME=your_initiator_name
MPESA_INITIATOR_PASSWORD=your_initiator_password
# Business Shortcode
MPESA_SHORTCODE=your_shortcode
MPESA_BUSINESS_SHORTCODE=your_business_shortcode
# Express (STK Push) Settings
MPESA_PASSKEY=your_passkey
# Environment
MPESA_PRODUCTION=false
# Callback URLs
MPESA_CALLBACK_URL=https://your-domain.com/api/callback
MPESA_TIMEOUT_URL=https://your-domain.com/api/timeout
MPESA_RESULT_URL=https://your-domain.com/api/result
Laravel Configuration
When using the package with Laravel, you can publish the configuration file to customize the settings:
php artisan vendor:publish --tag=mpesa-config
This will create a config/mpesa.php file in your Laravel application where you can configure all the M-Pesa settings. The configuration values will be automatically loaded from your .env file using the prefixed environment variables (e.g., MPESA_CONSUMER_KEY).
Example Laravel .env configuration:
MPESA_CONSUMER_KEY=your_consumer_key
MPESA_CONSUMER_SECRET=your_consumer_secret
MPESA_PRODUCTION=false
MPESA_INITIATOR_NAME=your_initiator_name
MPESA_INITIATOR_PASSWORD=your_initiator_password
MPESA_SHORTCODE=your_shortcode
MPESA_BUSINESS_SHORTCODE=your_business_shortcode
MPESA_PASSKEY=your_passkey
MPESA_CALLBACK_URL=https://your-domain.com/api/callback
MPESA_TIMEOUT_URL=https://your-domain.com/api/timeout
MPESA_RESULT_URL=https://your-domain.com/api/result
Features
The SDK provides the following features:
API Services
- B2C (Business to Customer) - Send money from a business to customers
- B2B (Business to Business) - Send money from one business to another
- C2B (Customer to Business) - Receive money from customers
- Express (STK Push) - Prompt customers to enter their M-Pesa PIN on their phones
- Account Balance - Check account balance
- Transaction Status - Check the status of a transaction
- Transaction Reversal - Reverse a transaction
Additional Features
- PSR-3 Logging - Comprehensive logging of API requests and responses
- Token Caching - Efficient caching of access tokens to reduce API calls
- Enhanced Webhook Handling - Simplified processing of M-Pesa callbacks
- Custom Exceptions - Detailed exception handling for better error management
- Utilities - Logging, Storage, JSON Management, and Helper Functions
Usage
Initialization
Initialize the MpesaAPI with your credentials:
use Rndwiga\Mpesa\MpesaAPI; use Monolog\Logger; use Monolog\Handler\StreamHandler; use Rndwiga\Mpesa\Utils\FileCache; // Create a logger (optional) $logger = new Logger('mpesa'); $logger->pushHandler(new StreamHandler('path/to/mpesa.log', Logger::DEBUG)); // Create a cache (optional) $cache = new FileCache('path/to/cache'); // Initialize the Mpesa API $mpesa = new MpesaAPI( 'your_consumer_key', 'your_consumer_secret', false, // false for sandbox, true for production $logger, // optional $cache // optional );
Laravel Usage
When using the package with Laravel, you can access the Mpesa API through the facade:
use Rndwiga\Mpesa\Facades\Mpesa; // The Mpesa facade automatically uses the configuration from config/mpesa.php // No need to manually initialize the API // Example: Send money using B2C $response = Mpesa::b2c() ->setInitiatorName(config('mpesa.initiator_name')) ->setSecurityCredential(config('mpesa.initiator_password')) ->setCommandId('BusinessPayment') ->setAmount(100) ->setPartyA(config('mpesa.shortcode')) ->setPartyB('254712345678') ->setRemarks('Payment for services') ->setQueueTimeoutUrl(config('mpesa.timeout_url')) ->setResultUrl(config('mpesa.result_url')) ->setOccasion('Service payment') ->makePayment(); // Example: STK Push $response = Mpesa::express() ->setBusinessShortCode(config('mpesa.business_shortcode')) ->setPasskey(config('mpesa.passkey')) ->setTransactionType('CustomerPayBillOnline') ->setAmount(100) ->setPartyA('254712345678') ->setPartyB(config('mpesa.business_shortcode')) ->setPhoneNumber('254712345678') ->setCallbackUrl(config('mpesa.callback_url')) ->setAccountReference('Payment for order #123') ->setTransactionDesc('Payment for product/service') ->push();
You can also use dependency injection in your controllers:
use Rndwiga\Mpesa\MpesaAPI; class PaymentController extends Controller { protected $mpesa; public function __construct(MpesaAPI $mpesa) { $this->mpesa = $mpesa; } public function processPayment() { $response = $this->mpesa->express() ->setBusinessShortCode(config('mpesa.business_shortcode')) // ... other settings ->push(); // Process the response return response()->json($response); } }
B2C (Business to Customer)
Send money from a business to a customer:
$response = $mpesa->b2c() ->setInitiatorName('your_initiator_name') ->setSecurityCredential('your_initiator_password') ->setCommandId('BusinessPayment') // Options: SalaryPayment, BusinessPayment, PromotionPayment ->setAmount(100) // Amount to send ->setPartyA('your_shortcode') // Your shortcode ->setPartyB('254712345678') // Customer phone number ->setRemarks('Payment for services') // Transaction remarks ->setQueueTimeoutUrl('https://example.com/timeout') // Timeout URL ->setResultUrl('https://example.com/result') // Result URL ->setOccasion('Service payment') // Optional: Transaction occasion ->makePayment();
B2B (Business to Business)
Send money from one business to another:
$response = $mpesa->b2b() ->setInitiatorName('your_initiator_name') ->setSecurityCredential('your_initiator_password') ->setCommandId('BusinessPayBill') // Options: BusinessPayBill, MerchantToMerchantTransfer, etc. ->setAmount(100) // Amount to send ->setSenderIdentifierType(4) // 4 for organization shortcode ->setReceiverIdentifierType(4) // 4 for organization shortcode ->setPartyA('your_shortcode') // Your shortcode ->setPartyB('600000') // Receiver shortcode ->setAccountReference('Account reference') ->setRemarks('Payment for services') // Transaction remarks ->setQueueTimeoutUrl('https://example.com/timeout') // Timeout URL ->setResultUrl('https://example.com/result') // Result URL ->makePayment();
C2B (Customer to Business)
Register URLs for C2B transactions:
$response = $mpesa->c2b() ->setShortCode('your_shortcode') // Your shortcode ->setResponseType('Completed') // Options: Completed, Cancelled ->setConfirmationURL('https://example.com/confirmation') ->setValidationURL('https://example.com/validation') ->registerURLs();
Simulate a C2B transaction (for testing in sandbox):
$response = $mpesa->c2b() ->setShortCode('your_shortcode') // Your shortcode ->setCommandID('CustomerPayBillOnline') // Options: CustomerPayBillOnline, CustomerBuyGoodsOnline ->setAmount(100) // Amount to send ->setMsisdn('254712345678') // Customer phone number ->setBillRefNumber('REF123') // Reference number ->simulate();
Express (STK Push)
Prompt a customer to enter their M-Pesa PIN on their phone:
$response = $mpesa->express() ->setBusinessShortCode('your_business_shortcode') ->setPasskey('your_passkey') ->setTransactionType('CustomerPayBillOnline') ->setAmount(100) // Amount to charge ->setPartyA('254712345678') // Customer phone number ->setPartyB('your_business_shortcode') // Your shortcode ->setPhoneNumber('254712345678') // Customer phone number ->setCallbackUrl('https://example.com/callback') // Callback URL ->setAccountReference('Payment for order #123') // Reference ->setTransactionDesc('Payment for product/service') // Description ->push();
Query the status of an STK push:
$response = $mpesa->express() ->setBusinessShortCode('your_business_shortcode') ->setPasskey('your_passkey') ->query('ws_CO_DMZ_123456789_123456789');
Account Balance
Check your account balance:
$response = $mpesa->account() ->setInitiatorName('your_initiator_name') ->setSecurityCredential('your_initiator_password') ->setCommandId('AccountBalance') ->setPartyA('your_shortcode') // Your shortcode ->setIdentifierType(4) // 4 for organization shortcode ->setRemarks('Account balance query') ->setQueueTimeoutUrl('https://example.com/timeout') // Timeout URL ->setResultUrl('https://example.com/result') // Result URL ->queryBalance();
Transaction Status
Check the status of a transaction:
$response = $mpesa->account() ->setInitiatorName('your_initiator_name') ->setSecurityCredential('your_initiator_password') ->setCommandId('TransactionStatusQuery') ->setPartyA('your_shortcode') // Your shortcode ->setIdentifierType(4) // 4 for organization shortcode ->setTransactionID('LKXXXX1234') // The M-Pesa Transaction ID ->setRemarks('Transaction status query') ->setQueueTimeoutUrl('https://example.com/timeout') // Timeout URL ->setResultUrl('https://example.com/result') // Result URL ->queryTransactionStatus();
Transaction Reversal
Reverse a transaction:
$response = $mpesa->account() ->setInitiatorName('your_initiator_name') ->setSecurityCredential('your_initiator_password') ->setTransactionId('LKXXXX1234') ->setAmount(100) // Amount to reverse ->setReceiverParty('receiver_shortcode') ->setReceiverIdentifierType(Rndwiga\Mpesa\Api\Account::IDENTIFIER_TYPE_SHORTCODE) ->setRemarks('Test reversal') ->setQueueTimeoutUrl('https://example.com/timeout') ->setResultUrl('https://example.com/result') ->setOccasion('Test occasion') ->reverseTransaction();
Handling Callbacks
Using the WebhookHandler (Recommended)
Process callbacks from M-Pesa:
// Get the callback data $callbackData = file_get_contents('php://input'); // Create a webhook handler $webhook = $mpesa->webhook($callbackData); // Check the callback type if ($webhook->isCallbackType('express')) { // Handle Express (STK Push) callback $resultCode = $webhook->getValue('Body.stkCallback.ResultCode'); $resultDesc = $webhook->getValue('Body.stkCallback.ResultDesc'); if ($resultCode == 0) { // Transaction was successful $amount = $webhook->getValueFromItems('Amount'); $receiptNumber = $webhook->getValueFromItems('MpesaReceiptNumber'); $transactionDate = $webhook->getValueFromItems('TransactionDate'); $phoneNumber = $webhook->getValueFromItems('PhoneNumber'); // Process the payment // ... } // Send a success response back to Mpesa echo $webhook->generateSuccessResponse('Callback processed successfully'); } elseif ($webhook->isCallbackType('b2c')) { // Handle B2C callback // ... } elseif ($webhook->isCallbackType('c2b')) { // Handle C2B callback // ... }
Alternative Method
// Create a webhook handler and capture the callback data $webhook = $mpesa->webhook(); $webhook->captureCallback()->parseCallback(); // Check the type of callback if ($webhook->isCallbackType('c2b')) { // Process C2B callback $transactionId = $webhook->getValue('TransID'); $amount = $webhook->getValue('TransAmount'); $phoneNumber = $webhook->getValue('MSISDN'); // Do something with the data... } elseif ($webhook->isCallbackType('express')) { // Process STK Push callback $resultCode = $webhook->getValue('Body.stkCallback.ResultCode'); $resultDesc = $webhook->getValue('Body.stkCallback.ResultDesc'); // Get nested values using dot notation $amount = $webhook->getValue('Body.stkCallback.CallbackMetadata.Item.0.Value'); $mpesaReceiptNumber = $webhook->getValue('Body.stkCallback.CallbackMetadata.Item.1.Value'); // Do something with the data... } // Send a success response back to Mpesa echo $webhook->generateSuccessResponse('Transaction processed successfully'); // Or send an error response if needed // echo $webhook->generateErrorResponse('Transaction failed', '1');
Legacy Method
// For STK Push callbacks $callbackData = json_decode(file_get_contents('php://input'), true); $processedCallback = $mpesa->express()->processCallback($callbackData); // For other callbacks (B2C, B2B, Account Balance, etc.) $callbackData = json_decode(file_get_contents('php://input'), true); $processedCallback = $mpesa->account()->processCallback($callbackData); // Send a success response back to Mpesa echo $mpesa->finishTransaction();
Utilities
Logging
The SDK includes multiple logging options:
Using PSR-3 Compatible Logger
use Monolog\Logger; use Monolog\Handler\StreamHandler; $logger = new Logger('mpesa'); $logger->pushHandler(new StreamHandler('path/to/mpesa.log', Logger::DEBUG)); // Use the logger with the MpesaAPI $mpesa = new MpesaAPI( 'your_consumer_key', 'your_consumer_secret', false, $logger ); // The logger will automatically log API requests and responses
Using the Built-in Logger
use Rndwiga\Mpesa\Utils\Logger; // Create a logger with folder and file name $logger = new Logger('mpesa_logs', 'transactions'); // Log data at different levels $logger->logDebugData(['transaction_id' => '123456', 'status' => 'pending']); $logger->logInfoData(['message' => 'Payment received', 'amount' => 1000]); $logger->logWarningData(['message' => 'Retry attempt', 'attempt' => 3]); $logger->logErrorData(['message' => 'Transaction failed', 'reason' => 'Timeout']); // Or use PSR-3 methods $logger->debug('Debug message', ['context' => 'value']); $logger->info('Info message', ['context' => 'value']); $logger->warning('Warning message', ['context' => 'value']); $logger->error('Error message', ['context' => 'value']); // Get the log file path $logFilePath = $logger->getLogFile('log'); // Returns path to transactions.log
Storage
The SDK includes multiple storage options:
Using File Cache
use Rndwiga\Mpesa\Utils\FileCache; $cache = new FileCache('path/to/cache'); // Use the cache with the MpesaAPI $mpesa = new MpesaAPI( 'your_consumer_key', 'your_consumer_secret', false, null, $cache ); // The cache will automatically store access tokens
Using the Storage Class
use Rndwiga\Mpesa\Utils\Storage; // Create a storage instance $storage = new Storage('mpesa_data'); $storage->setLogFolder('transactions'); // Create a storage path $path = $storage->createStorage(); // Get the full storage path $fullPath = $storage->storagePath($path); // Compress a file $compressedFile = Storage::gzCompressFile('path/to/file.txt', 9, true); // Generate a random ID $randomId = Storage::generateRandomId();
JSON Management
The SDK includes utilities for working with JSON data:
Using WebhookHandler
use Rndwiga\Mpesa\Utils\WebhookHandler; // Parse JSON data $webhook = new WebhookHandler(); $webhook->captureCallback($jsonData); $webhook->parseCallback(); // Extract values using dot notation $value = $webhook->getValue('path.to.value'); // Generate JSON responses $response = $webhook->generateSuccessResponse('Success message');
Using JsonManager
use Rndwiga\Mpesa\Utils\JsonManager; // Save data to a JSON file $result = JsonManager::saveToFile('data.json', 'transactions', ['id' => 123, 'amount' => 1000]); // Save data to a specific file path $result = JsonManager::saveToFilePath('/path/to/file.json', ['id' => 123, 'amount' => 1000]); // Read a JSON file $data = JsonManager::readJsonFile('/path/to/file.json', true); // Add data to an existing JSON file $result = JsonManager::addDataToJsonFile('/path/to/file.json', ['id' => 456, 'amount' => 2000]); // Validate JSON data $validation = JsonManager::validateJsonData('{"id": 123, "amount": 1000}'); if ($validation['status'] === 'success') { // JSON is valid $data = $validation['response']; }
Helper Functions
The SDK includes helper functions for common tasks:
use function Rndwiga\Mpesa\Utils\mpesa_env; use function Rndwiga\Mpesa\Utils\mpesa_str_slug; // Get an environment variable $apiKey = mpesa_env('MPESA_API_KEY'); // Convert a string to a URL-friendly slug $slug = mpesa_str_slug('Hello World'); // Returns 'hello-world'
When using the package with Laravel, these helper functions are designed to work seamlessly with Laravel's built-in functions. The mpesa_env() function will use Laravel's env() function if available, and mpesa_str_slug() will use Laravel's Str::slug() if available.
Error Handling
The SDK provides detailed error handling for API responses:
try { $response = $mpesa->express()->push(); if (isset($response['success']) && $response['success']) { // Request was successful $checkoutRequestId = $response['data']->CheckoutRequestID; // ... } else { // Request failed $errorMessage = $response['errorMessage'] ?? 'Unknown error'; // Handle the error } } catch (\Exception $e) { // Handle exceptions $errorMessage = $e->getMessage(); // ... }
The package also provides custom exception classes for better error handling:
use Rndwiga\Mpesa\Exceptions\MpesaException; use Rndwiga\Mpesa\Exceptions\AuthenticationException; use Rndwiga\Mpesa\Exceptions\ValidationException; use Rndwiga\Mpesa\Exceptions\ApiException; try { // Make an API request $response = $mpesa->b2c() ->setInitiatorName('your_initiator_name') ->setSecurityCredential('your_initiator_password') ->setCommandId(Rndwiga\Mpesa\Api\B2C::COMMAND_ID_BUSINESS_PAYMENT) ->setAmount(100) ->setPartyA('your_shortcode') ->setPartyB('254722000000') ->setRemarks('Test payment') ->setQueueTimeoutUrl('https://example.com/timeout') ->setResultUrl('https://example.com/result') ->setOccasion('Test occasion') ->makePayment(); // Check if the request was successful if (!$response['success']) { // Handle API error echo "API Error: " . $response['errorMessage']; } } catch (AuthenticationException $e) { // Handle authentication errors (e.g., invalid credentials) echo "Authentication Error: " . $e->getMessage(); } catch (ValidationException $e) { // Handle validation errors (e.g., invalid phone number) echo "Validation Error: " . $e->getMessage(); } catch (ApiException $e) { // Handle API-specific errors echo "API Error: " . $e->getMessage(); echo "API Error Code: " . $e->getApiErrorCode(); echo "Request ID: " . $e->getRequestId(); // Get additional error data if available $errorData = $e->getErrorData(); if ($errorData) { // Process error data } } catch (MpesaException $e) { // Handle other Mpesa-related errors echo "Mpesa Error: " . $e->getMessage(); } catch (\Exception $e) { // Handle other unexpected errors echo "Error: " . $e->getMessage(); }
Custom Implementations
Custom Cache Implementation
You can create your own cache implementation by implementing the CacheInterface:
use Rndwiga\Mpesa\Utils\CacheInterface; class RedisCache implements CacheInterface { private $redis; public function __construct($redisClient) { $this->redis = $redisClient; } public function get(string $key, $default = null) { $value = $this->redis->get($key); return $value !== false ? json_decode($value, true) : $default; } public function set(string $key, $value, ?int $ttl = null): bool { return $this->redis->setex($key, $ttl ?? 3600, json_encode($value)); } public function has(string $key): bool { return $this->redis->exists($key); } public function delete(string $key): bool { return $this->redis->del($key) > 0; } } // Use your custom cache implementation $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $cache = new RedisCache($redis); $mpesa = new MpesaAPI( 'your_consumer_key', 'your_consumer_secret', false, $logger, $cache );
Examples
Check the examples directory for more detailed examples:
b2c_example.php: Example of B2C paymentb2b_example.php: Example of B2B paymentc2b_example.php: Example of C2B registration and simulationexpress_example.php: Example of STK Push and callback processingaccount_balance_example.php: Example of checking account balancetransaction_status_example.php: Example of checking transaction statustransaction_reversal_example.php: Example of reversing a transactionwebhook_example.php: Example of using the WebhookHandler to process callbacks
All examples demonstrate the use of logging, caching, and webhook handling features.
Testing
The package includes comprehensive tests for all components using PestPHP, a delightful testing framework for PHP:
composer test
You can also run the tests directly:
./vendor/bin/pest
Or run specific test files:
./vendor/bin/pest tests/Client/MpesaClientTest.php ./vendor/bin/pest tests/Utils/WebhookHandlerTest.php
PestPHP provides a more expressive and elegant syntax for writing tests. For more information, visit pestphp.com.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
rndwiga/mpesa-sdk 适用场景与选型建议
rndwiga/mpesa-sdk 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 28 次下载、GitHub Stars 达 1, 最近一次更新时间为 2018 年 07 月 10 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「php」 「laravel」 「ai」 「mpesa」 「rndwiga」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 rndwiga/mpesa-sdk 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 rndwiga/mpesa-sdk 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 rndwiga/mpesa-sdk 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Beyonic PHP Library
Alfabank REST API integration
Mpesa driver for omnipay payment processing library
Zero-dependency raw PHP DNS resolver, domain-ownership verification, and intoDNS/MxToolbox-style diagnostics. Queries authoritative nameservers directly over sockets — never trusts the recursive cache for ownership checks.
Laravel package for Accurate Online API integration.
Official Safaricom Daraja M-Pesa integration for Laravel built on ysg/payment-core.
统计信息
- 总下载量: 28
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 28
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2018-07-10