paynecta / paynecta-laravel-sdk
Official Laravel SDK for Paynecta Payment API - Simplify M-Pesa, Bank, and Wallet payment integrations in Kenya
Installs: 20
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/paynecta/paynecta-laravel-sdk
Requires
- php: ^8.2|^8.3
- guzzlehttp/guzzle: ^7.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
README
Official Laravel SDK for Paynecta Payment API - Simplify M-Pesa, Bank, and Wallet payment integrations in Kenya.
Features
- 🚀 Easy Integration - Get started in minutes with simple configuration
- 💳 M-Pesa STK Push - Trigger payment prompts directly on customer phones
- 💰 Payment Links - Create and manage shareable payment pages
- 🏦 Bank Integration - Access all available banks and their paybill numbers
- 🔔 Real-time Webhooks - Instant notifications for payment events
- 🛡️ Secure Authentication - API key and email-based authentication
- 📝 Comprehensive Logging - Debug with detailed request/response logs
- ⚡ Exception Handling - Graceful error handling with specific exceptions
- 🎯 Laravel Events - Native Laravel event system for webhooks
Requirements
- PHP 8.1 or higher
- Laravel 10.x or 11.x
- Guzzle HTTP Client 7.x
Installation
Install the package via Composer:
composer require paynecta/paynecta-laravel-sdk
Publish Configuration
Publish the configuration file to customize settings:
php artisan vendor:publish --tag=paynecta-config
This will create a config/paynecta.php file in your Laravel application.
Environment Configuration
Add your Paynecta credentials to your .env file:
PAYNECTA_API_KEY=your_api_key_here PAYNECTA_EMAIL=your-email@example.com PAYNECTA_LOGGING=false
⚠️ Security Note: Never commit your API credentials to version control. Always use environment variables.
Getting Your API Credentials
- Log in to your Paynecta Dashboard
- Navigate to
/apisection - Click "Create New API Key"
- Copy your API key immediately (it's shown only once!)
- Store it securely in your
.envfile
Quick Start
Verify Authentication
Test your credentials and retrieve user information:
use Paynecta\LaravelSdk\Facades\Paynecta; try { $user = Paynecta::verifyAuth(); echo "Authentication successful!"; echo "User: " . $user['data']['email']; } catch (\Paynecta\LaravelSdk\Exceptions\AuthenticationException $e) { echo "Authentication failed: " . $e->getMessage(); }
Usage Guide
1. Payment Links
use Paynecta\LaravelSdk\Facades\Paynecta; // Get all payment links $links = Paynecta::paymentLinks()->getAll(); // Get specific link $link = Paynecta::paymentLinks()->get('ABC123'); // Get only invoices $invoices = Paynecta::paymentLinks()->getInvoices(); // Search links $results = Paynecta::paymentLinks()->search('subscription'); // Count total links $count = Paynecta::paymentLinks()->count();
2. Initialize Payments (M-Pesa STK Push)
use Paynecta\LaravelSdk\Facades\Paynecta; // Initialize payment $payment = Paynecta::payments()->initialize( 'ABC123', // Payment link code '254700000000', // Mobile number 100 // Amount in KES (1-250,000) ); // With validation $payment = Paynecta::payments()->initializeWithValidation( 'ABC123', '0700000000', // Accepts 07XX format 500 ); // Get transaction reference $reference = Paynecta::payments()->getTransactionReference($payment); echo "Transaction Reference: {$reference}";
3. Query Payment Status
use Paynecta\LaravelSdk\Facades\Paynecta; // Query status $status = Paynecta::payments()->queryStatus('ABCP20240803123456ABCD'); // Check status if (Paynecta::payments()->isCompleted($status)) { $receipt = Paynecta::payments()->getMpesaReceiptNumber($status); echo "Payment completed! Receipt: {$receipt}"; } if (Paynecta::payments()->isFailed($status)) { $reason = Paynecta::payments()->getFailureReason($status); echo "Payment failed: {$reason}"; } // Poll until complete (checks every 2 seconds, max 30 attempts) $finalStatus = Paynecta::payments()->pollStatus($reference, 30, 2);
4. Currency Rates
use Paynecta\LaravelSdk\Facades\Paynecta; // Get all currency rates (160+ currencies) $rates = Paynecta::currencyRates()->getAll(); // Get specific currency rate $usdRate = Paynecta::currencyRates()->get('USD'); // Convert currency $converted = Paynecta::currencyRates()->convert(100, 'USD', 'KES'); // Convert with specific date $converted = Paynecta::currencyRates()->convert(100, 'USD', 'KES', '2025-10-01'); // Get historical rates $history = Paynecta::currencyRates()->getHistory('KES', 'USD', '2025-10-01', '2025-10-13'); // Helper methods $rate = Paynecta::currencyRates()->getRate($usdRate); $amount = Paynecta::currencyRates()->getConvertedAmount($converted); $allRates = Paynecta::currencyRates()->getRates($rates);
5. Banks
use Paynecta\LaravelSdk\Facades\Paynecta; // Get all banks $banks = Paynecta::banks()->getAll(); // Get specific bank $bank = Paynecta::banks()->get('jR3kL9'); // Search banks $results = Paynecta::banks()->search('equity'); // Find by name $kcb = Paynecta::banks()->findByName('KCB Bank'); // Find by paybill $bank = Paynecta::banks()->findByPaybill('247247'); // For dropdowns (returns bank_id => bank_name) $options = Paynecta::banks()->getForDropdown(); // Simple list (returns bank_name => paybill_number) $list = Paynecta::banks()->getAllAsList(); // Grouped by first letter $grouped = Paynecta::banks()->getGroupedByLetter();
6. Webhooks
Setup Webhook URL
Your webhook URL will be automatically registered at:
https://yourdomain.com/paynecta/webhook
Add to your dashboard at: https://paynecta.co.ke
Whitelist Webhook Route (Important!)
Add to app/Http/Middleware/VerifyCsrfToken.php:
protected $except = [ 'paynecta/webhook', ];
Listen to Webhook Events
Create event listeners:
php artisan make:listener HandlePaymentCompleted
In app/Listeners/HandlePaymentCompleted.php:
<?php namespace App\Listeners; use Paynecta\LaravelSdk\Events\PaymentCompletedEvent; use Illuminate\Contracts\Queue\ShouldQueue; class HandlePaymentCompleted implements ShouldQueue { public function handle(PaymentCompletedEvent $event) { // Access payment data $reference = $event->transactionReference; $amount = $event->amount; $receipt = $event->mpesaReceiptNumber; $mobile = $event->mobileNumber; // Update database \DB::table('payments') ->where('transaction_reference', $reference) ->update([ 'status' => 'completed', 'mpesa_receipt' => $receipt, 'paid_at' => now() ]); // Send confirmation, fulfill order, etc. } }
Register in app/Providers/EventServiceProvider.php:
use Paynecta\LaravelSdk\Events\PaymentCompletedEvent; use Paynecta\LaravelSdk\Events\PaymentFailedEvent; use Paynecta\LaravelSdk\Events\PaymentCancelledEvent; protected $listen = [ PaymentCompletedEvent::class => [ HandlePaymentCompleted::class, ], PaymentFailedEvent::class => [ HandlePaymentFailed::class, ], PaymentCancelledEvent::class => [ HandlePaymentCancelled::class, ], ];
Complete Payment Flow Example
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Paynecta\LaravelSdk\Facades\Paynecta; use App\Models\Order; class CheckoutController extends Controller { public function initiatePayment(Request $request) { $validated = $request->validate([ 'order_id' => 'required|exists:orders,id', 'mobile_number' => 'required|string', ]); $order = Order::findOrFail($validated['order_id']); try { // Initialize payment $payment = Paynecta::payments()->initializeWithValidation( 'YOUR_LINK_CODE', $validated['mobile_number'], $order->total_amount ); $reference = Paynecta::payments()->getTransactionReference($payment); // Save transaction reference $order->update([ 'transaction_reference' => $reference, 'payment_status' => 'pending' ]); return response()->json([ 'success' => true, 'message' => 'Check your phone for STK push', 'transaction_reference' => $reference ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => $e->getMessage() ], 400); } } public function checkStatus($reference) { try { $status = Paynecta::payments()->queryStatus($reference); return response()->json([ 'success' => true, 'status' => Paynecta::payments()->getStatus($status), 'is_completed' => Paynecta::payments()->isCompleted($status), 'mpesa_receipt' => Paynecta::payments()->getMpesaReceiptNumber($status), ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => $e->getMessage() ], 404); } } }
Configuration Options
The package uses the following configuration options (in config/paynecta.php):
return [ // API credentials 'api_key' => env('PAYNECTA_API_KEY'), 'email' => env('PAYNECTA_EMAIL'), // API endpoint 'base_url' => env('PAYNECTA_BASE_URL', 'https://paynecta.co.ke/api/v1'), // Request timeout in seconds 'timeout' => env('PAYNECTA_TIMEOUT', 30), // Enable logging for debugging 'logging' => env('PAYNECTA_LOGGING', false), // Log channel 'log_channel' => env('PAYNECTA_LOG_CHANNEL', 'stack'), // Webhook settings 'webhook_path' => env('PAYNECTA_WEBHOOK_PATH', 'paynecta/webhook'), 'webhook_duplicate_detection' => env('PAYNECTA_WEBHOOK_DUPLICATE_DETECTION', true), 'webhook_middleware' => ['api'], ];
Advanced Usage
Dependency Injection
use Paynecta\LaravelSdk\PaynectaClient; class PaymentController extends Controller { public function __construct( protected PaynectaClient $paynecta ) {} public function processPayment() { $user = $this->paynecta->verifyAuth(); $links = $this->paynecta->paymentLinks()->getAll(); } }
Custom Timeout
$user = Paynecta::setTimeout(60)->verifyAuth();
Enable Logging
// In .env PAYNECTA_LOGGING=true // Or programmatically Paynecta::setLogging(true)->verifyAuth();
Custom Base URL (Testing)
Paynecta::setBaseUrl('https://sandbox.paynecta.co.ke/api/v1');
Exception Handling
The SDK throws specific exceptions for different error types:
use Paynecta\LaravelSdk\Exceptions\AuthenticationException; use Paynecta\LaravelSdk\Exceptions\ValidationException; use Paynecta\LaravelSdk\Exceptions\NotFoundException; use Paynecta\LaravelSdk\Exceptions\RateLimitException; use Paynecta\LaravelSdk\Exceptions\PaynectaException; try { $result = Paynecta::payments()->initialize('ABC123', '254700000000', 100); } catch (AuthenticationException $e) { // Invalid API key or email (401) $errorCode = $e->getErrorCode(); $responseBody = $e->getResponseBody(); } catch (ValidationException $e) { // Invalid request data (400) $errors = $e->getResponseBody()['errors'] ?? []; } catch (NotFoundException $e) { // Resource not found (404) } catch (RateLimitException $e) { // Too many requests (429) } catch (PaynectaException $e) { // Any other Paynecta error } catch (\Exception $e) { // Network or other errors }
Exception Methods
All Paynecta exceptions provide these methods:
$exception->getMessage(); // Human-readable error message $exception->getCode(); // HTTP status code $exception->getErrorCode(); // API-specific error code $exception->getResponseBody(); // Full API response body $exception->hasErrorCode(); // Check if error code exists
Testing
Testing Webhooks Locally
Use ngrok to expose your local server:
ngrok http 8000
Copy the HTTPS URL and add to your Paynecta dashboard:
https://abc123.ngrok.io/paynecta/webhook
Manual Testing
Route::get('/test-payment', function () { try { // Test authentication $user = Paynecta::verifyAuth(); echo "✓ Authentication successful\n"; // Test payment links $links = Paynecta::paymentLinks()->getAll(); echo "✓ Found {$links['data']['total']} payment links\n"; // Test banks $banks = Paynecta::banks()->getAll(); echo "✓ Found {$banks['data']['total']} banks\n"; return 'All tests passed!'; } catch (\Exception $e) { return "Error: " . $e->getMessage(); } });
API Reference
Authentication
verifyAuth()- Verify API credentials and get user info
Payment Links
paymentLinks()->getAll()- Get all payment linkspaymentLinks()->get($code)- Get specific linkpaymentLinks()->getInvoices()- Get invoice links onlypaymentLinks()->getRegularLinks()- Get non-invoice linkspaymentLinks()->search($term)- Search linkspaymentLinks()->count()- Get total count
Payments
payments()->initialize($code, $mobile, $amount)- Initialize STK pushpayments()->initializeWithValidation($code, $mobile, $amount)- Initialize with validationpayments()->queryStatus($reference)- Query payment statuspayments()->pollStatus($reference, $maxAttempts, $sleepSeconds)- Poll until completepayments()->isCompleted($response)- Check if completedpayments()->isPending($response)- Check if pendingpayments()->isFailed($response)- Check if failedpayments()->getMpesaReceiptNumber($response)- Get receipt numberpayments()->getFailureReason($response)- Get failure reason
Banks
banks()->getAll()- Get all banksbanks()->get($bankId)- Get specific bankbanks()->search($term)- Search banksbanks()->findByName($name)- Find by exact namebanks()->findByPaybill($paybill)- Find by paybill numberbanks()->getForDropdown()- Get for select dropdownbanks()->getAllAsList()- Get as simple listbanks()->getGroupedByLetter()- Get grouped by first letter
Currency Rates
currencyRates()->getAll()- Get all currency rates (160+ currencies)currencyRates()->get($currency)- Get specific currency ratecurrencyRates()->convert($amount, $from, $to, $date)- Convert currency amountscurrencyRates()->getHistory($from, $to, $startDate, $endDate)- Get historical ratescurrencyRates()->getRate($response)- Extract rate from responsecurrencyRates()->getConvertedAmount($response)- Extract converted amountcurrencyRates()->getRates($response)- Extract rates array
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security-related issues, please email hello@paynecta.co.ke instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.
Support
- 📧 Email: hello@paynecta.co.ke
- 🌐 Website: https://paynecta.co.ke
- 📖 Documentation: https://paynecta.co.ke/docs
- 💬 Support: https://paynecta.co.ke/support
Made with ❤️ by Paynecta