PHPackages                             rainwaves/paystack-payment - 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. rainwaves/paystack-payment

ActiveLibrary[Payment Processing](/categories/payments)

rainwaves/paystack-payment
==========================

Laravel package for Paystack single payments, subscriptions, webhooks, and refunds.

v1.0.0(3mo ago)00MITPHPPHP ^8.2

Since Mar 23Pushed 3mo agoCompare

[ Source](https://github.com/Magnificent-Big-J/paystack-payment)[ Packagist](https://packagist.org/packages/rainwaves/paystack-payment)[ Docs](https://github.com/Magnificent-Big-J/paystack-payment)[ RSS](/packages/rainwaves-paystack-payment/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (1)Dependencies (4)Versions (2)Used By (0)

Paystack Payment Package
========================

[](#paystack-payment-package)

This is a Laravel package for integrating with the Paystack payment gateway. It supports customer creation, recurring plans, single payments, transaction verification, webhook verification, and refunds.

The package includes request validation guards before outbound calls and returns DTOs with transaction details that are useful to Rainwaves host applications.

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

[](#installation)

You can install the package via Composer:

```
composer require rainwaves/paystack-payment
```

For package development:

```
composer install
composer lint
composer test
```

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

[](#configuration)

Publish the config file in your Laravel application:

```
php artisan vendor:publish --provider="rainwaves\\PaystackPayment\\PaystackServiceProvider"
```

Set the Paystack credentials in your `.env` file:

- `PAYSTACK_SECRET_KEY=`
- `PAYSTACK_PUBLIC_KEY=`
- `PAYSTACK_WEBHOOK_SECRET=`
- `PAYSTACK_CALLBACK_URL=`
- `PAYSTACK_CANCEL_URL=`
- `PAYSTACK_CURRENCY=ZAR`
- `PAYSTACK_TIMEOUT=15`
- `PAYSTACK_RETRY=2`

Example config:

```
return [
    'default' => env('PAYSTACK_PAYMENT_DRIVER', 'paystack'),
    'paystack' => [
        'secret_key' => env('PAYSTACK_SECRET_KEY', ''),
        'public_key' => env('PAYSTACK_PUBLIC_KEY', ''),
        'base_url' => env('PAYSTACK_BASE_URL', 'https://api.paystack.co'),
        'webhook_secret' => env('PAYSTACK_WEBHOOK_SECRET', env('PAYSTACK_SECRET_KEY', '')),
        'callback_url' => env('PAYSTACK_CALLBACK_URL'),
        'cancel_url' => env('PAYSTACK_CANCEL_URL'),
        'currency' => env('PAYSTACK_CURRENCY', 'ZAR'),
        'timeout' => (int) env('PAYSTACK_TIMEOUT', 15),
        'retry' => (int) env('PAYSTACK_RETRY', 2),
    ],
];
```

Compatibility
-------------

[](#compatibility)

- PHP: 8.2+
- Laravel: 12.x

Versioning
----------

[](#versioning)

Package versions should be published with Git tags, not by setting a `version` field in `composer.json`.

Recommended first stable release:

- `v1.0.0`

Currency Rule
-------------

[](#currency-rule)

Keep the currency rule simple:

- the package should use the currency configured for the Paystack portfolio
- set that default in `paystack.paystack.currency`
- pass a currency in the DTO only when you need to override the configured default
- all amounts sent to Paystack must be in minor units

Examples:

- `ZAR 125.50` must be sent as `12550`
- `USD 25.00` must be sent as `2500`

If your product catalog stores prices in `USD` but the customer is checking out against a `ZAR` Paystack portfolio, convert the amount before calling the package and send the final Paystack currency amount in minor units.

Usage
-----

[](#usage)

The main interface exposed by the package is `rainwaves\PaystackPayment\Contracts\PaymentGatewayInterface`.

### Laravel

[](#laravel)

```
use Illuminate\Http\Request;
use rainwaves\PaystackPayment\Contracts\PaymentGatewayInterface;
use rainwaves\PaystackPayment\DTO\CheckoutInitializationData;
use rainwaves\PaystackPayment\DTO\CustomerData;
use rainwaves\PaystackPayment\DTO\PlanData;
use rainwaves\PaystackPayment\DTO\RefundData;
use rainwaves\PaystackPayment\DTO\WebhookPayload;

class PaymentController extends Controller
{
    public function __construct(
        private readonly PaymentGatewayInterface $payments,
    ) {}

    public function createCustomer(Request $request)
    {
        return $this->payments->createCustomer(new CustomerData(
            email: $request->string('email')->toString(),
            firstName: $request->string('first_name')->toString(),
            lastName: $request->string('last_name')->toString(),
            phone: $request->string('phone')->toString(),
            metadata: [
                'user_id' => $request->user()?->id,
            ],
        ));
    }

    public function createPlan()
    {
        return $this->payments->createPlan(new PlanData(
            name: 'Gold Plan',
            amountInMinor: 9900,
            interval: 'monthly',
            description: 'Monthly Gold subscription',
        ));
    }

    public function singlePayment(Request $request)
    {
        return $this->payments->initializeCheckout(new CheckoutInitializationData(
            reference: (string) str()->uuid(),
            email: $request->string('email')->toString(),
            amountInMinor: 12550,
            callbackUrl: config('paystack.paystack.callback_url'),
            metadata: [
                'type' => 'single_payment',
                'order_id' => $request->integer('order_id'),
            ],
        ));
    }

    public function subscriptionPayment(Request $request)
    {
        return $this->payments->initializeCheckout(new CheckoutInitializationData(
            reference: (string) str()->uuid(),
            email: $request->string('email')->toString(),
            amountInMinor: 9900,
            planCode: 'PLN_xxxxxxxx',
            customerCode: 'CUS_xxxxxxxx',
            callbackUrl: config('paystack.paystack.callback_url'),
            metadata: [
                'type' => 'subscription',
                'portfolio_id' => $request->integer('portfolio_id'),
            ],
        ));
    }

    public function verifyTransaction(string $reference)
    {
        return $this->payments->verifyTransaction($reference);
    }

    public function refund(string $reference)
    {
        return $this->payments->createRefund(new RefundData(
            transactionReference: $reference,
            amountInMinor: 9900,
            reason: 'Customer requested cancellation',
        ));
    }

    public function webhook(Request $request)
    {
        return $this->payments->verifyWebhook(new WebhookPayload(
            rawBody: $request->getContent(),
            headers: $request->headers->all(),
            payload: $request->all(),
        ));
    }
}
```

### Single Payments

[](#single-payments)

For one-time payments, initialize checkout without a `planCode`:

```
use rainwaves\PaystackPayment\DTO\CheckoutInitializationData;

$checkout = $payments->initializeCheckout(new CheckoutInitializationData(
    reference: 'ORDER-1001',
    email: 'customer@example.com',
    amountInMinor: 12550,
    metadata: [
        'type' => 'single_payment',
        'order_id' => 1001,
    ],
));

return redirect()->away($checkout->checkoutUrl);
```

### Subscriptions

[](#subscriptions)

For subscriptions, create the Paystack plan first, then initialize checkout with the returned `planCode`:

```
use rainwaves\PaystackPayment\DTO\CheckoutInitializationData;
use rainwaves\PaystackPayment\DTO\PlanData;

$plan = $payments->createPlan(new PlanData(
    name: 'Premium Monthly',
    amountInMinor: 9900,
    interval: 'monthly',
));

$checkout = $payments->initializeCheckout(new CheckoutInitializationData(
    reference: 'SUB-1001',
    email: 'customer@example.com',
    amountInMinor: 9900,
    planCode: $plan->code,
));
```

### Optional Fields

[](#optional-fields)

- `CheckoutInitializationData::$callbackUrl`
- `CheckoutInitializationData::$planCode`
- `CheckoutInitializationData::$customerCode`
- `CheckoutInitializationData::$metadata`
- `CheckoutInitializationData::$currency`
- `PlanData::$description`
- `PlanData::$invoiceLimit`
- `PlanData::$metadata`
- `PlanData::$currency`
- `RefundData::$amountInMinor`
- `RefundData::$currency`
- `RefundData::$reason`
- `RefundData::$customerNote`
- `RefundData::$merchantNote`

### Validation Rules

[](#validation-rules)

The package validates common request mistakes before sending anything to Paystack:

- checkout amount must be greater than zero
- plan amount must be greater than zero
- refund amount must be greater than zero when provided
- checkout and customer emails must be valid email addresses
- checkout references, plan names, and plan intervals cannot be blank

Validation failures throw `rainwaves\PaystackPayment\Exceptions\InvalidPaymentRequestException`.

### Verification Details

[](#verification-details)

`verifyTransaction()` returns more than the basic status fields. In addition to the reference and amount, the DTO can include:

- `customerEmail`
- `customerName`
- `authorizationReusable`
- `paidAt`
- `feesInMinor`
- `channel`
- `gatewayResponse`

Example:

```
$transaction = $payments->verifyTransaction($reference);

if ($transaction->status === 'success' && $transaction->authorizationReusable) {
    // save reusable authorization details for future billing
}
```

### Webhooks

[](#webhooks)

The package verifies the Paystack webhook signature using the configured webhook secret:

```
$verification = $payments->verifyWebhook(new WebhookPayload(
    rawBody: $request->getContent(),
    headers: $request->headers->all(),
    payload: $request->all(),
));

if (! $verification->isValid) {
    abort(401, 'Invalid Paystack webhook signature.');
}
```

Webhook helpers are available on the verification DTO:

```
if ($verification->isChargeSuccess()) {
    // activate payment locally
}

if ($verification->isSubscriptionCreate()) {
    // persist provider subscription details
}
```

Notes
-----

[](#notes)

- The package returns DTOs so host applications can map provider responses into their own persistence and business logic.
- Single-payment and subscription activation flows remain the responsibility of the host application.
- Refund orchestration and local state transitions belong in the host application layer.

Production Checklist
--------------------

[](#production-checklist)

Before tagging a production release, run the checklist in [docs/sandbox-smoke-test.md](/home/eclaims/package-development/rainwaves/paystack-payment/docs/sandbox-smoke-test.md).

The first release notes are in [docs/release-notes-v1.0.0.md](/home/eclaims/package-development/rainwaves/paystack-payment/docs/release-notes-v1.0.0.md).

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance82

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

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

92d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/30896750?v=4)[Joel Mnisi](/maintainers/Magnificent-Big-J)[@Magnificent-Big-J](https://github.com/Magnificent-Big-J)

---

Top Contributors

[![mnisij](https://avatars.githubusercontent.com/u/14214514?v=4)](https://github.com/mnisij "mnisij (10 commits)")

---

Tags

paymentspaystackrainwavespaystack-payment

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/rainwaves-paystack-payment/health.svg)

```
[![Health](https://phpackages.com/badges/rainwaves-paystack-payment/health.svg)](https://phpackages.com/packages/rainwaves-paystack-payment)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.1M337](/packages/psalm-plugin-laravel)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

815320.5k3](/packages/defstudio-telegraph)[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.3M42](/packages/spatie-laravel-pdf)[ralphjsmit/laravel-glide

Auto-magically generate responsive images from static image files.

4923.6k5](/packages/ralphjsmit-laravel-glide)[simplestats-io/laravel-client

Analytics for Laravel. Track visitors, registrations, and payments. Discover which channels actually drive revenue, not just traffic. Server-side, GDPR compliant, ad-blocker proof.

5019.3k](/packages/simplestats-io-laravel-client)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3913.7k](/packages/rawilk-profile-filament-plugin)

PHPackages © 2026

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