A modern, type-safe PHP SDK for Paystack payment processing.
- PHP 8.0+
- Guzzle 7.x
composer require faridibin/paystack-phpThe Paystack client only registers the health service by default. Register the services you need before calling them.
use Faridibin\Paystack\Paystack;
use Faridibin\Paystack\Services\Payments\Transactions\Transactions;
use Faridibin\Paystack\Services\Payments\Customers;
use Faridibin\Paystack\Contracts\Services\Payments\Transactions\TransactionsInterface;
use Faridibin\Paystack\Contracts\Services\Payments\CustomersInterface;
$paystack = new Paystack(secretKey: 'sk_live_...');
$paystack->registerServices([
'transactions' => [Transactions::class, TransactionsInterface::class],
'customers' => [Customers::class, CustomersInterface::class],
]);
$paystack->transactions()->initialize(amount: 50000, email: 'customer@example.com');
$paystack->customers()->create(['email' => 'customer@example.com', 'first_name' => 'John', 'last_name' => 'Doe']);The alias on the left of each entry is the dynamic method name you'll call on $paystack. Pick whatever names you like.
| Suggested alias | Service class |
|---|---|
transactions() |
Services\Payments\Transactions\Transactions |
splits() |
Services\Payments\Transactions\Splits |
customers() |
Services\Payments\Customers |
charge() |
Services\Payments\Charge |
bulkCharges() |
Services\Payments\BulkCharges |
refunds() |
Services\Payments\Refunds |
subaccounts() |
Services\Payments\Subaccounts |
disputes() |
Services\Payments\Disputes |
settlements() |
Services\Payments\Settlements |
paymentRequests() |
Services\Payments\PaymentRequests |
dedicatedAccount() |
Services\Payments\DedicatedAccount |
terminal() |
Services\Payments\Terminal |
applePay() |
Services\Payments\ApplePay |
| Suggested alias | Service class |
|---|---|
transfers() |
Services\Transfers\Transfers |
recipients() |
Services\Transfers\Recipients |
control() |
Services\Transfers\Control |
| Suggested alias | Service class |
|---|---|
plans() |
Services\Recurring\Plans |
subscriptions() |
Services\Recurring\Subscriptions |
| Suggested alias | Service class |
|---|---|
products() |
Services\Commerce\Products |
paymentPages() |
Services\Commerce\PaymentPages |
| Suggested alias | Service class |
|---|---|
integration() |
Services\Integration |
verification() |
Services\Verification |
miscellaneous() |
Services\Miscellaneous |
balance() |
Services\Balance |
directDebit() |
Services\DirectDebit |
virtualTerminal() |
Services\VirtualTerminal |
storefront() |
Services\Storefront |
order() |
Services\Order |
// Initialize a transaction
$response = $paystack->transactions()->initialize(amount: 50000, email: 'customer@example.com');
$authUrl = $response->getData()->authorization_url;
// Verify a transaction
$paystack->transactions()->verify('ref_abc123');
// List transactions
$paystack->transactions()->list(perPage: 20, page: 1);
// Fetch a transaction by id
$paystack->transactions()->fetch('123456789');
// Charge a saved authorization
$paystack->transactions()->chargeAuthorization('AUTH_xxx', amount: 10000, email: 'customer@example.com');
// Partial debit
$paystack->transactions()->partialDebit('AUTH_xxx', amount: 10000, currency: 'NGN', email: 'customer@example.com');// Create a customer
$paystack->customers()->create([
'email' => 'john@example.com',
'first_name' => 'John',
'last_name' => 'Doe',
'phone' => '+2348000000000',
]);
// Fetch a customer
$paystack->customers()->fetch('CUS_xxx');
// Update a customer
$paystack->customers()->update('CUS_xxx', ['first_name' => 'Jane']);
// Validate a customer's identity (e.g. BVN check)
$paystack->customers()->validate('CUS_xxx', [
'first_name' => 'John',
'last_name' => 'Doe',
'type' => 'bank_account',
'value' => '0123456789',
'country' => 'NG',
'bvn' => '12345678901',
'bank_code' => '058',
'account_number' => '0123456789',
]);
// Whitelist or blacklist a customer
$paystack->customers()->setRiskStatus('CUS_xxx', 'allow');use Faridibin\Paystack\Enums\Currency;
// Initiate a transfer (reference must be unique per request β required for idempotency)
$paystack->transfers()->initiateTransfer(
amount: 10000,
recipient: 'RCP_xxx',
reference: 'pay_invoice_42_2026_04',
optional: ['reason' => 'Payment for services'],
);
// Finalize a transfer (when OTP is required)
$paystack->transfers()->finalizeTransfer('TRF_xxx', '123456');
// Bulk transfers
$paystack->transfers()->initiateBulkTransfer(Currency::NGN, [
['amount' => 5000, 'recipient' => 'RCP_aaa', 'reference' => 'inv_1', 'reason' => 'Invoice 1'],
['amount' => 7500, 'recipient' => 'RCP_bbb', 'reference' => 'inv_2', 'reason' => 'Invoice 2'],
]);
// Verify and fetch
$paystack->transfers()->verifyTransfer('ref_abc123');
$paystack->transfers()->fetchTransfer('TRF_xxx');use Faridibin\Paystack\Enums\RecipientType;
// Create a single recipient
$paystack->recipients()->createRecipient(
type: RecipientType::NUBAN,
name: 'John Doe',
accountNumber: '0123456789',
bankCode: '058',
);
// Bulk recipients
$paystack->recipients()->createBulkRecipients([
['type' => 'nuban', 'name' => 'John Doe', 'account_number' => '0123456789', 'bank_code' => '058'],
['type' => 'nuban', 'name' => 'Jane Smith','account_number' => '0987654321', 'bank_code' => '058'],
]);use Faridibin\Paystack\Enums\PlanInterval;
// Create a plan
$paystack->plans()->create('Pro Monthly', amount: 500000, interval: PlanInterval::MONTHLY);
// Subscribe a customer
$paystack->subscriptions()->create('CUS_xxx', 'PLN_xxx');
// Enable / disable a subscription (token is the email_token from the subscription object)
$paystack->subscriptions()->toggle('SUB_xxx', 'tok_xxx', active: true);
$paystack->subscriptions()->toggle('SUB_xxx', 'tok_xxx', active: false);
// Generate or email a card-update link for the subscription
$paystack->subscriptions()->generateUpdateSubscriptionLink('SUB_xxx');
$paystack->subscriptions()->sendUpdateSubscriptionLink('SUB_xxx');use Faridibin\Paystack\Enums\SplitType;
use Faridibin\Paystack\Enums\Bearer;
use Faridibin\Paystack\Enums\Currency;
$paystack->splits()->createSplit(
name: 'Halfsies',
type: SplitType::PERCENTAGE,
currency: Currency::NGN,
subaccounts: [['subaccount' => 'ACCT_xxx', 'share' => 50]],
bearer: Bearer::SUB_ACCOUNT,
bearerSubaccount: 'ACCT_xxx',
);$paystack->storefront()->create([
'name' => 'My Store',
'slug' => 'my-store',
'description' => 'Curated goods',
'currency' => 'NGN',
]);
$paystack->storefront()->verifySlug('my-store');
$paystack->storefront()->fetch('1');
$paystack->storefront()->update('1', ['name' => 'My New Store']);
$paystack->storefront()->addProducts('1', ['products' => [10, 20]]);
$paystack->storefront()->publish('1');
$paystack->storefront()->duplicate('1');
$paystack->storefront()->fetchOrders('1');
$paystack->storefront()->listProducts('1');
$paystack->storefront()->delete('1');$paystack->order()->create([
'amount' => 50000,
'currency' => 'NGN',
'items' => [['product' => 1, 'quantity' => 2]],
]);
$paystack->order()->list(perPage: 20, page: 1);
$paystack->order()->fetch('ORD_xxx');
$paystack->order()->fetchByProduct('123');
$paystack->order()->validate('ORD_xxx');$paystack->miscellaneous()->listCountries();
$paystack->miscellaneous()->listStates('CA');
$paystack->miscellaneous()->listBanks('nigeria');Use Webhook::validateSignature() and Webhook::isIpWhitelisted() to authenticate incoming Paystack webhooks:
use Faridibin\Paystack\Webhook;
use Faridibin\Paystack\Exceptions\PaystackException;
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PAYSTACK_SIGNATURE'] ?? '';
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
try {
Webhook::isIpWhitelisted($ip);
Webhook::validateSignature($payload, $signature, 'sk_live_...');
$event = json_decode($payload, true);
match ($event['event']) {
'charge.success' => handleChargeSuccess($event['data']),
'transfer.success' => handleTransferSuccess($event['data']),
default => null,
};
http_response_code(200);
} catch (PaystackException $e) {
http_response_code(403);
}Paystack sends webhooks only from these IP addresses:
52.31.139.7552.49.173.16952.214.14.220
composer testMIT