kommandhub/paystack

A framework-agnostic PHP library for integrating Paystack payments using SOLID principles and PSR standards.

Maintainers

Package info

github.com/KommandHub/paystack

pkg:composer/kommandhub/paystack

Statistics

Installs: 31

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

1.1.0 2026-03-22 01:42 UTC

This package is auto-updated.

Last update: 2026-03-22 10:38:58 UTC


README

Paystack logo

Paystack PHP Library

PHP Composer Latest Version on Packagist Total Downloads Software License

A framework-agnostic PHP library for integrating Paystack payments using SOLID principles and PSR standards. It provides a clean, object-oriented interface to the Paystack API and works in any PHP environment.

Table of Contents

Requirements

  • PHP 8.1 or higher
  • A PSR-18 HTTP client (e.g. guzzlehttp/guzzle, symfony/http-client)
  • PSR-17 HTTP factory (e.g. nyholm/psr7, guzzlehttp/psr7)

Installation

composer require kommandhub/paystack

If you don't already have a PSR-18 client and PSR-17 factory, install popular ones:

composer require guzzlehttp/guzzle nyholm/psr7

Quick Start

use Kommandhub\Paystack\Paystack;
use GuzzleHttp\Client;
use Nyholm\Psr7\Factory\Psr17Factory;

$factory  = new Psr17Factory();
$paystack = new Paystack(
    secretKey:      'sk_live_your_secret_key',
    client:         new Client(),
    requestFactory: $factory,
    streamFactory:  $factory
);

// Initialize a transaction
$response = $paystack->transactions()->initialize([
    'email'  => 'customer@example.com',
    'amount' => 500000, // amount in kobo (NGN 5,000)
]);

header('Location: ' . $response['data']['authorization_url']);
exit;

Initialization

Using Guzzle and Nyholm PSR-7

use Kommandhub\Paystack\Paystack;
use GuzzleHttp\Client;
use Nyholm\Psr7\Factory\Psr17Factory;

$factory  = new Psr17Factory();

$paystack = new Paystack(
    secretKey:      'sk_live_your_secret_key',
    client:         new Client(),
    requestFactory: $factory,
    streamFactory:  $factory
);

Bringing Your Own HTTP Client

Implement Kommandhub\Paystack\Contracts\HttpClientInterface to wrap any HTTP layer you prefer, then pass it directly:

use Kommandhub\Paystack\Paystack;
use App\Http\MyCustomHttpClient;

$paystack = new Paystack(
    secretKey:  'sk_live_your_secret_key',
    httpClient: new MyCustomHttpClient()
);

Response Structure

Every resource method returns an associative array that mirrors the Paystack API JSON response:

[
    'status'  => true,           // bool – whether the request succeeded
    'message' => 'Authorized',   // string – human-readable status message
    'data'    => [ ... ],        // array – the actual payload (varies by endpoint)
]

Always check $response['status'] before consuming $response['data'].

Error Handling

All resource methods throw Kommandhub\Paystack\Exceptions\PaystackException on HTTP or API errors. Wrap calls in a try/catch block:

use Kommandhub\Paystack\Exceptions\PaystackException;

try {
    $response = $paystack->transactions()->verify('invalid_ref');
} catch (PaystackException $e) {
    // Log or display $e->getMessage()
    echo 'Paystack error: ' . $e->getMessage();
}

Resources

Transactions

Handle payment initialization, verification, and retrieval.

// Initialize a transaction
$response = $paystack->transactions()->initialize([
    'email'        => 'customer@example.com',
    'amount'       => 500000,                         // in kobo
    'callback_url' => 'https://your-site.com/callback',
]);

$authorizationUrl = $response['data']['authorization_url'];

// Verify a transaction
$response = $paystack->transactions()->verify('transaction_reference');

// List transactions (supports query params: perPage, page, customer, status, etc.)
$response = $paystack->transactions()->list(['perPage' => 20, 'page' => 1]);

// Fetch a single transaction by ID
$response = $paystack->transactions()->fetch('12345678');

Customers

Manage your customer database.

// Create a customer
$response = $paystack->customers()->create([
    'email'      => 'customer@example.com',
    'first_name' => 'John',
    'last_name'  => 'Doe',
    'phone'      => '+2348012345678',
]);

// List customers (supports query params: perPage, page, etc.)
$response = $paystack->customers()->list(['perPage' => 50]);

// Fetch a customer by email or customer code
$response = $paystack->customers()->fetch('customer@example.com');
$response = $paystack->customers()->fetch('CUS_xxxxxxxxxx');

// Update a customer
$response = $paystack->customers()->update('CUS_xxxxxxxxxx', [
    'first_name' => 'Jane',
]);

Transfers

Send money to customers or vendors.

// Create a transfer recipient
$response = $paystack->transfers()->recipient([
    'type'           => 'nuban',
    'name'           => 'John Doe',
    'account_number' => '0001234567',
    'bank_code'      => '058',
    'currency'       => 'NGN',
]);

$recipientCode = $response['data']['recipient_code'];

// Initiate a transfer
$response = $paystack->transfers()->initiate([
    'source'    => 'balance',
    'amount'    => 50000,
    'recipient' => $recipientCode,
    'reason'    => 'Payment for services',
]);

// List transfers (supports query params: perPage, page, customer, etc.)
$response = $paystack->transfers()->list(['perPage' => 20]);

// Fetch a single transfer by ID or transfer code
$response = $paystack->transfers()->fetch('TRF_xxxxxxxxxx');

// Verify a transfer by reference
$response = $paystack->transfers()->verify('transfer_reference');

Subscriptions

Manage recurring payments.

// Create a subscription
$response = $paystack->subscriptions()->create([
    'customer'   => 'CUS_xxxxxxxxxx',
    'plan'       => 'PLN_xxxxxxxxxx',
    'start_date' => '2026-01-01T00:00:00.000Z', // optional
]);

// List subscriptions (supports query params: perPage, page, customer, plan)
$response = $paystack->subscriptions()->list(['plan' => 'PLN_xxxxxxxxxx']);

// Fetch a subscription by ID or subscription code
$response = $paystack->subscriptions()->fetch('SUB_xxxxxxxxxx');

// Enable a subscription
$response = $paystack->subscriptions()->enable([
    'code'  => 'SUB_xxxxxxxxxx',
    'token' => 'email_token',
]);

// Disable a subscription
$response = $paystack->subscriptions()->disable([
    'code'  => 'SUB_xxxxxxxxxx',
    'token' => 'email_token',
]);

// Generate a self-service management link for the customer
$response = $paystack->subscriptions()->manageLink('SUB_xxxxxxxxxx');
$managementUrl = $response['data']['link'];

// Email the management link directly to the customer
$response = $paystack->subscriptions()->sendManageLink('SUB_xxxxxxxxxx');

Plans

Create and manage payment plans for subscriptions.

// Create a plan
$response = $paystack->plans()->create([
    'name'     => 'Monthly Premium',
    'amount'   => 500000,   // in kobo
    'interval' => 'monthly', // daily | weekly | monthly | annually
]);

// List plans (supports query params: perPage, page, status, interval, amount)
$response = $paystack->plans()->list(['interval' => 'monthly']);

// Fetch a plan by ID or plan code
$response = $paystack->plans()->fetch('PLN_xxxxxxxxxx');

// Update a plan
$response = $paystack->plans()->update('PLN_xxxxxxxxxx', [
    'name'   => 'Monthly Premium Plus',
    'amount' => 750000,
]);

Splits

Split payments between multiple subaccounts.

// Create a split
$response = $paystack->splits()->create([
    'name'         => 'Revenue Split',
    'type'         => 'percentage',  // percentage | flat
    'currency'     => 'NGN',
    'subaccounts'  => [
        ['subaccount' => 'ACCT_xxxxxxxxxx', 'share' => 20],
    ],
    'bearer_type'  => 'subaccount',  // subaccount | account | all-proportional | all
    'bearer_subaccount' => 'ACCT_xxxxxxxxxx',
]);

// List splits (supports query params: name, active, sort_by, perPage, page, from, to)
$response = $paystack->splits()->list(['active' => true]);

// Fetch a split by ID
$response = $paystack->splits()->fetch('SPL_xxxxxxxxxx');

// Update a split
$response = $paystack->splits()->update('SPL_xxxxxxxxxx', [
    'name'   => 'Updated Revenue Split',
    'active' => true,
]);

// Add or update a subaccount in a split
$response = $paystack->splits()->addSubaccount('SPL_xxxxxxxxxx', [
    'subaccount' => 'ACCT_yyyyyyyyyy',
    'share'      => 30,
]);

// Remove a subaccount from a split
$response = $paystack->splits()->removeSubaccount('SPL_xxxxxxxxxx', [
    'subaccount' => 'ACCT_yyyyyyyyyy',
]);

Subaccounts

Manage subaccounts for split payments and marketplace settlements.

// Create a subaccount
$response = $paystack->subaccounts()->create([
    'business_name'    => 'Acme Stores',
    'settlement_bank'  => '058',
    'account_number'   => '0001234567',
    'percentage_charge' => 18.2,
]);

// List subaccounts (supports query params: perPage, page, from, to)
$response = $paystack->subaccounts()->list(['perPage' => 50]);

// Fetch a subaccount by ID or subaccount code
$response = $paystack->subaccounts()->fetch('ACCT_xxxxxxxxxx');

// Update a subaccount
$response = $paystack->subaccounts()->update('ACCT_xxxxxxxxxx', [
    'percentage_charge' => 20.0,
    'description'       => 'Updated description',
]);

Refunds

Process full or partial refunds for transactions.

// Create a refund (omit 'amount' for a full refund)
$response = $paystack->refunds()->create([
    'transaction' => 'transaction_reference',
    'amount'      => 50000, // optional – partial refund in kobo
]);

// List refunds (supports query params: reference, currency, from, to, perPage, page)
$response = $paystack->refunds()->list(['reference' => 'transaction_reference']);

// Fetch a refund by reference
$response = $paystack->refunds()->fetch('refund_reference');

Verification

Verify customer account and card information.

// Resolve a bank account number
$response = $paystack->verification()->resolveAccount('0001234567', '058');
$accountName = $response['data']['account_name'];

// Resolve a card BIN (first 6 digits)
$response = $paystack->verification()->resolveCardBin('539983');
$cardInfo  = $response['data']; // bank, card_type, brand, etc.

Settlements

Retrieve settlement reports and their associated transactions.

// List settlements (supports query params: perPage, page, status, subaccount, from, to)
$response = $paystack->settlements()->list(['from' => '2026-01-01']);

// Fetch transactions for a specific settlement
$response = $paystack->settlements()->transactions('settlement_id', ['perPage' => 100]);

Miscellaneous

Access supporting reference data from the Paystack API.

// List supported banks (supports query params: country, use_cursor, perPage, etc.)
$response = $paystack->miscellaneous()->listBanks(['country' => 'nigeria']);

// List supported countries
$response = $paystack->miscellaneous()->listCountries();

// List states for Address Verification Service (AVS)
$response = $paystack->miscellaneous()->listStates('US');

Webhook Handling

Paystack sends webhook events to your endpoint for asynchronous notifications. Always validate the signature before processing:

// webhook.php

$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PAYSTACK_SIGNATURE'] ?? '';
$secret    = 'sk_live_your_secret_key';

if (hash_hmac('sha512', $payload, $secret) !== $signature) {
    http_response_code(401);
    exit('Invalid signature');
}

$event = json_decode($payload, true);

match ($event['event']) {
    'charge.success'      => handleChargeSuccess($event['data']),
    'transfer.success'    => handleTransferSuccess($event['data']),
    'subscription.create' => handleSubscriptionCreate($event['data']),
    default               => null,
};

http_response_code(200);

Tip: Respond with HTTP 200 as quickly as possible and process webhook payloads asynchronously (e.g. via a queue) to avoid timeouts.

Testing

composer test

Development (Docker)

This project includes a Docker environment for easy development.

Requirements

  • Docker
  • Docker Compose

Getting Started

Command Description
make build Build and start the container
make shell Open a shell inside container
make test Run the test suite
make lint Run static analysis (PHPStan)
make format Fix code style (PHP CS Fixer)
make down Stop and remove containers

Or use docker-compose directly:

docker-compose up -d
docker-compose exec app sh

Code Quality

Tool Command Purpose
PHPStan composer lint Static analysis
PHP CS Fixer composer format Code style enforcement

Please ensure both pass before submitting a pull request.

Contributing

Please see CONTRIBUTING for details.

License

The MIT License (MIT). Please see the License File for more information.