bazzly/payoffice

Laravel package to use all fintech payment API and fetch server for pings

Maintainers

Package info

github.com/Bazzly/payoffice

Type:package

pkg:composer/bazzly/payoffice

Transparency log

Statistics

Installs: 10

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-08-02 10:34 UTC

This package is auto-updated.

Last update: 2026-08-02 13:01:12 UTC


README

All your payment providers in one place.

Latest Version Software License Total Downloads

Payoffice is a Laravel package that solves one specific problem: a payment provider's API can go down or slow down, and your checkout shouldn't blindly trust it. Before sending a customer to a payment gateway, Payoffice can ping the provider's API host and report whether it's up, down, and how fast it's responding — so your app can pick a healthy provider or warn the user instead of failing mid-checkout.

On top of that, it bundles ready-to-use integrations for popular fintech APIs so you don't have to wire each one up from scratch.

Table of contents

Features

  • Provider health check — ping a payment API's host over TCP and get back status (up/down) and latency in milliseconds before deciding whether to use it.
  • Paystack payments — initialize transactions, verify payments, manage plans, customers, subscriptions, payment pages, and subaccounts.
  • Paystack transfers — look up banks, resolve account numbers, create transfer recipients, and send money.
  • Secure transaction references — cryptographically random reference/token generator.
  • Config-driven, multi-provider — Paystack, Flutterwave, Interswitch, and Remita are pre-scaffolded in the published config file.

Requirements

Requirement Version
PHP ^7.2 | ^8.0 | ^8.1 | ^8.2 | ^8.3 | ^8.4
Laravel (illuminate/support) ^6 | ^7 | ^8 | ^9 | ^10 | ^11 | ^12 | ^13
guzzlehttp/guzzle ^6 | ^7 | ^8 | ^9

Local development (running the test suite / examples/demo.php) is verified against the latest supported combination — PHP 8.4, Laravel 13, PHPUnit 13, orchestra/testbench 11 — via require-dev, regardless of which older Laravel/PHP version you build against.

Installation

Install via Composer:

composer require bazzly/payoffice

Laravel's package auto-discovery will register Bazzly\Payoffice\PaymentServiceProvider automatically — no manual entry in config/app.php is needed.

Publish the config file and the pings_monitoring migration:

php artisan vendor:publish --provider="Bazzly\Payoffice\PaymentServiceProvider" --tag="config"
php artisan vendor:publish --provider="Bazzly\Payoffice\PaymentServiceProvider" --tag="pings_monitoring"
php artisan migrate

Publishing the config is required — the package reads provider settings from config/payoffice.php once it exists in your app, not from the package's internal copy.

Configuration

The published config/payoffice.php is a list of provider entries. Fill in credentials via your .env file:

# Paystack
PAYSTACK_PUBLIC_KEY=
PAYSTACK_SECRET_KEY=
PAYSTACK_PAYMENT_URL=https://api.paystack.co
PAYSTACK_MERCHANT_EMAIL=
PAYSTACK_MERCHANT_CURRENCY=NGN

# Flutterwave
FLW_PUBLIC_KEY=
FLW_SECRET_KEY=
FLW_SECRET_HASH=

# Interswitch
INTERSWITCH_GATEWAY_TYPE=WEBPAY
INTERSWITCH_CURRENCY=566
INTERSWITCH_SITE_REDIRECT_URL=
INTERSWITCH_ENV=TEST
INTERSWITCH_SPLIT=false
INTERSWITCH_COLLEGE=
INTERSWITCH_SEND_MAIL=false
INTERSWITCH_MAC_KEY=
INTERSWITCH_PRODUCT_ID=
INTERSWITCH_PAY_ITEM_ID=

# Remita
MERCHANTID=
SERVICETYPEID=
FUNDINGACCOUNT=
FUNDINGBANKCODE=
APIKEY=
MANDATETPYE=DD

Each provider entry in config/payoffice.php has a name and APIURL key used by the health-ping feature, plus a provider-specific block (paystack, flutterwave, etc.) used by that provider's integration classes.

Usage

Server / API health ping

PingServer checks whether a payment API host is reachable and how fast it responds, so you can gate checkout on the provider actually being up.

use Bazzly\Payoffice\PingServer;

// PingServer(string $name, string $url, ?int $preferredPingMs = null)
$check = new PingServer('paystack', 'api.paystack.co', 100);

$result = $check->getUrlServerDetails();

// $result = [
//     'name'        => 'paystack',
//     'apiurl'      => 'api.paystack.co',
//     'serverStatus'=> 'up',     // PingServer::UPSTATUS / PingServer::DOWNSTATUS
//     'serverPing'  => 42,       // measured latency in ms
//     'userPing'    => 100,      // your preferred/acceptable threshold (defaults to 10)
// ];

if ($result['serverStatus'] === PingServer::UPSTATUS && $result['serverPing'] <= $result['userPing']) {
    // safe to redirect the customer to this provider
} else {
    // provider is down or too slow — fall back to another provider
}

To check every provider configured in config/payoffice.php in one pass:

use Bazzly\Payoffice\PingServer;

$providers = config('payoffice');

$statuses = collect($providers)->map(function ($provider) {
    $ping = new PingServer($provider['name'], $provider['APIURL']);
    return $ping->getUrlServerDetails();
});

Persisting ping results

If you want a history of ping checks (e.g. for an internal status dashboard), the pings_monitoring migration and PingsMonitoring Eloquent model are included:

use Bazzly\Payoffice\Models\PingsMonitoring;
use Bazzly\Payoffice\PingServer;

$result = (new PingServer('paystack', 'api.paystack.co', 100))->getUrlServerDetails();

PingsMonitoring::create([
    'name'         => $result['name'],
    'apiurl'       => $result['apiurl'],
    'serverStatus' => $result['serverStatus'],
    'serverPing'   => $result['serverPing'],
    'userPing'     => $result['userPing'],
]);

This is a manual step — the package does not currently schedule ping checks for you. Wire it into your own app/Console/Kernel.php schedule if you want periodic checks.

Paystack — payments

GetPaid wraps the Paystack transactions/plans/customers/subscriptions/pages/subaccounts API. Most methods read their payload straight from the current request (i.e. they're meant to be called from a controller handling a form POST), but you can also pass an explicit $data array to bypass that.

use Bazzly\Payoffice\Paystack\GetPaid;

$paystack = new GetPaid();

// Initialize a transaction and redirect the customer to Paystack
public function pay(GetPaid $paystack)
{
    return $paystack->getAuthorizationUrl()->redirectNow();
}

// Or supply the payload explicitly instead of relying on request() input
$paystack->getAuthorizationUrl([
    'amount'    => 500000, // kobo
    'email'     => 'customer@example.com',
    'reference' => $paystack->genTranxRef(),
]);

// Verify a transaction after the customer returns from Paystack
public function callback(GetPaid $paystack)
{
    if ($paystack->isTransactionVerificationValid()) {
        $payment = $paystack->getPaymentData();
        // mark the order as paid
    }
}

Other available methods:

Method Purpose
genTranxRef() Generate a unique transaction reference
getAllCustomers() / createCustomer() / fetchCustomer($id) / updateCustomer($id) Customer management
getAllPlans() / createPlan() / fetchPlan($code) / updatePlan($code) Subscription plan management
createSubscription() / getAllSubscriptions() / getCustomerSubscriptions($id) / getPlanSubscriptions($id) / enableSubscription() / disableSubscription() / fetchSubscription($id) Subscription management
createPage() / getAllPages() / fetchPage($id) / updatePage($id) Paystack payment pages
createSubAccount() / fetchSubAccount($code) / listSubAccounts($perPage, $page) / updateSubAccount($code) Split-payment subaccounts
exportTransactions() / getAllTransactions() Transaction reporting

Paystack — transfers & banks

Transfer handles paying money out — bank lookups, recipient creation, and transfers.

use Bazzly\Payoffice\Paystack\Transfer;

$transfer = new Transfer();

// List supported banks
$banks = $transfer->getBanks('nigeria');

// Confirm an account number belongs to the expected owner
$account = $transfer->confirmAccount('0123456789', '058');

// Send money to a bank account
$transfer->sendMonyToAccDetails(
    accName: 'Jane Doe',
    accNumber: '0123456789',
    bankName: 'Guaranty Trust Bank',
    metadata: [
        'bankCode' => '058',
        'source'   => 'balance',
        'amount'   => 500000, // kobo
        'reference'=> $transfer->getBanks() ? uniqid('trf_') : null,
        'reason'   => 'Vendor payout',
    ]
);

// Check your Paystack balance
$balance = $transfer->getBalance();

// Verify a transfer by its reference
$status = $transfer->getVerifyTransfer('trf_abc123');

Transaction reference generator

TransRef generates cryptographically-random reference strings/tokens (useful for anything needing a unique, non-guessable identifier — not limited to Paystack).

use Bazzly\Payoffice\TransRef;

$reference = TransRef::getHashedToken(); // 25-char alphanumeric token by default
$reference = TransRef::getHashedToken(12); // custom length

Testing

composer install
vendor/bin/phpunit

PingServer, GetPaid, and Transfer all have automated coverage. The Paystack tests don't hit the real API — they inject a Guzzle MockHandler via an optional constructor argument (new GetPaid($handlerStack) / new Transfer($handlerStack)), so the suite runs offline with no credentials needed:

use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;

$mock = new MockHandler([
    new Response(200, [], json_encode(['status' => true, 'data' => [/* ... */]])),
]);

$paystack = new GetPaid(HandlerStack::create($mock));

Omit the argument in real usage (new GetPaid()) and it talks to the real Paystack API as normal.

Tests use PHPUnit's #[Test] attribute (PHPUnit\Framework\Attributes\Test), not the older /** @test */ docblock — the latter was removed in PHPUnit 11+. Match that convention for any new test you add.

Local simulation

examples/demo.php is a runnable, no-credentials-needed walkthrough of the whole package — a real network health check via PingServer, plus a mocked Paystack payment and payout flow via GetPaid/Transfer (same MockHandler approach as the tests). Useful for seeing the package work end-to-end without setting up a Laravel app or real API keys:

composer install
php examples/demo.php

Roadmap / known limitations

This package is under active development. Known rough edges before you rely on it in production:

  • Scheduled/periodic pinging and automatic persistence to PingsMonitoring are not wired up yet; you must trigger and store checks yourself.
  • The Paystack integration is a fork of unicodeveloper/laravel-paystack adapted to this package's config structure — behavior should match the upstream package, but hasn't yet been independently re-verified end-to-end here.

Credits

  • ALLI BAZEET — author
  • unicodeveloper — the Paystack integration in src/Paystack is adapted from laravel-paystack; enormous credit for the original, well-documented implementation this was built on.

License

The MIT License (MIT). See LICENSE for details.