ubitechsolutionsltd / clickpesa-laravel-package
ClickPesa PHP & Laravel SDK for seamless payment collections, disbursements, and webhook handling.
Package info
github.com/ubitechsolutionsltd/clickpesa-laravel-package
Language:HTML
pkg:composer/ubitechsolutionsltd/clickpesa-laravel-package
Requires
- php: ^8.1|^8.2|^8.3
- ext-hash: *
- ext-json: *
- guzzlehttp/guzzle: ^7.5
- illuminate/contracts: ^10.0|^11.0|^12.0|^13.0
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/routing: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0|^10.0|^11.0
- phpunit/phpunit: ^10.0|^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-11-04 11:19:08 UTC
README
ClickPesa PHP & Laravel SDK
Developed & Maintained by UBITECH SOLUTIONS LIMITED
๐ Contact / Support: +255 766 192 332
A modern, robust, and extensible SDK for integrating ClickPesa payment gateway and disbursement APIs into any PHP project, with first-class Laravel integration (Service Provider, Facade, Events, and Webhooks). Includes complete offline reference in documentation.pdf.
Features
- ๐ Two-Layer Decoupled Architecture: Can be used in plain PHP scripts, Symfony, WordPress, or with first-class Laravel integration.
- ๐ Automatic JWT Token Management: Handles
POST /generate-token, transparent in-memory and Laravel Cache persistence, and proactive refresh before the 1-hour expiration. - ๐ก๏ธ Built-in Checksum Engine: Implements ClickPesa's canonicalization algorithm (recursive alphabetical sorting, compact JSON, HMAC-SHA256) for both outgoing request signing and incoming webhook verification.
- ๐ฑ Complete Payment Collections:
- Mobile USSD-PUSH: Preview fees and send push requests to M-Pesa, Tigo-Pesa, Airtel Money, Halopesa.
- Card Payments: Preview fees and initiate card payment sessions.
- Hosted Checkout Links: Generate hosted payment URLs with itemized details or order totals.
- BillPay (Control Numbers): Generate single & bulk control numbers for orders and customers, query details, and update bills.
- CRDB Direct Debit: Request recurring mandate approvals, inspect mandates, and cancel them.
- ๐ธ Instant Disbursements (Payouts):
- Mobile Money (MNO) Payouts: Send payouts directly to mobile wallets with built-in 60s cooldown detection (
RateLimitException). - Bank Payouts: ACH/RTGS transfers with BIC and account verification.
- Lipa Namba / TanQR Payouts: Instant payments to merchant Lipa Namba or TanQR codes.
- Payout Links: Generate hosted disbursement links.
- Mobile Money (MNO) Payouts: Send payouts directly to mobile wallets with built-in 60s cooldown detection (
- ๐ Account & Utilities:
- Live balances across currencies (TZS, USD).
- Account statements.
- Bank BIC directory.
- Real-time exchange rates.
- โก Webhook Processing:
- Typed event objects (
PaymentReceivedEvent,PaymentFailedEvent,PayoutInitiatedEvent, etc.). - Automatic signature verification with timing-attack prevention (
hash_equals). - Native Laravel route macro (
Route::clickpesaWebhooks()) and dispatched Laravel events.
- Typed event objects (
- ๐งช Testing Fakes:
ClickPesa::fake()and assertion methods for effortless unit and feature testing.
Installation
Install the package via Composer:
composer require ubitechsolutionsltd/clickpesa-laravel-package
Laravel Quickstart
1. Configuration & Publishing
In Laravel, the package automatically registers the ClickPesaServiceProvider and ClickPesa Facade via package discovery.
Publish the configuration file:
php artisan vendor:publish --tag=clickpesa-config
Add your ClickPesa API credentials to your .env file:
CLICKPESA_CLIENT_ID=your_client_id_here CLICKPESA_API_KEY=your_api_key_here CLICKPESA_CHECKSUM_KEY=your_checksum_secret_here CLICKPESA_CHECKSUM_ENABLED=true
2. Laravel Usage via Facade
use ClickPesa\Laravel\Facades\ClickPesa; // --- 1. Initiate Mobile USSD-PUSH --- $push = ClickPesa::ussdPush()->initiate([ 'amount' => '10000', 'currency' => 'TZS', 'orderReference' => 'ORDER-1001', 'phoneNumber' => '255712345678', ]); // --- 2. Generate Hosted Checkout Link --- $checkout = ClickPesa::checkoutLinks()->generate([ 'totalPrice' => '25000', 'orderReference' => 'INV-9021', 'orderCurrency' => 'TZS', 'customerName' => 'Mathayo John', 'customerEmail' => 'mathayo@example.com', 'customerPhone' => '255712345678', ]); $redirectUrl = $checkout['checkoutLink']; // --- 3. Query Payment Status --- $attempts = ClickPesa::payments()->get('ORDER-1001'); // --- 4. Send Disbursements (All Payout Types Supported) --- // 4a. Mobile Money Payout (M-Pesa, Airtel, Mixx by Yas, HaloPesa) $mnoPayout = ClickPesa::mobileMoneyPayouts()->create([ 'amount' => 25000, 'currency' => 'TZS', 'phoneNumber' => '255755123456', 'orderReference' => 'PAYOUT-MNO-01', ]); // 4b. Bank Payout (EFT / TISS transfers with BIC) $bankPayout = ClickPesa::bankPayouts()->create([ 'amount' => 500000, 'currency' => 'TZS', 'orderReference' => 'PAYOUT-BNK-01', 'accountNumber' => '0150123456700', 'accountName' => 'Acme Ltd', 'bic' => 'CORUTZTZ', // CRDB Bank BIC ]); // 4c. Merchant Lipa Namba Payout $lnPayout = ClickPesa::lipaNambaPayouts()->create([ 'amount' => 15000, 'currency' => 'TZS', 'orderReference' => 'PAYOUT-LN-01', 'lipaNamba' => '48001268', 'providerCode' => '503', // M-Pesa merchant ]); // 4d. TIPS TanQR Payout (Direct to QR code) $qrPayout = ClickPesa::lipaNambaPayouts()->create([ 'amount' => 30000, 'currency' => 'TZS', 'orderReference' => 'PAYOUT-QR-01', 'qrCode' => '00020101021226...', ]); // 4e. Hosted Payout Link (Payee selects preferred destination) $payoutLink = ClickPesa::payoutLinks()->create([ 'amount' => 100000, 'currency' => 'TZS', 'orderReference' => 'PAYOUT-LINK-01', 'recipientName' => 'Juma Hamisi', ]); $claimUrl = $payoutLink['payoutUrl']; // --- 5. Check Balances & Offline Fee Calculation --- $balances = ClickPesa::balance()->get(); $fee = ClickPesa::fees()->calculateUssdPushFee(15000); // 920 TZS
3. Laravel Webhook Handling
Register the webhook route in your routes/api.php or routes/web.php:
use Illuminate\Support\Facades\Route; // Registers POST /clickpesa/webhooks Route::clickpesaWebhooks('clickpesa/webhooks');
When ClickPesa sends an event callback, the controller verifies the payload checksum and dispatches the corresponding Laravel event:
| Webhook Event | Dispatched Laravel Event |
|---|---|
PAYMENT RECEIVED |
ClickPesa\Laravel\Events\PaymentReceived |
PAYMENT FAILED |
ClickPesa\Laravel\Events\PaymentFailed |
PAYOUT INITIATED |
ClickPesa\Laravel\Events\PayoutInitiated |
PAYOUT REFUNDED |
ClickPesa\Laravel\Events\PayoutRefunded |
PAYOUT REVERSED |
ClickPesa\Laravel\Events\PayoutReversed |
DEPOSIT RECEIVED |
ClickPesa\Laravel\Events\DepositReceived |
Listen to events in your EventServiceProvider or listeners:
use ClickPesa\Laravel\Events\PaymentReceived; use Illuminate\Support\Facades\Event; Event::listen(PaymentReceived::class, function (PaymentReceived $event) { $orderRef = $event->getOrderReference(); $amount = $event->getCollectedAmount(); $paymentRef = $event->getPaymentReference(); // Mark order as paid in your database });
4. Testing with ClickPesa::fake()
You can mock all ClickPesa API calls during your tests:
use ClickPesa\Laravel\Facades\ClickPesa; public function test_user_can_initiate_payment(): void { ClickPesa::fake(); $this->postJson('/api/checkout', ['amount' => 5000]) ->assertOk(); ClickPesa::assertInitiatedUssdPush(function ($data) { return $data['amount'] === '5000'; }); ClickPesa::assertNotSent('/payouts/create-bank-payout'); }
Standalone PHP Usage (Non-Laravel)
You can use the SDK anywhere in PHP without Laravel:
require_once __DIR__ . '/vendor/autoload.php'; use ClickPesa\ClickPesaClient; $client = new ClickPesaClient([ 'client_id' => 'YOUR_CLIENT_ID', 'api_key' => 'YOUR_API_KEY', 'checksum_key' => 'YOUR_CHECKSUM_KEY', // optional 'checksum_enabled' => true, ]); // 1. Preview and Initiate USSD Push $preview = $client->ussdPush()->preview([ 'amount' => '1000', 'currency' => 'TZS', 'orderReference' => 'REF123', 'phoneNumber' => '255712345678', ]); $response = $client->ussdPush()->initiate([ 'amount' => '1000', 'currency' => 'TZS', 'orderReference' => 'REF123', 'phoneNumber' => '255712345678', ]); // 2. Create BillPay Order Control Number $bill = $client->billPay()->createOrder([ 'billDescription' => 'Invoice #1042', 'billAmount' => 45000, 'billReference' => 'INV1042', ]); $controlNumber = $bill['billPayNumber']; // 3. Standalone Webhook Handling use ClickPesa\Webhooks\WebhookHandler; $handler = new WebhookHandler('YOUR_CHECKSUM_KEY'); $event = $handler->handle(file_get_contents('php://input')); if ($event instanceof \ClickPesa\Webhooks\Events\PaymentReceivedEvent) { echo "Payment received: " . $event->getCollectedAmount(); }
Complete API Guide
1. Collections (Payments)
USSD Push
// Preview available telco methods & fees $client->ussdPush()->preview([ 'amount' => '5000', 'currency' => 'TZS', 'orderReference' => 'ORD101', 'phoneNumber' => '255712345678', ]); // Send USSD-Push prompt $client->ussdPush()->initiate([ 'amount' => '5000', 'currency' => 'TZS', 'orderReference' => 'ORD101', 'phoneNumber' => '255712345678', ]);
Card Payments
$client->cardPayments()->initiate([ 'amount' => '50', 'currency' => 'USD', 'orderReference' => 'CARD_01', 'customer' => [ 'fullName' => 'John Doe', 'email' => 'john@example.com', 'phoneNumber' => '255712345678', ], ]);
BillPay Control Numbers
// Create one-time Order Control Number $client->billPay()->createOrder([ 'billDescription' => 'School Fees', 'billAmount' => 150000, 'billReference' => 'SCH901', ]); // Create Customer Control Number $client->billPay()->createCustomer(); // Bulk creation (up to 50 items) $client->billPay()->bulkCreateOrders([ ['billDescription' => 'Bill 1', 'billAmount' => 5000], ['billDescription' => 'Bill 2', 'billAmount' => 10000], ]); // Query details & Update bill $client->billPay()->get('55042914871931'); $client->billPay()->update('55042914871931', ['billAmount' => 180000]);
Payment Status
// Query by Order Reference (returns array of attempts) $attempts = $client->payments()->get('ORDER-101'); // Query all payments with filters $list = $client->payments()->all([ 'status' => 'SUCCESS', 'startDate' => '2026-01-01', 'limit' => 20, ]);
2. Disbursements (Payouts)
ClickPesa supports 5 disbursement channels. All payout endpoints are subject to a 60-second cooldown between payout creations (RateLimitException).
2a. Mobile Money Payout (M-Pesa, Airtel, Mixx by Yas, HaloPesa)
// Step 1: Preview fee and check balance before sending $preview = $client->mobileMoneyPayouts()->preview([ 'amount' => 25000, 'currency' => 'TZS', 'phoneNumber' => '255755123456', 'orderReference' => 'MNO_PAY_01', ]); $fee = $preview['fee']; // e.g., 700 TZS // Step 2: Create mobile money payout $payout = $client->mobileMoneyPayouts()->create([ 'amount' => 25000, 'currency' => 'TZS', 'phoneNumber' => '255755123456', 'orderReference' => 'MNO_PAY_01', ]);
2b. Bank Payout (EFT / ACH vs TISS)
// Step 1: Preview bank payout (verifies BIC and estimated arrival) $preview = $client->bankPayouts()->preview([ 'amount' => 500000, 'currency' => 'TZS', 'accountNumber' => '0150123456700', 'bic' => 'CORUTZTZ', // CRDB Bank BIC 'orderReference'=> 'BANK_PAY_01', ]); // Step 2: Create bank payout // Note: Transfers <= 20M TZS use EFT (fee: 2,360 TZS). Transfers > 20M TZS must use TISS (fee: 11,800 TZS). $payout = $client->bankPayouts()->create([ 'amount' => 500000, 'currency' => 'TZS', 'orderReference'=> 'BANK_PAY_01', 'accountNumber' => '0150123456700', 'accountName' => 'Acme Supplies Ltd', 'bic' => 'CORUTZTZ', 'transferType' => 'ACH', // 'ACH' for EFT, 'RTGS' for TISS ]);
2c. Merchant Lipa Namba Payout
// Retrieve active Lipa Namba providers (e.g., M-Pesa 503, Airtel 502) $providers = $client->lipaNambaPayouts()->providers(); // Preview and create payout to merchant Lipa Namba $payout = $client->lipaNambaPayouts()->create([ 'amount' => 15000, 'currency' => 'TZS', 'orderReference' => 'LN_PAY_01', 'lipaNamba' => '48001268', 'providerCode' => '503', ]);
2d. TIPS TanQR Payout (Direct to QR)
// Payout directly using the merchant's TIPS TanQR code $qrPayout = $client->lipaNambaPayouts()->create([ 'amount' => 30000, 'currency' => 'TZS', 'orderReference' => 'QR_PAY_01', 'qrCode' => '00020101021226...', ]);
2e. Hosted Payout Link
// Generate a hosted payout link where the recipient selects their preferred wallet or bank $link = $client->payoutLinks()->create([ 'amount' => 50000, 'currency' => 'TZS', 'orderReference' => 'LINK_PAY_01', 'recipientName' => 'Baraka Mushi', ]); $claimUrl = $link['payoutUrl'];
2f. Querying Payout Status & Tracking
// Get payout status by Order Reference $status = $client->payouts()->get('MNO_PAY_01'); // Filter & paginate payouts history $history = $client->payouts()->all([ 'status' => 'SUCCESS', 'startDate' => '2026-09-01', 'limit' => 50, ]);
2g. Handling the 60-Second Cooldown
ClickPesa enforces a 60-second cooldown between payout creations:
use ClickPesa\Exceptions\RateLimitException; try { $payout = $client->mobileMoneyPayouts()->create([...]); } catch (RateLimitException $e) { // Cooldown active - wait or queue the next payout job logger()->warning('ClickPesa payout rate limited: ' . $e->getMessage()); }
3. Pricing, Fee Bearers & Offline Fee Calculator
ClickPesa charges different fees depending on the channel and whether the customer or the merchant bears the cost. The SDK provides an instant, offline FeeCalculator so you can estimate and display fees in checkout screens without waiting for API roundtrips.
Fee Bearers Overview
| Channel | Fee Type | Fee Bearer | Notes |
|---|---|---|---|
| USSD Push (M-Pesa, Airtel, Mixx by Yas, HaloPesa) | Tiered slab (54 โ 7,960 TZS) | Customer | Added to the customer's payment at checkout. |
| Card Payments (Visa, Mastercard, UnionPay) | 4.85% | Customer | Added to the customer's payment at checkout. |
| BillPay (M-Pesa & Airtel) | 1.0% | Merchant | Deducted from merchant settlement. |
| BillPay (HaloPesa) | 2.0% | Merchant | Deducted from merchant settlement. |
| BillPay (Mixx by Yas / Tigo) | 2.5% | Merchant | Deducted from merchant settlement. |
| BillPay (CRDB) | 1.0% | Merchant | Deducted from merchant settlement. |
| CRDB Direct Debit | 2,000 TZS flat | Merchant | Charged per successful scheduled debit. |
| TIPS TanQR Collection | 2.0% | Merchant | Deducted from merchant settlement. |
| Mobile Money & TanQR Payouts | Tiered slab (52 โ 9,890 TZS) | Configurable | Merchant can absorb fee OR deduct from payee. |
| Bank EFT Payout | 2,360 TZS flat | Configurable | For transfers $\le$ 20,000,000 TZS. |
| Bank TISS Payout (TZS) | 11,800 TZS flat | Configurable | For transfers up to 1,000,000,000 TZS. |
| Bank TISS Payout (USD) | $7.50 USD flat | Configurable | For transfers up to $1,000,000 USD. |
Offline Fee Calculation Examples
use ClickPesa\Laravel\Facades\ClickPesa; use ClickPesa\Pricing\ChannelLimits; // 1. Calculate USSD Push fee $ussdFee = ClickPesa::fees()->calculateUssdPushFee(15000); // 920.0 TZS // 2. Calculate Card Payment fee $cardFee = ClickPesa::fees()->calculateCardFee(50000); // 2,425.0 TZS (4.85%) // 3. Calculate BillPay fee $mpesaFee = ClickPesa::fees()->calculateBillPayFee('mpesa', 100000); // 1,000.0 TZS (1%) $mixxFee = ClickPesa::fees()->calculateBillPayFee('mixx', 100000); // 2,500.0 TZS (2.5%) // 4. Calculate Net Merchant Settlement (e.g. on 100,000 TZS collection) $net = ClickPesa::fees()->calculateNetSettlement('billpay_mpesa', 100000); // 99,000.0 TZS // 5. Payout Budgeting (Absorb Fee vs Deduct from Recipient) // Option A: Business absorbs fee (payee receives full 50,000 TZS; business wallet debited 51,460 TZS) $budgetA = ClickPesa::fees()->calculatePayoutDeduction('mobile_money', 50000, absorbFee: true); // Option B: Deduct fee from payee (business wallet debited 50,000 TZS; payee receives 48,540 TZS) $budgetB = ClickPesa::fees()->calculatePayoutDeduction('mobile_money', 50000, absorbFee: false); // 6. Pre-Flight Limit Validation (Prevents 400 Bad Request) ChannelLimits::validate('ussd_push', 15000); // Passes // ChannelLimits::validate('ussd_push', 300); // Throws ValidationException: below minimum 500 TZS! // 7. Smart Bank Transfer Method Recommender $method = ChannelLimits::recommendBankTransferMethod(25000000); // Returns 'TISS' (> 20M TZS)
Environment Variables for Custom Pricing
All rates can be overridden in your .env file if ClickPesa updates fees or if custom negotiated rates apply to your account:
# Card percentage fee (default: 4.85) CLICKPESA_FEE_CARD_PERCENT=4.85 # BillPay percentage fees CLICKPESA_FEE_BILLPAY_MPESA_PERCENT=1.0 CLICKPESA_FEE_BILLPAY_AIRTEL_PERCENT=1.0 CLICKPESA_FEE_BILLPAY_HALOPESA_PERCENT=2.0 CLICKPESA_FEE_BILLPAY_MIXX_PERCENT=2.5 CLICKPESA_FEE_BILLPAY_CRDB_PERCENT=1.0 # Flat fees in TZS CLICKPESA_FEE_CRDB_DIRECT_DEBIT=2000 CLICKPESA_FEE_BANK_EFT=2360 CLICKPESA_FEE_BANK_TISS_TZS=11800 CLICKPESA_FEE_BANK_TISS_USD=7.50 # Bank EFT threshold (transfers above this use TISS) CLICKPESA_BANK_EFT_MAX_THRESHOLD=20000000
3. Checksum Verification
To generate or verify checksums directly:
use ClickPesa\Security\Checksum; // Generate $checksum = Checksum::generate($secretKey, $payload); // Timing-safe verification $isValid = Checksum::verify($secretKey, $payload, $receivedChecksum);
Exception Handling
All exceptions extend ClickPesa\Exceptions\ClickPesaException:
use ClickPesa\Exceptions\AuthenticationException; use ClickPesa\Exceptions\ValidationException; use ClickPesa\Exceptions\RateLimitException; use ClickPesa\Exceptions\ConflictException; use ClickPesa\Exceptions\NotFoundException; try { ClickPesa::mobileMoneyPayouts()->create([...]); } catch (RateLimitException $e) { // 60-second payout cooldown echo "Retry after: " . $e->getRetryAfterSeconds() . " seconds"; } catch (ValidationException $e) { echo "Invalid data: " . $e->getMessage(); } catch (ConflictException $e) { echo "Order reference already used: " . $e->getMessage(); } catch (AuthenticationException $e) { echo "Auth error: " . $e->getMessage(); }
Testing
Run the test suite using PHPUnit:
composer test
Or directly:
vendor/bin/phpunit
Authors & Support
This SDK is developed and maintained by UBITECH SOLUTIONS LIMITED.
- Organization: UBITECH SOLUTIONS LIMITED
- GitHub: github.com/ubitechsolutionsltd
- Phone / Support: +255 766 192 332
- Offline PDF Manual: documentation.pdf
Security
If you discover any security issues with this package, please contact security@clickpesa.com or reach out to UBITECH SOLUTIONS (+255 766 192 332).
License
The MIT License (MIT). Please see License File for more information.
