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

Abandoned → [damms005/laravel-multipay](/?search=damms005%2Flaravel-multipay)Library[Payment Processing](/categories/payments)

damms005/laravel-cashier
========================

An opinionated, easily extendable and configurable package for handling payments in Laravel

v7.2.6(1mo ago)27894[1 issues](https://github.com/damms005/laravel-multipay/issues)[2 PRs](https://github.com/damms005/laravel-multipay/pulls)MITPHPPHP ^8.1CI passing

Since Sep 25Pushed 2w ago3 watchersCompare

[ Source](https://github.com/damms005/laravel-multipay)[ Packagist](https://packagist.org/packages/damms005/laravel-cashier)[ Docs](https://github.com/damms005/laravel-multipay)[ GitHub Sponsors](https://github.com/damms005)[ RSS](/packages/damms005-laravel-cashier/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (33)Versions (169)Used By (0)

Laravel Multipay 💸
==================

[](#laravel-multipay-)

[![Art image for laravel-multipay](https://camo.githubusercontent.com/dff3655b184ea9b9735e89330ac7fb7ed474bbb1d712ba6877856681bfd73692/68747470733a2f2f62616e6e6572732e6265796f6e64636f2e64652f4c61726176656c2532304d756c74697061792e706e673f7468656d653d6c69676874267061636b6167654d616e616765723d636f6d706f7365722b72657175697265267061636b6167654e616d653d64616d6d733030352532466c61726176656c2d6d756c7469706179267061747465726e3d676c616d6f726f7573267374796c653d7374796c655f31266465736372697074696f6e3d416e2b6f70696e696f6e617465642b4c61726176656c2b7061636b6167652b666f722b68616e646c696e672b7061796d656e74732532432b636f6d706c6574652b776974682b626c6164652b7669657773266d643d312673686f7757617465726d61726b3d3126666f6e7453697a653d313030707826696d616765733d63617368267769647468733d333530)](https://camo.githubusercontent.com/dff3655b184ea9b9735e89330ac7fb7ed474bbb1d712ba6877856681bfd73692/68747470733a2f2f62616e6e6572732e6265796f6e64636f2e64652f4c61726176656c2532304d756c74697061792e706e673f7468656d653d6c69676874267061636b6167654d616e616765723d636f6d706f7365722b72657175697265267061636b6167654e616d653d64616d6d733030352532466c61726176656c2d6d756c7469706179267061747465726e3d676c616d6f726f7573267374796c653d7374796c655f31266465736372697074696f6e3d416e2b6f70696e696f6e617465642b4c61726176656c2b7061636b6167652b666f722b68616e646c696e672b7061796d656e74732532432b636f6d706c6574652b776974682b626c6164652b7669657773266d643d312673686f7757617465726d61726b3d3126666f6e7453697a653d313030707826696d616765733d63617368267769647468733d333530)

[![GitHub](https://camo.githubusercontent.com/52ba493bfa6198390369be014f483b8c5a5b9d669a1ee03576b8f2794822abe5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f64616d6d733030352f6c61726176656c2d6d756c7469706179)](https://camo.githubusercontent.com/52ba493bfa6198390369be014f483b8c5a5b9d669a1ee03576b8f2794822abe5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f64616d6d733030352f6c61726176656c2d6d756c7469706179)[![GitHub tag (with filter)](https://camo.githubusercontent.com/ec494ffbc31d89f371a7414450143efd173859d8560d09915a8f69f61c2570c0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f64616d6d733030352f6c61726176656c2d6d756c7469706179)](https://camo.githubusercontent.com/ec494ffbc31d89f371a7414450143efd173859d8560d09915a8f69f61c2570c0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f64616d6d733030352f6c61726176656c2d6d756c7469706179)[![Total Downloads](https://camo.githubusercontent.com/ffccd5e0291914267d80019f56e49cdecae9f571ee60975eeec6df14413790de/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f64616d6d733030352f6c61726176656c2d6d756c74697061792e737667)](https://packagist.org/packages/damms005/laravel-multipay)[![GitHub Workflow Status (with event)](https://camo.githubusercontent.com/42a3dac2e00c28768bf7b1b016699af346eea4e16d01be18c16ff4a8fb721338/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f64616d6d733030352f6c61726176656c2d6d756c74697061792f72756e2d74657374732e796d6c)](https://camo.githubusercontent.com/42a3dac2e00c28768bf7b1b016699af346eea4e16d01be18c16ff4a8fb721338/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f64616d6d733030352f6c61726176656c2d6d756c74697061792f72756e2d74657374732e796d6c)

An opinionated Laravel package to handle payments, complete with blade views, routing, and everything in-between.

Whether you want to quickly bootstrap payment processing for your Laravel applications, or you want a way to test supported payment processors, this package's got you!

> Although opinionated, this package allows you to "theme" the views. It achieves this theming by `@extend()`ing whatever view you specify in `config('laravel-multipay.extended_layout')` (defaults to `layout.app`).

Requirements:
-------------

[](#requirements)

This package is [tested against:](https://github.com/damms005/laravel-multipay/blob/d1a15bf762ba2adabc97714f1565c6c0f0fcd58d/.github/workflows/run-tests.yml#L16-17)

- PHP ^8.2
- Laravel 11/12

Currently supported payment handlers
------------------------------------

[](#currently-supported-payment-handlers)

Currently, this package supports the following online payment processors/handlers

- [Paystack](https://paystack.com)
- [Remita](http://remita.net)
- [Flutterwave](https://flutterwave.com)\*\*
- [Interswitch](https://www.interswitchgroup.com)\*\*
- [UnifiedPayments](https://unifiedpayments.com)\*\*

Note

*key*: \*\* for the indicated providers, a few features may be missing. PRs welcomed if you cannot afford the wait 😉

Tip

Your preferred payment handler is not yet supported? Please consider [opening the appropriate issue type](https://github.com/damms005/laravel-multipay/issues/new?assignees=&labels=&template=addition-of-new-payment-handler.md&title=Addition+of+new+payment+handler+-+%5Bpayment+handler+name+here%5D).

Tip

Adding a new payment handler is straight-forward. Simply add a class that extends `Damms005\LaravelMultipay\Services\PaymentHandlers\BasePaymentHandler` and implement `Damms005\LaravelMultipay\Contracts\PaymentHandlerInterface`

Note

Payment providers that you so register as described above are resolvable from the [Laravel Container](https://laravel.com/docs/9.x/container) to improve the flexibility of this package and improve DX.

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

[](#installation)

```
composer require damms005/laravel-multipay
```

### Publish the config file.

[](#publish-the-config-file)

```
php artisan vendor:publish --tag=laravel-multipay-config
```

### Run migrations.

[](#run-migrations)

```
php artisan migrate
```

#### Demo Repo

[](#demo-repo)

I [published an open source app](https://github.com/damms005/nft-marketplace) that uses this payment package. It is also an excellent example of a Laravel app that uses [Laravel Vite](https://laravel.com/docs/9.x/vite#main-content) and leverages on [Laravel Echo](https://laravel.com/docs/9.x/broadcasting#client-side-installation) to provide realtime experience via public and private channels using [Laravel Websocket](https://beyondco.de/docs/laravel-websockets), powered by [Livewire](https://laravel-livewire.com/docs).

### Test drive 🚀

[](#test-drive-)

Want to take things for a spin? Visit `/payment/test-drive` (`route('payment.test-drive')` provided by this package) . For [Paystack](https://paystack.com), ensure to set `paystack_secret_key` key in the `laravel-multipay.php` config file that you published previously at installation. You can get your key from your [settings page](https://dashboard.paystack.co/#/settings/developer).

> **Warning**
> Ensure you have [TailwindCSS installed](https://tailwindcss.com/docs/installation), then add this package's views to the `content` key of your `tailwind.config.js` configuration file, like below:

```
    content: [
        ...,
        './vendor/damms005/laravel-multipay/views/**/*.blade.php',
    ],
    ...
```

### Needed Third-party Integrations:

[](#needed-third-party-integrations)

- Flutterwave: If you want to use Flutterwave, ensure to get your API details [from the dashboard](https://dashboard.flutterwave.com/dashboard/settings/apis), and use it to set the following variables in your `.env` file:

```
FLW_PUBLIC_KEY=FLWPUBK-xxxxxxxxxxxxxxxxxxxxx-X
FLW_SECRET_KEY=FLWSECK-xxxxxxxxxxxxxxxxxxxxx-X
FLW_SECRET_HASH=hash-123xxxxxxxxxxxxxxxxxxx-X
```

- Paystack: Paystack requires a secret key. Go to [the Paystack dashboard](https://dashboard.paystack.co/#/settings/developer) to obtain one, and use it to set the following variable:

```
PAYSTACK_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxx
PAYSTACK_TERMINAL_ID=xxxxxxxxxxxxxxxxxxxxx
```

> The `PAYSTACK_TERMINAL_ID` is only required if you intend to use [Paystack Terminal](https://paystack.com/terminal/) for payment processing.

- Remita: Ensure to set the following environment variables:

```
REMITA_MERCHANT_ID=xxxxxxxxxxxxxxxxxxxxx
REMITA_API_KEY=xxxxxxxxxxxxxxxxxxxxx
```

> For most of the above environment variables, you should rather use the (published) config file to set the corresponding values.

Usage
-----

[](#usage)

### Typical process-flow

[](#typical-process-flow)

#### Step 1

[](#step-1)

Send a `POST` request to `/payment/details/confirm` (`route('payment.show_transaction_details_for_user_confirmation')` provided by this package).

Check the [InitiatePaymentRequest](src/Http/Requests/InitiatePaymentRequest.php#L28) form request class to know the values you are to post to this endpoint. (tip: you can also check [test-drive/pay.blade.php](views/test-drive/pay.blade.php)).

This `POST` request will typically be made by submitting a form from your frontend to the route described above.

Note

if you need to store additional/contextual data with this payment, you can include such data in the request, in a field named `metadata`. The value must be a valid JSON string.

#### Step 2

[](#step-2)

Upon user confirmation of transaction, user is redirected to the appropriate payment handler's gateway.

#### Step 3

[](#step-3)

When user is done with the transaction on the payment handler's end (either successfully paid, or declined transaction), user is redirected back to `/payment/completed` (`route('payment.finished.callback_url')` provided by this package) .

### Metadata Usage

[](#metadata-usage)

In the payment initiation request in [Step 1](#step-1), you can provide a `metadata` field. This field is stored in the `metadata` column of the `payments` table, and available as `AsArrayObject::class` property of the `Payment` model and it provides powerful customization options for individual payments.

The metadata should be a valid JSON string containing key-value pairs that modify payment behavior.

#### Available Metadata Keys

[](#available-metadata-keys)

**`completion_url`**

- After successful payment, the user will be redirected to the URL specified by this key instead of the default payment completion page
- When user is redirected to the specified URL, the transaction reference will be included as `transaction_reference` in the URL query string

**`payment_processor`**

- Use this key to dynamically set the payment handler for the specific transaction
- Valid values are any of [the providers listed above](#currently-supported-payment-handlers)
- This will override the default payment processor configuration

**`split_code`** (Paystack only)

- When using Paystack, you can use this key to specify a split code to process the transaction as a [Paystack Multi-split Transaction](https://paystack.com/docs/payments/multi-split-payments)
- This feature is only available when using Paystack as the payment handler

**`additional_payment_payload`** (Paystack only)

- When using Paystack, you can use this key to specify additional parameters for transaction initialization. For example, you can set `channels` to restrict payment methods: `{ "channels": ["card", "bank", "ussd", "qr", "mobile_money"] }`
- See [Paystack transaction initialization documentation](https://paystack.com/docs/api/transaction/#initialize) for all available parameters
- This feature is only available when using Paystack as the payment handler

Subscriptions (Recurring Payments)
----------------------------------

[](#subscriptions-recurring-payments)

This package provides built-in support for subscription-based recurring payments via the `SubscriptionService` class.

### Supported Handlers

[](#supported-handlers)

HandlerCreate planSubscribePause / Cancel / ResumePaystack✅✅✅Flutterwave✅✅—Pause/cancel/resume requires the handler to implement the `ManagesSubscriptions` contract. Only Paystack does today; calling the management methods with an unsupported handler throws a `SubscriptionManagementException`.

### Creating a Payment Plan

[](#creating-a-payment-plan)

Before subscribing users, create a payment plan:

```
use Damms005\LaravelMultipay\Services\SubscriptionService;
use Damms005\LaravelMultipay\Contracts\PaymentHandlerInterface;

$handler = app(PaymentHandlerInterface::class);

$plan = SubscriptionService::createPaymentPlan(
    handler: $handler,
    name: 'Pro Monthly',
    amount: '5000',        // in minor currency unit (e.g., kobo, cents)
    interval: 'monthly',   // 'monthly', 'quarterly', 'biannually', or 'yearly'
    description: 'Pro plan - billed monthly',
    currency: 'NGN'
);
```

This registers the plan with the payment provider and stores it locally in the `payment_plans` table.

If a plan with the same amount, interval, and currency already exists for the handler, use `findOrCreatePaymentPlan` to avoid duplicates:

```
$plan = SubscriptionService::findOrCreatePaymentPlan(
    handler: $handler,
    amount: '5000',
    interval: 'monthly',
    description: 'Pro plan - billed monthly',
    currency: 'NGN'
);
```

### Subscribing a User to a Plan

[](#subscribing-a-user-to-a-plan)

```
use Damms005\LaravelMultipay\Services\SubscriptionService;
use Damms005\LaravelMultipay\Contracts\PaymentHandlerInterface;

$handler = app(PaymentHandlerInterface::class);

return SubscriptionService::subscribeToPlan(
    handler: $handler,
    user: $user,
    plan: $plan,
    completionUrl: route('dashboard')
);
```

This redirects the user to the payment gateway. Upon successful payment, a `Subscription` record is created automatically with the appropriate `next_payment_due_date`.

You can optionally provide a custom transaction reference and additional metadata:

```
return SubscriptionService::subscribeToPlan(
    handler: $handler,
    user: $user,
    plan: $plan,
    completionUrl: route('dashboard'),
    transactionReference: 'MY-CUSTOM-REF-001',
    metadata: ['order_id' => 123],
    displayAmount: '50.00'  // human-readable amount (e.g., naira) — defaults to plan amount if omitted
);
```

### Checking Active Subscriptions

[](#checking-active-subscriptions)

```
use Damms005\LaravelMultipay\Services\SubscriptionService;

$subscription = SubscriptionService::getActiveSubscriptionFor($user, $plan);

if ($subscription) {
    // User has an active subscription
    // $subscription->next_payment_due_date
}
```

A subscription is considered active if its `status` is `active` **and** its `next_payment_due_date` is in the future. Paused and cancelled subscriptions are excluded.

### Managing Subscriptions (Pause, Cancel, Resume)

[](#managing-subscriptions-pause-cancel-resume)

Subscriptions can be paused (temporarily suspended, intended to be resumed later), cancelled (permanently stopped), or resumed. Under the hood, both pause and cancel call the provider's "disable" endpoint so the subscription stops renewing; the difference between them is intent, tracked locally via the `status` column. Resume calls the provider's "enable" endpoint.

> **Provider note (Paystack):** Paystack has no native "pause". Disabling a subscription stops it from renewing on its next payment date (you'll receive a `subscription.not_renew` event immediately, then `subscription.disable` on the would-be charge date). You **cannot** shift the next payment date by an arbitrary number of days — a pause effectively skips the upcoming renewal. Re-enabling before the next payment date keeps billing uninterrupted; re-enabling after the period lapses starts a fresh cycle.

#### Capturing the provider's subscription code and token

[](#capturing-the-providers-subscription-code-and-token)

To manage a subscription you need the provider's **subscription code** and **email token**. For Paystack these are delivered on the `subscription.create` webhook (`data.subscription_code` and `data.email_token`) shortly after the first successful charge on a plan. Persist them onto the local `Subscription` with `recordProviderSubscriptionData()`:

```
use Damms005\LaravelMultipay\Services\SubscriptionService;

// inside your subscription.create webhook handling
SubscriptionService::recordProviderSubscriptionData(
    $subscription,
    subscriptionCode: $request->input('data.subscription_code'),
    emailToken: $request->input('data.email_token'),
);
```

If you did not capture them at creation time, you can retrieve them from the provider (Paystack) via the handler:

```
$details = $handler->getSubscriptionDetails('SUB_xxxxxxxx');
// ['subscription_code' => ..., 'email_token' => ..., 'status' => ..., 'next_payment_date' => ...]
```

#### Pause, cancel, resume

[](#pause-cancel-resume)

```
use Damms005\LaravelMultipay\Services\SubscriptionService;
use Damms005\LaravelMultipay\Contracts\PaymentHandlerInterface;

$handler = app(PaymentHandlerInterface::class); // must implement ManagesSubscriptions (Paystack does)

// Pause — subscription stops renewing, status becomes "paused"
SubscriptionService::pauseSubscription($handler, $subscription);

// Resume — only valid for a paused subscription, status becomes "active"
SubscriptionService::resumeSubscription($handler, $subscription);

// Cancel — subscription stops renewing permanently, status becomes "cancelled"
SubscriptionService::cancelSubscription($handler, $subscription);
```

Each method calls the provider, updates the local `status`, and returns the refreshed `Subscription`. They throw `SubscriptionManagementException` when:

- the handler does not implement `ManagesSubscriptions`,
- the subscription is missing its provider subscription code or email token, or
- you attempt to resume a subscription that is not paused.

Provider-side failures (e.g. an invalid subscription code) bubble up as an `Exception` carrying the provider's message.

### Models

[](#models)

**`PaymentPlan`** — represents a recurring billing plan:

ColumnDescription`name`Unique plan name`amount`Billing amount`interval``monthly` or `yearly``description`Human-readable description`currency`Currency code (e.g., NGN)`payment_handler_fqcn`Payment handler class name`payment_handler_plan_id`Plan ID from the payment provider**`Subscription`** — represents a user's subscription to a plan:

ColumnDescription`user_id`The subscribed user`payment_plan_id`FK to `payment_plans``next_payment_due_date`When the next payment is due`metadata`Optional JSON metadata`payment_handler_subscription_code`Provider's subscription code (required to manage it)`payment_handler_email_token`Provider's email token (required to manage it)`status``active`, `paused`, or `cancelled`On successful payment, `SuccessfulLaravelMultipayPaymentEvent` is fired — listen for this to run any domain-specific logic.

Payment Conflict Resolution (PCR)
---------------------------------

[](#payment-conflict-resolution-pcr)

If for any reason, your user/customer claims that the payment they made was successful but that your platform did not reflect such successful payment, this PCR feature enables you to resolve such claims by simply calling:

```
/**
 * @var Damms005\LaravelMultipay\ValueObjects\ReQuery $outcome
 */
$outcome = LaravelMultipay::reQueryUnsuccessfulPayment($payment)
```

The payment will be re-resolved and the payment will be updated in the database. If the payment is successful, the `SuccessfulLaravelMultipayPaymentEvent` event will be fired, so you can run any domain/application-specific procedures.

WebHooks Payment Notifications (optional)
-----------------------------------------

[](#webhooks-payment-notifications-optional)

One of the benefits of this package is to remove the need for you to have to deal with payment webhooks. Depending on your needs, the event handling may suffice for your use case.

If you need webhook notifications from payment providers, use the webhook endpoint provided by this package: `route('payment.external-webhook-endpoint')`.

> If you use this payment notification URL feature, ensure that in the handler for `SuccessfulLaravelMultipayPaymentEvent`, you have not previously handled the event for that same payment.

Events
------

[](#events)

### SuccessfulLaravelMultipayPaymentEvent

[](#successfullaravelmultipaypaymentevent)

If there are additional steps you want to take upon successful payment, listen for `SuccessfulLaravelMultipayPaymentEvent`. This event will be fired whenever a successful payment occurs, with its corresponding `Payment` model.

Paystack Terminal
-----------------

[](#paystack-terminal)

[Paystack Terminal](https://paystack.com/terminal/) allows you to process payments on physical payment terminals. This feature is useful for point-of-sale (POS) systems and retail environments.

### Prerequisites

[](#prerequisites)

1. Ensure you have `PAYSTACK_SECRET_KEY` configured in your `.env` file
2. Obtain your Terminal ID from [Paystack Dashboard](https://dashboard.paystack.co/#/settings/terminals)
3. Set the `PAYSTACK_TERMINAL_ID` in your `.env` file:

```
PAYSTACK_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxx
PAYSTACK_TERMINAL_ID=xxxxxxxxxxxxxxxxxxxxx
```

Alternatively, you can set the Terminal ID dynamically in your session:

```
session(['multipay::paystack_terminal_id' => 'your_terminal_id']);
```

### Usage

[](#usage-1)

The Paystack Terminal functionality is provided via the `Terminal` class:

```
use Damms005\LaravelMultipay\Services\PaymentHandlers\PaystackTerminal\Terminal;

$terminal = app(Terminal::class);
```

### Creating a Payment Request

[](#creating-a-payment-request)

Create a payment request that can be pushed to a terminal:

```
$payment = $terminal->createPaymentRequest(
    model: 'App\Models\User',
    modelId: 123,
    email: 'customer@example.com',
    description: 'Product purchase',
    amount: 50000  // Amount in kobo (50,000 kobo = 500 NGN)
);
```

This creates a payment record and returns a `Payment` model instance with the payment details stored in metadata.

### Checking Terminal Status

[](#checking-terminal-status)

Verify that the terminal hardware is online and ready before pushing payments:

```
try {
    $status = $terminal->waitForTerminalHardware();
    // Terminal is online
} catch (\Exception $e) {
    // Terminal is offline or not configured
}
```

### Pushing Payment to Terminal

[](#pushing-payment-to-terminal)

Send a payment request to the terminal for processing:

```
try {
    $eventId = $terminal->pushToTerminal($payment);
    // Payment has been pushed to terminal
} catch (\Exception $e) {
    // Failed to push to terminal
}
```

The returned `$eventId` can be used to track the payment request delivery status.

### Verifying Terminal Receipt

[](#verifying-terminal-receipt)

Confirm that the terminal received the payment request (within 48 hours of creation):

```
try {
    $result = $terminal->terminalReceivedPaymentRequest($eventId);
    // Terminal has received the payment request
} catch (\Exception $e) {
    // Could not verify receipt
}
```

### Error Handling

[](#error-handling)

The Terminal class throws `\Exception` on failures. Common scenarios include:

- Terminal ID not configured
- Terminal hardware offline
- Invalid payment request data
- Network errors communicating with Paystack API

Always wrap Terminal method calls in try-catch blocks for proper error handling.

Webhook Push Notifications
--------------------------

[](#webhook-push-notifications)

When a payment succeeds, this package can automatically send a webhook to an external system (e.g. a financial tracking service). This uses [spatie/laravel-webhook-server](https://github.com/spatie/laravel-webhook-server) under the hood.

### Setup

[](#setup)

1. Install the webhook server package:

```
composer require spatie/laravel-webhook-server
```

2. Set the webhook URL and signing secret in your `.env`:

```
LARAVEL_MULTIPAY_WEBHOOK_URL=https://your-receiving-app.com/api/webhooks/payments
LARAVEL_MULTIPAY_WEBHOOK_SIGNING_SECRET=your-shared-secret
```

3. Create a class that implements `Damms005\LaravelMultipay\Contracts\WebhookPayloadPackager`:

```
use Damms005\LaravelMultipay\Models\Payment;
use Damms005\LaravelMultipay\Contracts\WebhookPayloadPackager;

class MyWebhookPayloadPackager implements WebhookPayloadPackager
{
    public function getWebhookPayload(Payment $payment): array
    {
        return [
            'transaction_reference' => $payment->transaction_reference,
            'amount_paid' => $payment->original_amount_displayed_to_user,
            'payment_processor_name' => $payment->payment_processor_name,
            // ...add any app-specific data you need
        ];
    }
}
```

4. Register your packager in a service provider:

```
config()->set(
    'laravel-multipay.webhook.payload_packager',
    \App\Services\MyWebhookPayloadPackager::class,
);
```

Once configured, every `SuccessfulLaravelMultipayPaymentEvent` will trigger a signed webhook POST to the configured URL with the payload returned by your packager.

### Backfilling Existing Payments

[](#backfilling-existing-payments)

To send existing successful payments to the webhook endpoint:

```
php artisan multipay:send-payments-webhook
```

Options:

- `--from=YYYY-MM-DD` — only payments created on or after this date
- `--to=YYYY-MM-DD` — only payments created on or before this date
- `--chunk=100` — number of payments per batch (default: 100)

The command fail-fast aborts after 3 consecutive batch failures.

Testing
-------

[](#testing)

```
composer test
```

Credits
-------

[](#credits)

This package is made possible by the nice works done by the following awesome projects:

- [yabacon/paystack-php](https://github.com/yabacon/paystack-php)
- [kingflamez/laravelrave](https://github.com/kingflamez/laravelrave)

License
-------

[](#license)

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

###  Health Score

55

—

FairBetter than 97% of packages

Maintenance94

Actively maintained with recent releases

Popularity22

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity79

Established project with proven stability

 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

Every ~10 days

Recently: every ~26 days

Total

165

Last Release

33d ago

Major Versions

v2.6.26 → v3.02024-06-17

v3.10.3 → v4.0.02024-10-10

v4.1.0 → v5.0.02024-10-25

v5.2.2 → v6.0.02025-08-23

v6.0.5 → v7.0.02026-02-12

PHP version history (5 changes)v1.0.0PHP ^8.0

v2.0.20PHP ^7.1|^8.0

v2.4.7PHP ^7.1|^8.0|^8.1

v2.5.0PHP ^8.0|^8.1

v4.0.0PHP ^8.1

### Community

Maintainers

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

---

Top Contributors

[![damms005](https://avatars.githubusercontent.com/u/9839355?v=4)](https://github.com/damms005 "damms005 (287 commits)")

---

Tags

laravellaravel-paymentsdamms005configurable laravel paymentsmultiple payments providersmultiple paymentsDamilola Olowookere

###  Code Quality

TestsPest

Static AnalysisPHPStan

### Embed Badge

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

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

###  Alternatives

[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k108.5M882](/packages/laravel-socialite)[craftcms/cms

Craft CMS

3.6k3.6M3.1k](/packages/craftcms-cms)[spatie/laravel-health

Monitor the health of a Laravel application

87512.0M164](/packages/spatie-laravel-health)[sebdesign/laravel-viva-payments

A Laravel package for integrating the Viva Payments gateway

4851.0k](/packages/sebdesign-laravel-viva-payments)

PHPackages © 2026

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