paynexus / laravel-paynexus
Accept payments through PayNexus on your Laravel website. Supports M-Pesa STK Push, payment pages, webhooks, and optional Filament admin panel integration.
Requires
- php: ^8.2
- illuminate/http: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
Suggests
- filament/filament: Optional: For admin panel integration with resources and widgets (^3.0|^5.0)
README
Accept payments through PayNexus on your Laravel website. Supports M-Pesa STK Push, embeddable payment pages, webhooks, and optional Filament admin panel integration.
Installation
composer require paynexus/laravel-paynexus
Core Installation (Without Filament)
-
Install the package:
composer require paynexus/laravel-paynexus
-
Publish the configuration:
php artisan vendor:publish --tag=paynexus-config
-
Set your API credentials in
.env:PAYNEXUS_SECRET_KEY=sk_your_secret_key_here PAYNEXUS_WEBHOOK_SECRET=whsec_your_webhook_secret PAYNEXUS_BASE_URL=https://paynexus.co.ke/api PAYNEXUS_CURRENCY=KES
Where to get these credentials:
- Secret Key: From PayNexus Dashboard → API Keys (sk_...)
- Webhook Secret: From PayNexus Dashboard → Webhooks → Generate webhook secret
- Dashboard URL: https://paynexus.co.ke/merchant/login
-
Publish migrations (optional):
php artisan vendor:publish --tag=paynexus-migrations php artisan migrate
Filament Integration (Optional)
If you use Filament and want admin panel integration:
-
Install Filament (if not already installed):
composer require filament/filament
-
Enable Filament integration in your
.env:PAYNEXUS_FILAMENT_ENABLED=true
-
Register the plugin in your PanelProvider:
// In your Filament PanelProvider ->plugins([ \PayNexus\Filament\PayNexusPlugin::make(), ])
This adds:
- Payments Resource — View and manage payments in your admin panel
- Revenue Widget — Dashboard chart showing payment trends
- Payment Stats Widget — Quick overview stats
Configuration Options
Basic Configuration
| Option | Environment Variable | Default | Description |
|---|---|---|---|
| Secret Key | PAYNEXUS_SECRET_KEY |
- | Your PayNexus secret key (sk_...) |
| Base URL | PAYNEXUS_BASE_URL |
https://paynexus.co.ke/api |
PayNexus API base URL |
| Currency | PAYNEXUS_CURRENCY |
KES |
Default currency |
| Webhook Secret | PAYNEXUS_WEBHOOK_SECRET |
- | Webhook signature secret |
| Log Channel | PAYNEXUS_LOG_CHANNEL |
null |
Custom log channel |
Filament Configuration
| Option | Environment Variable | Default | Description |
|---|---|---|---|
| Filament Enabled | PAYNEXUS_FILAMENT_ENABLED |
false |
Enable Filament integration |
| Navigation Group | PAYNEXUS_FILAMENT_GROUP |
PayNexus |
Admin panel navigation group |
| Auto Register | PAYNEXUS_FILAMENT_AUTO_REGISTER |
true |
Auto-register resources/widgets |
Quick Start
Initiate an M-Pesa Payment
use PayNexus\Facades\PayNexus; // Step 1: Get payment accounts to determine account type $accountsResponse = PayNexus::getPaymentAccounts(); if (!$accountsResponse['success']) { // Handle error throw new Exception('Failed to get payment accounts: ' . $accountsResponse['message']); } $mpesaAccount = null; foreach ($accountsResponse['data'] as $account) { if ($account['provider'] === 'mpesa') { $mpesaAccount = $account; break; } } if (!$mpesaAccount) { throw new Exception('No M-Pesa payment account found'); } // Step 2: Validate phone number $phoneValidation = PayNexus::validatePhone('0746990866'); if (!$phoneValidation['success'] || !$phoneValidation['data']['valid']) { throw new Exception('Invalid phone number'); } $normalizedPhone = $phoneValidation['data']['normalized']; // Step 3: Determine account reference based on account type if ($mpesaAccount['type'] === 'paybill') { $accountReference = $mpesaAccount['account_number']; } elseif ($mpesaAccount['type'] === 'till') { $accountReference = 'ORDER_' . time(); } // Step 4: Initiate payment $result = PayNexus::pay([ 'payment_account_id' => $mpesaAccount['id'], 'amount' => 1000, 'phone' => $normalizedPhone, 'account_reference' => $accountReference, 'description' => 'Order #12345', ]); if ($result['success']) { // STK push sent — $result['data']['checkout_request_id'] }
Check Payment Status
$status = PayNexus::status($checkoutRequestId); // $status['status'] => 'completed', 'pending', 'failed'
Embedded Payment Page
Generate a hosted payment page URL:
$url = PayNexus::paymentPage([ 'amount' => 500, 'title' => 'Premium Subscription', 'description' => 'Monthly plan', 'customer_name' => 'John Doe', 'customer_email' => 'john@example.com', 'success_url' => route('payment.success'), 'cancel_url' => route('payment.cancel'), ]); return redirect($url);
Webhooks
The package registers a webhook route at /paynexus/webhook automatically. Implement listeners for payment events:
// In EventServiceProvider use PayNexus\Events\PaymentCompleted; use PayNexus\Events\PaymentFailed; protected $listen = [ PaymentCompleted::class => [ \App\Listeners\HandlePaymentSuccess::class, ], PaymentFailed::class => [ \App\Listeners\HandlePaymentFailure::class, ], ];
Blade Components
<!-- Payment Button --> <x-paynexus::pay-button :amount="1000" phone="254746990866" description="Order Payment" reference="ORD-123" class="bg-blue-500 text-white px-6 py-3 rounded-lg" > Pay KES 1,000 </x-paynexus::pay-button>
Filament Integration (Optional)
If your project uses Filament, the package provides optional resources and widgets:
// In your Filament PanelProvider ->plugins([ \PayNexus\Filament\PayNexusPlugin::make(), ])
This adds:
- Payments Resource — View and manage payments in your admin panel
- Revenue Widget — Dashboard chart showing payment trends
- Payment Stats Widget — Quick overview stats
API Reference
PayNexus::getPaymentAccounts(): array
Get available payment accounts from your merchant dashboard.
PayNexus::validatePhone(string $phone): array
Validate and normalize a phone number.
| Parameter | Type | Required | Description |
|---|---|---|---|
| phone | string | Yes | Phone number to validate |
PayNexus::pay(array $data): array
Initiate an M-Pesa STK Push payment.
| Parameter | Type | Required | Description |
|---|---|---|---|
| payment_account_id | string | Yes | Payment account ID from getPaymentAccounts() |
| amount | float | Yes | Payment amount |
| phone | string | Yes | Normalized phone number |
| account_reference | string | Yes | Account reference (paybill number or order ID) |
| description | string | No | Payment description |
| remark | string | No | Payment remark |
PayNexus::status(string $checkoutRequestId): array
Check payment status by checkout request ID.
PayNexus::paymentPage(array $data): string
Generate a hosted payment page URL.
PayNexus::transactions(array $filters): array
List transactions with optional filters.
Events
| Event | Description |
|---|---|
PayNexus\Events\PaymentCompleted |
Fired when a payment succeeds |
PayNexus\Events\PaymentFailed |
Fired when a payment fails |
Troubleshooting
Common Issues
-
"PayNexus configuration key 'secret_key' is required"
- Ensure you've set
PAYNEXUS_SECRET_KEYin your.envfile - Make sure the secret key starts with
sk_ - Run
php artisan config:clearafter updating environment variables
- Ensure you've set
-
"Connection error: Unable to reach PayNexus API"
- Check your internet connection
- Verify
PAYNEXUS_BASE_URLis correct - Ensure your API keys are valid
-
Filament resources not showing
- Set
PAYNEXUS_FILAMENT_ENABLED=truein your.env - Ensure you've registered the plugin in your PanelProvider
- Clear caches:
php artisan config:clear && php artisan filament:cache
- Set
-
Webhook signature verification failing
- Ensure
PAYNEXUS_WEBHOOK_SECRETmatches your PayNexus dashboard settings - Check that your webhook URL is accessible from the internet
- Ensure
Debug Mode
To enable debug logging, set a log channel:
PAYNEXUS_LOG_CHANNEL=paynexus
Then configure the channel in config/logging.php.
Upgrade Guide
From v1.x to v2.x
- Refund functionality removed - If you were using refund methods, they are no longer available
- Filament integration is now opt-in - You must explicitly enable it in configuration
- Better error handling - Error messages are now more descriptive
- Configuration validation - Invalid configurations will throw exceptions during registration
License
MIT