tish / laravel-mpesa
Laravel M-Pesa Lipa Na M-Pesa STK Push integration package with automatic callback handling
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.8.2
- illuminate/support: ^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^7.0|^8.0|^9.0|^10.0|^11.0
- phpunit/phpunit: ^10.5|^11.5|^12.0
This package is auto-updated.
Last update: 2025-07-17 09:49:12 UTC
README
A Laravel package for integrating M-Pesa Lipa Na M-Pesa STK Push payments.
Installation
For Development/Testing (Package not yet published)
- Create the package structure in your Laravel project:
# In your Laravel project root
mkdir -p packages/tish/laravel-mpesa
-
Copy all package files to
packages/tish/laravel-mpesa/
(see file structure below) -
Add the local package repository to your main
composer.json
:
{ "repositories": [ { "type": "path", "url": "./packages/tish/laravel-mpesa" } ], "require": { "tish/laravel-mpesa": "dev-main" } }
- Install the local package:
composer require tish/laravel-mpesa:dev-main
For Production (Once Published to Packagist)
- Install the package via Composer:
composer require tish/laravel-mpesa
- Publish the config file and migrations:
php artisan vendor:publish --provider="Tish\LaravelMpesa\MpesaServiceProvider"
php artisan migrate
- Add your M-Pesa credentials to your
.env
file:
MPESA_CONSUMER_KEY=your_consumer_key MPESA_CONSUMER_SECRET=your_consumer_secret MPESA_PASSKEY=your_passkey MPESA_BUSINESS_SHORT_CODE=your_shortcode MPESA_CALLBACK_URL=https://yourdomain.com/mpesa/callback MPESA_SANDBOX=true
- Create listeners to handle payment events:
php artisan make:listener HandleSuccessfulPayment php artisan make:listener HandleFailedPayment
- Register the event listeners in your
app/Providers/EventServiceProvider.php
:
<?php namespace App\Providers; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Tish\LaravelMpesa\Events\PaymentCompleted; use Tish\LaravelMpesa\Events\PaymentFailed; class EventServiceProvider extends ServiceProvider { protected $listen = [ PaymentCompleted::class => [ \App\Listeners\HandleSuccessfulPayment::class, ], PaymentFailed::class => [ \App\Listeners\HandleFailedPayment::class, ], ]; public function boot() { // } }
- Implement your listeners:
app/Listeners/HandleSuccessfulPayment.php
:
<?php namespace App\Listeners; use Tish\LaravelMpesa\Events\PaymentCompleted; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Support\Facades\Log; class HandleSuccessfulPayment implements ShouldQueue { use InteractsWithQueue; public function handle(PaymentCompleted $event) { $transaction = $event->transaction; Log::info('Payment completed', [ 'account_reference' => $transaction->account_reference, 'receipt_number' => $transaction->mpesa_receipt_number, 'amount' => $transaction->amount, 'phone' => $transaction->phone_number, ]); // Update your database here // Example: Find order by account_reference and mark as paid /* $order = Order::where('order_number', $transaction->account_reference)->first(); if ($order) { $order->update([ 'status' => 'paid', 'mpesa_receipt' => $transaction->mpesa_receipt_number, 'payment_date' => $transaction->transaction_date, ]); } */ } }
app/Listeners/HandleFailedPayment.php
:
<?php namespace App\Listeners; use Tish\LaravelMpesa\Events\PaymentFailed; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Support\Facades\Log; class HandleFailedPayment implements ShouldQueue { use InteractsWithQueue; public function handle(PaymentFailed $event) { $transaction = $event->transaction; Log::warning('Payment failed', [ 'account_reference' => $transaction->account_reference, 'result_desc' => $transaction->result_desc, 'amount' => $transaction->amount, 'phone' => $transaction->phone_number, ]); // Handle failed payment // Example: Update order status, send notification, etc. /* $order = Order::where('order_number', $transaction->account_reference)->first(); if ($order) { $order->update(['status' => 'payment_failed']); } */ } }
Usage
Initiate STK Push Payment
use Tish\LaravelMpesa\Facades\Mpesa; $response = Mpesa::stkPush( '254712345678', // Phone number 100, // Amount 'ORDER-12345', // Account reference (your order ID) 'Payment for Order 12345' // Transaction description ); if (isset($response['CheckoutRequestID'])) { // Payment initiated successfully // Store the CheckoutRequestID for tracking $checkoutRequestId = $response['CheckoutRequestID']; } else { // Handle error }
Check Payment Status
// Get transaction status $status = file_get_contents("http://yourapp.com/mpesa/status/{$checkoutRequestId}"); $statusData = json_decode($status, true); if ($statusData['status'] === 'completed') { echo "Payment successful! Receipt: " . $statusData['mpesa_receipt_number']; } elseif ($statusData['status'] === 'failed') { echo "Payment failed: " . $statusData['result_desc']; } else { echo "Payment pending..."; }
Available Transaction Data in Events
When handling the PaymentCompleted
or PaymentFailed
events, you have access to:
$transaction = $event->transaction; // Available properties: $transaction->checkout_request_id // M-Pesa checkout request ID $transaction->merchant_request_id // M-Pesa merchant request ID $transaction->phone_number // Customer phone number $transaction->amount // Transaction amount $transaction->account_reference // Your reference (order ID, etc.) $transaction->transaction_desc // Transaction description $transaction->status // 'pending', 'completed', 'failed' $transaction->mpesa_receipt_number // M-Pesa receipt (if successful) $transaction->transaction_date // When payment was made $transaction->result_code // M-Pesa result code $transaction->result_desc // M-Pesa result description
Important Notes
-
Callback URL: Make sure your
MPESA_CALLBACK_URL
is publicly accessible and points tohttps://yourdomain.com/mpesa/callback
-
Queue Workers: Since the listeners implement
ShouldQueue
, make sure you have queue workers running:php artisan queue:work
-
Logging: All M-Pesa transactions are logged for debugging. Check your Laravel logs.
-
Testing: Use the sandbox environment for testing by setting
MPESA_SANDBOX=true
Security
The package handles M-Pesa callback validation and ensures only valid callbacks are processed. Always use HTTPS in production.
Support
For support, please open an issue on GitHub.