PHPackages                             njoguamos/laravel-pesapal - 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. njoguamos/laravel-pesapal

ActiveLibrary[Payment Processing](/categories/payments)

njoguamos/laravel-pesapal
=========================

A Laravel package for interacting with https://www.pesapal.com api

v3.0.0(1mo ago)82.8k↓11.1%3[1 PRs](https://github.com/njoguamos/laravel-pesapal/pulls)1MITPHPPHP ^8.3 | ^8.4 | 8.5CI passing

Since Mar 12Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/njoguamos/laravel-pesapal)[ Packagist](https://packagist.org/packages/njoguamos/laravel-pesapal)[ Docs](https://github.com/njoguamos/laravel-pesapal)[ GitHub Sponsors](https://github.com/njoguamos)[ RSS](/packages/njoguamos-laravel-pesapal/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (28)Versions (62)Used By (1)

[![](https://camo.githubusercontent.com/c908f86c87ef9c61b218db982c338060bbb6321054d3f953a3535160656d4f05/68747470733a2f2f62616e6e6572732e6265796f6e64636f2e64652f4c61726176656c2532305065736170616c2e706e673f7468656d653d6c69676874267061636b6167654d616e616765723d636f6d706f7365722b72657175697265267061636b6167654e616d653d6e6a6f6775616d6f732532466c61726176656c2d7065736170616c267061747465726e3d7261696e267374796c653d7374796c655f32266465736372697074696f6e3d412b4c61726176656c2b7061636b6167652b666f722b696e746572616374696e672b776974682b68747470732533412532462532467777772e7065736170616c2e636f6d2b617069266d643d312673686f7757617465726d61726b3d3026666f6e7453697a653d313030707826696d616765733d68747470732533412532462532466c61726176656c2e636f6d253246696d672532466c6f676f6d61726b2e6d696e2e737667)](https://camo.githubusercontent.com/c908f86c87ef9c61b218db982c338060bbb6321054d3f953a3535160656d4f05/68747470733a2f2f62616e6e6572732e6265796f6e64636f2e64652f4c61726176656c2532305065736170616c2e706e673f7468656d653d6c69676874267061636b6167654d616e616765723d636f6d706f7365722b72657175697265267061636b6167654e616d653d6e6a6f6775616d6f732532466c61726176656c2d7065736170616c267061747465726e3d7261696e267374796c653d7374796c655f32266465736372697074696f6e3d412b4c61726176656c2b7061636b6167652b666f722b696e746572616374696e672b776974682b68747470732533412532462532467777772e7065736170616c2e636f6d2b617069266d643d312673686f7757617465726d61726b3d3026666f6e7453697a653d313030707826696d616765733d68747470732533412532462532466c61726176656c2e636f6d253246696d672532466c6f676f6d61726b2e6d696e2e737667)

Laravel 11+ package for interacting with Pesapal API
====================================================

[](#laravel-11-package-for-interacting-with-pesapal-api)

[![Latest Version on Packagist](https://camo.githubusercontent.com/b3fd8d4bf158a87e83864dc02c4d6fc04673491f44f33c1f47e1a2aaee13ea71/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e6a6f6775616d6f732f6c61726176656c2d7065736170616c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/njoguamos/laravel-pesapal)[![GitHub Actions Test Status](https://camo.githubusercontent.com/1d3d7b5e3b1acbf8bab8d693f4f6e7fab6e9f08c5df4e7f6ffa71665ac136a83/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e6a6f6775616d6f732f6c61726176656c2d7065736170616c2f72756e2d74657374732e796d6c3f6c6f676f3d676974687562266c6162656c3d5465737473)](https://camo.githubusercontent.com/1d3d7b5e3b1acbf8bab8d693f4f6e7fab6e9f08c5df4e7f6ffa71665ac136a83/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e6a6f6775616d6f732f6c61726176656c2d7065736170616c2f72756e2d74657374732e796d6c3f6c6f676f3d676974687562266c6162656c3d5465737473)[![GitHub Actions Workflow Status](https://camo.githubusercontent.com/c3cb4952c7967b00fa3f88446d11c4a7ae1a6cc6520c57dbcadc4d87295a9e39/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e6a6f6775616d6f732f6c61726176656c2d7065736170616c2f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6c6f676f3d676974687562266c6162656c3d436f64652532305374796c65)](https://camo.githubusercontent.com/c3cb4952c7967b00fa3f88446d11c4a7ae1a6cc6520c57dbcadc4d87295a9e39/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e6a6f6775616d6f732f6c61726176656c2d7065736170616c2f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6c6f676f3d676974687562266c6162656c3d436f64652532305374796c65)[![GitHub Actions PHPStan Status](https://camo.githubusercontent.com/5aacfb509676b9e640d4c1c1a338c6e3cbb1ea61207045b2d41138812f95e923/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e6a6f6775616d6f732f6c61726176656c2d7065736170616c2f7068707374616e2e796d6c3f6c6f676f3d676974687562266c6162656c3d5048505374616e)](https://camo.githubusercontent.com/5aacfb509676b9e640d4c1c1a338c6e3cbb1ea61207045b2d41138812f95e923/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e6a6f6775616d6f732f6c61726176656c2d7065736170616c2f7068707374616e2e796d6c3f6c6f676f3d676974687562266c6162656c3d5048505374616e)[![Total Downloads](https://camo.githubusercontent.com/a8d7fadee02c9937e66db137e45eaed635eebd212ea595ad0feb79f300394aaf/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6e6a6f6775616d6f732f6c61726176656c2d7065736170616c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/NjoguAmos/laravel-pesapal)

This package provides a way of interacting with Pesapal API. It provides a way of generating `access_token` and storing Instant Payment Notifications (IPNs) in the database. It also provides a way of submitting order requests and checking the status of a transaction.

Why use this package
--------------------

[](#why-use-this-package)

- To provide a way of generating Pesapal api `access_token` which normally expires after 5 minutes
- Offer a gateway to interacting with Pesapal v3 API
- Provide a way of storing Instant Payment Notifications (IPNs) in the database
- Saves you time from writing the same code over and over again

Playground
----------

[](#playground)

If you are looking to test this package, I have created a [playground](https://github.com/njoguamos/laravel-pesapal-playground) where you can test the package without having to create a new Laravel project.

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

[](#installation)

VersionSupported Laravel1.x10.x, 11.x2.x11.x, 12.xYou can install the package via composer:

```
composer require njoguamos/laravel-pesapal
```

This packages comes with the following tables

- `pesapal_tokens` - to store the `access_token` and `expires_at` for the Pesapal API
- `pesapal_ipns` - to store the Instant Payment Notifications

Publish and run the migrations

```
php artisan vendor:publish --tag="pesapal-migrations"
php artisan migrate
```

You can optionally publish the config file

```
php artisan vendor:publish --tag="pesapal-config"
```

Update your environment variables in your application.

```
PESAPAL_LIVE=
PESAPAL_CONSUMER_KEY=
PESAPAL_CONSUMER_SECRET=
```

Usage
-----

[](#usage)

### 1. Generate `access_token`

[](#1-generate-access_token)

To generate an `access_token` you can run the following command:

```
php artisan pesapal:auth
```

The command will get a fresh `access_token` from Pesapal API using the `CONSUMER_KEY` and `CONSUMER_SECRET` and save it in the database. The `access_token` is valid for 5 minutes therefore is wise to schedule the command to run every 4 minutes. In addition, when you have set `model:prune` command, all expired `access_token` will be deleted from the database since they are no longer useful.

```
 # Laravel 10 -> app/Console/Kernel.php

use NjoguAmos\Pesapal\Models\PesapalToken;

class Kernel extends ConsoleKernel
{
    protected function schedule(Schedule $schedule): void
    {
        # Other scheduled commands
        $schedule->command('pesapal:auth')->everyFourMinutes();
        Schedule::command('model:prune', ['--model' => [PesapalToken::class]])->everyFiveMinutes();
    }
}
```

```
 # Laravel 11 -> routes/console.php
use Illuminate\Support\Facades\Schedule;
use NjoguAmos\Pesapal\Models\PesapalToken;

Schedule::command('pesapal:auth')->everyFourMinutes();
Schedule::command('model:prune', ['--model' => [PesapalToken::class]])->everyFiveMinutes();
```

You can also call the `createToken' in `Pesapal`class directly to generate the`access\_token`. The method will return null or an new `PesapalToken` instance.

```
use NjoguAmos\Pesapal\Pesapal;

$token = Pesapal::createToken();
```

The results of `createToken` is an instance of `PesapalToken` Eloquent Model. Which mean you can call Eloquent methods e.g.

```
$data = $token->toArray();
```

```
[
 'access_token' => "eyJhbGciOiJIUzI1NiIs...6pVj1_DS37ghMGQ",
 'expires_at' => Carbon\Carbon instance
]
```

### 2. Create Instant Payment Notification

[](#2-create-instant-payment-notification)

To create an instant payment notification, you can use the `createIpn` method in the `Pesapal` class. The method will return an instance of `PesapalIpn` or null if the request fails.

> **info** Ensure that that your `pesapal_tokens` table as an `access_token` that is not expired.

```
use NjoguAmos\Pesapal\Pesapal;

$ipn = Pesapal::createIpn(
    url: 'https://www.yourapp.com/ipn',
    ipnType: IpnType::GET,
);
```

The results of `createIpn` is an instance of `PesapalIpn` Eloquent Model. Which mean you can call Eloquent methods e.g.

```
$data = $ipn->toArray();
```

```
[
    'url' => 'https://www.yourapp.com/ipn'
    'ipn_id' => 'e32182ca-0983-4fa0-91bc-c3bb813ba750'
    'type' => 'GET'
    'status' => 'Active'
]
```

> **info** The url should be a public url that can be accessed by pesapal.com. The `ipnType` can be either `IpnType::GET` or `IpnType::POST`.

You can go ahead and use the `ipn_id` to submit a Submit Order Requests.

> **info** Ensure that that your `pesapal_tokens` table as an `access_token` that is not expired. Of course, if you scheduled the `pesapal:auth` command, you should not worry about the `access_token` being expired.

### 3. Get Registered IPNs Endpoint

[](#3-get-registered-ipns-endpoint)

There are two ways to get the registered IPNs.

1. You can use the `getIpns` method in the `Pesapal` class to get a IPN from Pesapal API. This method returns an array for successful response or an instance of [Saloon Response](https://docs.saloon.dev/the-basics/responses) for failed response.

```
use NjoguAmos\Pesapal\Pesapal;

$response = Pesapal::getIpns();
```

Sample successful response

```
[
    [
        "url" => "https://www.myapplication.com/ipn",
        "created_date" => "2022-03-03T17:29:03.7208266Z",
        "ipn_id" => "e32182ca-0983-4fa0-91bc-c3bb813ba750",
        "error" => null,
        "status" => "200"
    ],
    [
        "url"=> "https://ipn.myapplication.com/application2",
        "created_date"=> "2021-12-05T04:23:45.5509243Z",
        "ipn_id"=> "c3bb813ba750-0983-4fa0-91bc-e32182ca",
        "error"=> null,
        "status"=> "200"
    ]
]
```

2. or get the IPNs from the database.

```
use NjoguAmos\Pesapal\Models\PesapalIpn;

$ips = PesapalIpn::all();
```

```
[
    [
    "id" => 1
    "url" => "http://kautzer.com/omnis-ut-qui-illo-id-laborum-numquam"
    "ipn_id" => "767e3275-d504-41a0-920a-dd752aafb5ac"
    "type" => 0
    "status" => 1
    "created_at" => "2024-03-18T08:10:32.000000Z"
    "updated_at" => "2024-03-18T05:10:32.000000Z"
  ],
  [
    "id" => 2
    "url" => "http://www.cole.org/qui-fugiat-accusamus-molestiae-aspernatur-sequi-eum-non-quae.html"
    "ipn_id" => "de07604f-c06b-4ccf-9cb5-dd75aaaff99f"
    "type" => 0
    "status" => 1
    "created_at" => "2024-03-18T08:10:33.000000Z"
    "updated_at" => "2024-03-18T05:10:33.000000Z"
  ]
]
```

### 4. Submit Order Request Endpoint

[](#4-submit-order-request-endpoint)

To submit an order request, you can use the `createOrder` method in the `Pesapal` class. You will need to construct a DTO for `PesapalOrderData` and `PesapalAddressData` as shown below. This method returns an array for successful response or an instance of [Saloon Response](https://docs.saloon.dev/the-basics/responses) for failed response.

> **info** You must provide a registered `PesapalIpn`.

```
use NjoguAmos\Pesapal\Enums\ISOCurrencyCode;
use NjoguAmos\Pesapal\Enums\ISOCountryCode;
use NjoguAmos\Pesapal\Enums\RedirectMode;
use NjoguAmos\Pesapal\Pesapal;
use NjoguAmos\Pesapal\DTOs\PesapalOrderData;
use NjoguAmos\Pesapal\DTOs\PesapalAddressData;

$ipnId = PesapalIpn::latest()->first()->ipn_id;

 $orderData = new PesapalOrderData(
    id: fake()->uuid(),
    currency: ISOCurrencyCode::KES,
    amount: fake()->randomFloat(nbMaxDecimals: 2, min: 50, max: 500),
    description: 'Test order',
    callbackUrl: fake()->url(),
    notificationId: $ipnId,
    cancellationUrl: fake()->url(),
    redirectMode: RedirectMode::PARENT_WINDOW,
);

// All fields are optional except either phoneNumber or emailAddress
$billingAddress = new PesapalAddressData(
    phoneNumber: '0700325008',
    emailAddress: 'test@xample.com',
    countryCode: ISOCountryCode::KE
    firstName: 'Amos',
    middleName: 'Njogu'
//    lastName: ''
    line2: "Gil House, Nairobi, Tom Mboya Street",
//    city: "",
//    state: "",
//    postalCode: "",
//    zipCode: "",
);

$order = Pesapal::createOrder(
    orderData: $orderData,
    billingAddress: $billingAddress,
);
```

Sample successful response

```
[
    "order_tracking_id" => "b945e4af-80a5-4ec1-8706-e03f8332fb04",
    "merchant_reference" => "TEST1515111119",
    "redirect_url" => "https://cybqa.pesapal.com/pesapaliframe/PesapalIframe3/Index/?OrderTrackingId=b945e4af-80a5-4ec1-8706-e03f8332fb04",
    "error" => null,
    "status" => "200"
]
```

You can now re-direct the user to the `redirect_url` to complete the payment.

### 5. Get Transaction Status Endpoint

[](#5-get-transaction-status-endpoint)

You can check the status of a transaction using `OrderTrackingId` issued when creating an order. You can do so by using the `getTransactionStatus` method in the `Pesapal` class. This method returns an array for successful response or an instance of [Saloon Response](https://docs.saloon.dev/the-basics/responses) for failed response.

```
use NjoguAmos\Pesapal\Pesapal;

 $transaction = Pesapal::getTransactionStatus(
    orderTrackingId: 'b945e4af-80a5-4ec1-8706-e03f8332fb04',
);

// $transaction either an array or an instance of Saloon Response
```

Sample successful response

```
[
  "payment_method" => "MpesaKE"
  "amount" => 6.0
  "created_date" => "2024-03-19T20:08:46.39"
  "confirmation_code" => "SCJ8JQ26SW"
  "order_tracking_id" => "af2234da-03ee-4b60-b2dd-dd746bcda1bd"
  "payment_status_description" => "Completed"
  "description" => null
  "message" => "Request processed successfully"
  "payment_account" => "2547xxx56689"
  "call_back_url" => "http://127.0.0.1:8000/pesapal-callback?OrderTrackingId=af2234da-03ee-4b60-b2dd-dd746bcda1bd&OrderMerchantReference=1"
  "status_code" => 1
  "merchant_reference" => "1"
  "payment_status_code" => ""
  "currency" => "KES"
  "error" => [
    "error_type" => null
    "code" => null
    "message" => null
  ]
  "status" => "200"
]
```

### 6. Recurring / Subscription Based Payments

[](#6-recurring--subscription-based-payments)

- TODO: Add documentation for recurring payments

### 7. Refund Request

[](#7-refund-request)

- TODO: Add documentation for refund request

### 8. Retrying Requests

[](#8-retrying-requests)

If for some reason, the payment did not complete and you have the order tracking ID, you can retry the payment by redirecting the user to the Pesapal payment page.

```
use NjoguAmos\Pesapal\Pesapal;

$redirectUrl = Pesapal::getRedirectUrl(orderTrackingId: $orderTrackingId);
// https://pay.pesapal.com/iframe/PesapalIframe3/Index?OrderTrackingId=db80f574-a759-40b3-a6ec-dc68ef3dc1e6
```

A note about responses
----------------------

[](#a-note-about-responses)

For flexibility and simplicity, the `Pesapal` static method returns an `array` for successful responses or an instance of `Saloon Response` for failed responses.

Example, when getting the transaction status using `getTransactionStatus` will either return an array of transaction details or an instance of `Saloon Response` if the request was not successful.

```
use NjoguAmos\Pesapal\Pesapal;

 $transaction = Pesapal::getTransactionStatus(
    orderTrackingId: 'b945e4af-80a5-4ec1-8706-e03f8332fb04',
);

if (is_array($transaction)) {
    // The API call was successful and response is an array
    //    [
    //      "payment_method" => "MpesaKE"
    //      "amount" => 6.0
    //      "created_date" => "2024-03-19T20:08:46.39"
    //      "confirmation_code" => "SCJ8JQ26SW"
    //      "....more field"
    //    ]
} else {
    // The API call was not successful. The response is an instance of Saloon Response
    // $transaction->status() ---> response status code.
    // $transaction->headers() ---> Returns all response headers
    // $transaction->getPendingRequest() ---> PendingRequest class that was built up for the request.
}
```

You can learn more about the \[Saloon Response(). You can use the response to diagnose the issue with the request.

Testing
-------

[](#testing)

> **Info** Where possible, the tests uses real [sandbox credentials](https://developer.pesapal.com/api3-demo-keys.txt), and as such the request is not mocked. The resulting response is saved at `tests/Fixtures` and used in future tests. Where it is impossible to use real credentials, the request is mocked. You can recreate the fixtures by deleting `tests/Fixtures` and running the tests.

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Njogu Amos](https://github.com/njoguamos)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

55

—

FairBetter than 98% of packages

Maintenance89

Actively maintained with recent releases

Popularity29

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity73

Established project with proven stability

 Bus Factor1

Top contributor holds 60.5% of commits — single point of failure

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

Every ~13 days

Recently: every ~23 days

Total

56

Last Release

54d ago

Major Versions

v0.0.5 → v1.0-beta.12024-03-18

v1.3.3 → v2.0.02025-03-17

v2.4.67 → v3.0.02026-03-25

PHP version history (4 changes)v0.0.1PHP ^8.1

v0.0.5PHP ^8.1 | ^8.2 | ^8.3

v2.0.0PHP ^8.2 | ^8.3 | ^8.4

v3.0.0PHP ^8.3 | ^8.4 | 8.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/1262b428518ef976f4268074e0b9e9280ec9af765aee553112bea64401beed8f?d=identicon)[njoguamos](/maintainers/njoguamos)

---

Top Contributors

[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (167 commits)")[![njoguamos](https://avatars.githubusercontent.com/u/29255728?v=4)](https://github.com/njoguamos "njoguamos (109 commits)")

---

Tags

laravelpaymentpayment-gatewaypesapallaravelpaymentpesapal

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/njoguamos-laravel-pesapal/health.svg)

```
[![Health](https://phpackages.com/badges/njoguamos-laravel-pesapal/health.svg)](https://phpackages.com/packages/njoguamos-laravel-pesapal)
```

###  Alternatives

[danestves/laravel-polar

A package to easily integrate your Laravel application with Polar.sh

7812.3k](/packages/danestves-laravel-polar)[musahmusah/laravel-multipayment-gateways

A Laravel Package that makes implementation of multiple payment Gateways endpoints and webhooks seamless

852.2k1](/packages/musahmusah-laravel-multipayment-gateways)

PHPackages © 2026

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