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

ActiveLibrary[Payment Processing](/categories/payments)

pawapay/laravel-pawapay
=======================

Laravel package for the PawaPay mobile money payment gateway.

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

Since Jun 11Pushed 1mo agoCompare

[ Source](https://github.com/dream-hun/laravel-pawapay)[ Packagist](https://packagist.org/packages/pawapay/laravel-pawapay)[ RSS](/packages/pawapay-laravel-pawapay/feed)WikiDiscussions main Synced 1w ago

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

Laravel PawaPay
===============

[](#laravel-pawapay)

[![Latest Version on Packagist](https://camo.githubusercontent.com/be18ba10aac6801e8cacc3304618eb80b5378c32f73e6e1b6b63a454d8c09902/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f706177617061792f6c61726176656c2d706177617061792e737667)](https://packagist.org/packages/pawapay/laravel-pawapay)[![PHP Version](https://camo.githubusercontent.com/ef0054230522e542bc1f908ac005c6c75888dea255bac910f9015e12095e31d7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e332d626c7565)](https://php.net)[![Laravel Version](https://camo.githubusercontent.com/6276c3f67b7b539222e2048fb10cae8bb35f60e028eaf1cfa6211e5b864ae58e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d31332e782d726564)](https://laravel.com)[![License](https://camo.githubusercontent.com/074b89bca64d3edc93a1db6c7e3b1636b874540ba91d66367c0e5e354c56d0ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e737667)](LICENSE)

A type-safe Laravel package for the [PawaPay](https://pawapay.io) mobile money payment gateway — enabling deposits, payouts, refunds, and payment pages across African mobile money providers.

---

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

[](#requirements)

- PHP ^8.3
- Laravel 13.x
- A PawaPay API token — get one from the [PawaPay Dashboard](https://dashboard.pawapay.io)

---

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

[](#installation)

```
composer require pawapay/laravel-pawapay
```

The service provider and `PawaPay` facade alias are registered automatically via Laravel's package auto-discovery.

Publish the configuration file:

```
php artisan vendor:publish --tag=pawapay-config
```

---

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

[](#configuration)

Add the following to your `.env` file:

```
PAWAPAY_TOKEN=your-api-token
PAWAPAY_SANDBOX=true
PAWAPAY_TIMEOUT=30
PAWAPAY_WEBHOOK_PATH=/webhooks/pawapay
PAWAPAY_WEBHOOK_SECRET=your-webhook-secret
```

KeyDefaultDescription`PAWAPAY_TOKEN`—Your PawaPay API bearer token (required)`PAWAPAY_SANDBOX``true`Use the sandbox API. Set to `false` for production`PAWAPAY_TIMEOUT``30`HTTP request timeout in seconds`PAWAPAY_WEBHOOK_PATH``/webhooks/pawapay`URL path where PawaPay sends webhook callbacks`PAWAPAY_WEBHOOK_SECRET`—Optional secret for webhook signature verification---

Usage
-----

[](#usage)

All methods are available via the `PawaPay` facade or by injecting `PawaPay\Contracts\PawaPayClientInterface`.

### Deposits

[](#deposits)

Initiate a deposit (customer pays into your account):

```
use PawaPay\Data\DepositData;
use PawaPay\Facades\PawaPay;

$data = new DepositData(
    depositId: (string) Str::uuid(),   // unique ID you generate
    phoneNumber: '260971234567',        // customer's MSISDN
    provider: 'MTN_MOMO_ZMB',          // mobile money provider code
    amount: '100.00',
    currency: 'ZMW',
    customerMessage: 'Payment for order #1234',  // optional
    clientReferenceId: 'order-1234',             // optional, your internal reference
    metadata: [                                   // optional
        ['fieldName' => 'orderId', 'fieldValue' => '1234'],
        ['fieldName' => 'email', 'fieldValue' => 'user@example.com', 'isPII' => true],
    ],
);

$response = PawaPay::initiateDeposit($data);

if ($response->isAccepted()) {
    // Transaction accepted — poll for final status
    $status = PawaPay::getDeposit($response->depositId);

    if ($status->isCompleted()) {
        // Payment confirmed
        echo $status->providerTransactionId;
    }
}
```

**DepositData fields:**

FieldTypeRequiredDescription`depositId``string`YesUnique identifier for this deposit (UUID recommended)`phoneNumber``string`YesCustomer's phone number (MSISDN format)`provider``string`YesProvider code, e.g. `MTN_MOMO_ZMB``amount``string`YesTransaction amount`currency``string`YesISO 4217 currency code, e.g. `ZMW``customerMessage``?string`NoMessage shown to the customer`clientReferenceId``?string`NoYour internal reference ID`preAuthorisationCode``?string`NoPre-authorisation code, if applicable`metadata``array`NoCustom metadata fields (see [Metadata](#metadata))**Available methods:**

```
PawaPay::initiateDeposit(DepositData $data): DepositResponse
PawaPay::getDeposit(string $depositId): DepositResponse
PawaPay::resendDepositCallback(string $depositId): array
```

---

### Payouts

[](#payouts)

Send money out to a recipient:

```
use PawaPay\Data\PayoutData;
use PawaPay\Facades\PawaPay;

$data = new PayoutData(
    payoutId: (string) Str::uuid(),
    phoneNumber: '260971234567',
    provider: 'MTN_MOMO_ZMB',
    amount: '50.00',
    currency: 'ZMW',
    customerMessage: 'Your withdrawal',  // optional
    clientReferenceId: 'withdrawal-567', // optional
);

$response = PawaPay::initiatePayout($data);

if ($response->isAccepted()) {
    $status = PawaPay::getPayout($response->payoutId);

    if ($status->isCompleted()) {
        echo 'Payout sent: ' . $status->providerTransactionId;
    }
}
```

**PayoutData fields:**

FieldTypeRequiredDescription`payoutId``string`YesUnique identifier for this payout`phoneNumber``string`YesRecipient's phone number (MSISDN format)`provider``string`YesProvider code`amount``string`YesTransaction amount`currency``string`YesISO 4217 currency code`customerMessage``?string`NoMessage shown to the recipient`clientReferenceId``?string`NoYour internal reference ID`metadata``array`NoCustom metadata fields**Available methods:**

```
PawaPay::initiatePayout(PayoutData $data): PayoutResponse
PawaPay::getPayout(string $payoutId): PayoutResponse
PawaPay::resendPayoutCallback(string $payoutId): array
```

---

### Refunds

[](#refunds)

Refund a previously completed deposit:

```
use PawaPay\Data\RefundData;
use PawaPay\Facades\PawaPay;

$data = new RefundData(
    refundId: (string) Str::uuid(),
    depositId: 'f4401bd2-1568-4140-bf2d-eb77d2b2b639',  // original deposit ID
    amount: '100.00',
    currency: 'ZMW',
    clientReferenceId: 'refund-for-order-1234',  // optional
);

$response = PawaPay::initiateRefund($data);

if ($response->isAccepted()) {
    $status = PawaPay::getRefund($response->refundId);

    if ($status->isCompleted()) {
        echo 'Refund processed';
    } elseif ($status->isFailed()) {
        echo 'Refund failed: ' . $status->failureMessage;
    }
}
```

**RefundData fields:**

FieldTypeRequiredDescription`refundId``string`YesUnique identifier for this refund`depositId``string`YesThe original deposit ID to refund`amount``string`YesAmount to refund`currency``string`YesISO 4217 currency code`clientReferenceId``?string`NoYour internal reference ID`metadata``array`NoCustom metadata fields**Available methods:**

```
PawaPay::initiateRefund(RefundData $data): RefundResponse
PawaPay::getRefund(string $refundId): RefundResponse
```

---

### Payment Pages

[](#payment-pages)

Create a hosted payment page where customers complete the payment in their browser:

```
use PawaPay\Data\PaymentPageData;
use PawaPay\Facades\PawaPay;

$data = new PaymentPageData(
    depositId: (string) Str::uuid(),
    returnUrl: 'https://yourapp.com/payment/return',
    phoneNumber: '260971234567',   // optional, pre-fills the form
    amount: '100.00',              // optional
    currency: 'ZMW',               // optional
    country: 'ZMB',                // optional, ISO 3166-1 alpha-3
    reason: 'Order payment',       // optional
    language: 'en',                // optional
    customerMessage: 'Thank you',  // optional
);

$page = PawaPay::createPaymentPage($data);
// $page contains the payment page URL and details from PawaPay
```

**Available methods:**

```
PawaPay::createPaymentPage(PaymentPageData $data): array
```

---

### Active Configuration

[](#active-configuration)

Retrieve the providers available for your account, optionally filtered by country or operation type:

```
use PawaPay\Facades\PawaPay;

$config = PawaPay::getActiveConfiguration();

echo $config->companyName;
echo $config->signatureRequired ? 'Signatures required' : 'No signatures needed';

// Filter providers by country (ISO 3166-1 alpha-3)
$zambiaProviders = $config->providersForCountry('ZMB');

// Filter by operation type
$depositProviders = $config->providersForOperationType('DEPOSIT');

// Or pass filters directly to the API call
$config = PawaPay::getActiveConfiguration(country: 'ZMB', operationType: 'DEPOSIT');
```

---

### Response Helper Methods

[](#response-helper-methods)

All transaction responses (`DepositResponse`, `PayoutResponse`, `RefundResponse`) share these helper methods:

```
$response->isAccepted()   // status === ACCEPTED (transaction is being processed)
$response->isCompleted()  // status === COMPLETED (transaction succeeded)
$response->isFailed()     // status === FAILED or REJECTED
$response->isDuplicate()  // status === DUPLICATE_IGNORED (same ID submitted twice)
```

When a transaction fails, additional details are available:

```
$response->failureCode;    // FailureCode enum, e.g. FailureCode::InvalidPhoneNumber
$response->failureMessage; // Human-readable failure description
```

---

### Metadata

[](#metadata)

All transaction data classes accept an optional `metadata` array for passing custom fields alongside a transaction. Fields marked `isPII` are treated as personally identifiable information by PawaPay.

```
$metadata = [
    ['fieldName' => 'orderId',    'fieldValue' => '1234'],
    ['fieldName' => 'customerEmail', 'fieldValue' => 'user@example.com', 'isPII' => true],
];
```

---

Webhooks
--------

[](#webhooks)

PawaPay sends real-time status updates to your application via HTTP callbacks. This package registers the webhook route automatically — no manual route registration is needed.

**Default endpoint:** `POST /webhooks/pawapay`

You can change the path via `PAWAPAY_WEBHOOK_PATH` in your `.env`.

### Signature Verification

[](#signature-verification)

When `PAWAPAY_WEBHOOK_SECRET` is set, the package verifies the `Content-Digest` header of every incoming webhook request using SHA-256 or SHA-512. Requests that fail verification are rejected.

If no secret is configured, signature verification is skipped and all incoming requests to the webhook endpoint are accepted.

---

Events
------

[](#events)

When a webhook is received, the package dispatches a Laravel event based on the transaction type. Listen to these events to react to transaction status changes.

EventPropertiesTriggered by`PawaPay\Events\DepositStatusUpdated``$depositId`, `$status`, `$payload`Deposit callbacks`PawaPay\Events\PayoutStatusUpdated``$payoutId`, `$status`, `$payload`Payout callbacks`PawaPay\Events\RefundStatusUpdated``$refundId`, `$status`, `$payload`Refund callbacksThe `$status` property is a `TransactionStatus` enum. The `$payload` array contains the full raw webhook body.

Register your listeners in `AppServiceProvider` or a dedicated `EventServiceProvider`:

```
use Illuminate\Support\Facades\Event;
use PawaPay\Events\DepositStatusUpdated;
use PawaPay\Enums\TransactionStatus;

Event::listen(DepositStatusUpdated::class, function (DepositStatusUpdated $event) {
    if ($event->status === TransactionStatus::Completed) {
        // Mark the order as paid
        Order::where('deposit_id', $event->depositId)->update(['paid' => true]);
    }

    if ($event->status->isFinal() && $event->status !== TransactionStatus::Completed) {
        // Handle failure — notify the customer, release reserved stock, etc.
    }
});
```

---

Error Handling
--------------

[](#error-handling)

ExceptionWhen thrown`PawaPay\Exceptions\AuthenticationException`HTTP 401 — invalid or missing API token`PawaPay\Exceptions\ApiException`Any other non-2xx API response`PawaPay\Exceptions\PawaPayException`Base class; also thrown on webhook signature failureAll exceptions expose a `$response` property with the raw `Illuminate\Http\Client\Response` object for inspection.

```
use PawaPay\Exceptions\AuthenticationException;
use PawaPay\Exceptions\ApiException;
use PawaPay\Exceptions\PawaPayException;
use PawaPay\Facades\PawaPay;

try {
    $response = PawaPay::initiateDeposit($data);
} catch (AuthenticationException $e) {
    // Invalid token — check PAWAPAY_TOKEN in your .env
    logger()->error('PawaPay auth failed', ['body' => $e->response->body()]);
} catch (ApiException $e) {
    // Non-2xx response from PawaPay API
    logger()->error('PawaPay API error', [
        'status' => $e->response->status(),
        'body'   => $e->response->body(),
    ]);
} catch (PawaPayException $e) {
    // Catch-all for any other PawaPay error
    logger()->error('PawaPay error: ' . $e->getMessage());
}
```

---

Enums Reference
---------------

[](#enums-reference)

### `TransactionStatus`

[](#transactionstatus)

CaseValueDescription`Accepted``ACCEPTED`Transaction received and accepted`Enqueued``ENQUEUED`Queued for processing`Processing``PROCESSING`Currently being processed`InReconciliation``IN_RECONCILIATION`Under reconciliation`Completed``COMPLETED`Successfully completed`Failed``FAILED`Transaction failed`Rejected``REJECTED`Rejected by the provider`DuplicateIgnored``DUPLICATE_IGNORED`Duplicate transaction ID```
$status->isFinal();      // true for Completed, Failed, Rejected
$status->isSuccessful(); // true only for Completed
```

### `OperationType`

[](#operationtype)

CaseValue`Deposit``DEPOSIT``Payout``PAYOUT``Refund``REFUND``Remittance``REMITTANCE``PushDeposit``PUSH_DEPOSIT``NameLookup``NAME_LOOKUP`### `FailureCode`

[](#failurecode)

**Authentication &amp; Authorization**

CodeDescription`NO_AUTHENTICATION`No authentication token provided`AUTHENTICATION_ERROR`Token is invalid or expired`AUTHORISATION_ERROR`Insufficient permissions`HTTP_SIGNATURE_ERROR`HTTP signature verification failed**Feature Restrictions**

CodeDescription`DEPOSITS_NOT_ALLOWED`Deposits not enabled for this account`PAYOUTS_NOT_ALLOWED`Payouts not enabled for this account`REFUNDS_NOT_ALLOWED`Refunds not enabled for this account**Input Validation**

CodeDescription`INVALID_INPUT`General invalid input`MISSING_PARAMETER`Required parameter is missing`UNSUPPORTED_PARAMETER`Parameter is not supported`INVALID_PARAMETER`Parameter value is invalid`DUPLICATE_METADATA_FIELD`Duplicate field names in metadata**Business Logic**

CodeDescription`INVALID_PHONE_NUMBER`Phone number is not valid for this provider`INVALID_AMOUNT`Amount is invalid`AMOUNT_OUT_OF_BOUNDS`Amount exceeds provider limits`INVALID_CURRENCY`Currency is not supported`INVALID_PROVIDER`Provider code is unrecognised`PROVIDER_TEMPORARILY_UNAVAILABLE`Provider is down or unreachable`PAWAPAY_WALLET_OUT_OF_FUNDS`Insufficient funds in your PawaPay wallet`NOT_FOUND`Transaction ID not found`INVALID_STATE`Transaction is not in a state that allows this operation**System**

CodeDescription`UNKNOWN_ERROR`Unexpected error on PawaPay's side---

Testing
-------

[](#testing)

The package uses Laravel's `Http::fake()` for testing — no real API calls are made. See [`tests/Feature/`](tests/Feature/) for complete examples covering deposits, payouts, refunds, active configuration, and webhook handling.

---

License
-------

[](#license)

The MIT License (MIT).

```
MIT License

Copyright (c) 2026 PawaPay

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

```

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance90

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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

Unknown

Total

1

Last Release

46d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/40598991?v=4)[zaiyi](/maintainers/DreamChaser)[@DreamChaser](https://github.com/DreamChaser)

---

Top Contributors

[![dream-hun](https://avatars.githubusercontent.com/u/71966425?v=4)](https://github.com/dream-hun "dream-hun (3 commits)")

### Embed Badge

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

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

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)

PHPackages © 2026

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