PHPackages                             felixmuhoro/laravel-mpesa-checkout - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. felixmuhoro/laravel-mpesa-checkout

ActiveLibrary[Payment Processing](/categories/payments)

felixmuhoro/laravel-mpesa-checkout
==================================

Drop-in M-Pesa STK Push checkout UI for Laravel — Blade component + controller with full polling flow

v1.0.0(1mo ago)00MITPHPPHP ^8.1

Since Jun 4Pushed 1mo agoCompare

[ Source](https://github.com/felixmuhoro/laravel-mpesa-checkout)[ Packagist](https://packagist.org/packages/felixmuhoro/laravel-mpesa-checkout)[ Docs](https://github.com/felixmuhoro/laravel-mpesa-checkout)[ RSS](/packages/felixmuhoro-laravel-mpesa-checkout/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependencies (2)Versions (2)Used By (0)

laravel-mpesa-checkout
======================

[](#laravel-mpesa-checkout)

Drop-in M-Pesa STK Push checkout UI for Laravel — a Blade component + controller that handles the complete payment flow with JS polling.

Requirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 10 / 11 / 12 / 13
- [`felixmuhoro/laravel-mpesa`](https://github.com/felixmuhoro/laravel-mpesa) ^1.2

Installation
------------

[](#installation)

```
composer require felixmuhoro/laravel-mpesa-checkout
```

The service provider registers automatically via Laravel's package discovery.

Publish the config:

```
php artisan vendor:publish --tag=mpesa-checkout-config
```

Publish assets (JS):

```
php artisan vendor:publish --tag=mpesa-checkout-assets
```

Configuration
-------------

[](#configuration)

`config/mpesa-checkout.php` (with `.env` overrides):

KeyEnvDefaultDescription`session_ttl``MPESA_CHECKOUT_TTL``300`Session lifetime in seconds`poll_interval_ms``MPESA_CHECKOUT_POLL_INTERVAL``3000`JS poll interval (ms)`poll_timeout_ms``MPESA_CHECKOUT_POLL_TIMEOUT``120000`JS timeout before "expired" (ms)`route_prefix``MPESA_CHECKOUT_ROUTE_PREFIX``mpesa-checkout`URL prefix for package routes`cache_store``MPESA_CHECKOUT_CACHE_STORE``null` (default)Cache driver for sessions`webhook_secret``MPESA_CHECKOUT_WEBHOOK_SECRET``null`HMAC secret for callback verification`brand_name``APP_NAME``My App`Shown in the modal header`brand_logo``MPESA_CHECKOUT_LOGO``null`URL to your logo`redirect_success``MPESA_CHECKOUT_SUCCESS_URL``/`Page-flow success redirect`redirect_cancel``MPESA_CHECKOUT_CANCEL_URL``/`Page-flow cancel redirectUsage
-----

[](#usage)

### Blade Component (modal flow)

[](#blade-component-modal-flow)

Add to your layout — the button opens a modal, handles everything in-page:

```
{{-- In your layout head / bottom of body --}}
@stack('styles')
@stack('scripts')

{{-- Anywhere on the page --}}

```

JavaScript callbacks (optional):

```
function handleMpesaSuccess(detail) {
    console.log('Paid! Receipt:', detail.receipt);
    window.location.reload();
}

function handleMpesaFail(detail) {
    console.log('Failed:', detail.reason || detail.status);
}
```

You can also listen to DOM events:

```
document.addEventListener('mpesa:success', e => {
    console.log('receipt:', e.detail.receipt);
});
document.addEventListener('mpesa:fail', e => {
    console.log('reason:', e.detail.reason);
});
```

### Standalone Page Flow

[](#standalone-page-flow)

Redirect the user to the checkout page:

```
return redirect()->route('mpesa-checkout.page', [
    'amount'      => 1500,
    'reference'   => 'INV-2024-001',
    'description' => 'Order payment',
    'phone'       => $user->phone,
]);
```

Set `MPESA_CHECKOUT_SUCCESS_URL` and `MPESA_CHECKOUT_CANCEL_URL` to control where the user lands after payment.

### Programmatic API

[](#programmatic-api)

```
use FelixMuhoro\MpesaCheckout\CheckoutManager;

class OrderController extends Controller
{
    public function pay(Request $request, CheckoutManager $checkout)
    {
        $session = $checkout->initiate(
            amount:      1500,
            phone:       '0712345678',
            reference:   'INV-001',
            description: 'Order #1234',
        );

        return response()->json([
            'session_id' => $session->sessionId,
            'status'     => $session->status->value,
        ]);
    }
}
```

Routes
------

[](#routes)

MethodPathNameDescriptionPOST`/mpesa-checkout/initiate``mpesa-checkout.initiate`Start STK PushGET`/mpesa-checkout/poll/{sessionId}``mpesa-checkout.poll`JS polling endpointPOST`/mpesa-checkout/webhook``mpesa-checkout.webhook`M-Pesa callback URLDELETE`/mpesa-checkout/{sessionId}``mpesa-checkout.cancel`Cancel sessionGET`/mpesa-checkout/pay``mpesa-checkout.page`Standalone checkout page### Webhook / Callback URL

[](#webhook--callback-url)

Point your Safaricom Daraja app's **Confirmation URL** to:

```
https://yourdomain.com/mpesa-checkout/webhook

```

This URL is automatically excluded from CSRF verification.

Checkout Flow
-------------

[](#checkout-flow)

```
User clicks button
    -> JS POSTs /mpesa-checkout/initiate
    -> Safaricom sends STK Push to phone
    -> Modal shows "Check your phone" + countdown
    -> JS polls /mpesa-checkout/poll every 3 s
    -> On result: success or fail state shown
    -> Optional JS callback / DOM event fired

```

The poll endpoint also calls `stkQuery` against Safaricom on each poll, so it works even when the M-Pesa webhook callback is delayed or unreliable.

Customising Views
-----------------

[](#customising-views)

```
php artisan vendor:publish --tag=mpesa-checkout-views
```

Views are published to `resources/views/vendor/mpesa-checkout/`.

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

MIT - Felix Muhoro

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance90

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

50d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/f4e43995a8ec026a33d25263c30f437674d6d8481092cb3acd64e96e4ba3f4e4?d=identicon)[felixmuhoro](/maintainers/felixmuhoro)

---

Tags

laravelmpesakenyasafaricom

### Embed Badge

![Health badge](/badges/felixmuhoro-laravel-mpesa-checkout/health.svg)

```
[![Health](https://phpackages.com/badges/felixmuhoro-laravel-mpesa-checkout/health.svg)](https://phpackages.com/packages/felixmuhoro-laravel-mpesa-checkout)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
