Laravel package to use all fintech payment API and fetch server for pings
bazzly/payoffice is a Laravel package for laravel package to use all fintech payment api and fetch server for pings.
It currently has 0 GitHub stars and 10 downloads on Packagist (latest version v0.1.0).
Install it with composer require bazzly/payoffice.
Discover more Laravel packages by bazzly
or browse all Laravel packages to compare alternatives.
Last updated
All your payment providers in one place.
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.
up/down) and latency in milliseconds before deciding whether to use it.| 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.
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.phponce it exists in your app, not from the package's internal copy.
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.
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();
});
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.phpschedule if you want periodic checks.
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' => '[email protected]',
'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 |
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');
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
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.
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
This package is under active development. Known rough edges before you rely on it in production:
PingsMonitoring are not wired
up yet; you must trigger and store checks yourself.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.src/Paystack is adapted from laravel-paystack; enormous credit for the
original, well-documented implementation this was built on.The MIT License (MIT). See LICENSE for details.