kpay / laravel-kpay
Laravel 12 package for integrating with the K-Pay payment gateway.
Requires
- php: ^8.2
- illuminate/http: ^12.0
- illuminate/routing: ^12.0
- illuminate/support: ^12.0
Requires (Dev)
- laravel/pint: ^1.26
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.0
- rector/rector: ^2.2
This package is auto-updated.
Last update: 2026-05-06 04:46:55 UTC
README
Laravel 12 package for integrating with the K-Pay payment gateway.
Based on the official K-Pay API documentation: https://developers.kpay.africa/documentation.php
Installation
Require the package via Composer:
composer require kpay/laravel-kpay
Publish the config:
php artisan vendor:publish --tag=kpay-config
Configuration
Set these environment variables:
KPAY_BASE_URL=https://pay.esicia.com/ KPAY_API_KEY=your_api_key KPAY_USERNAME=your_username KPAY_PASSWORD=your_password KPAY_RETAILER_ID=YOUR_RETAILER_ID KPAY_RETURL=https://your-app.com/kpay/callback KPAY_REDIRECTURL=https://your-app.com/payment/return KPAY_CURRENCY=RWF
Usage
Initiate a payment
use KPay; use KPay\LaravelKPay\Enums\PaymentMethod; $result = KPay::pay([ 'msisdn' => '250783300000', 'email' => 'customer@example.com', 'details' => 'Order #12345', 'refid' => 'ORDER123456789', 'amount' => 5000, 'cname' => 'John Doe', 'cnumber' => 'CUST001', 'pmethod' => PaymentMethod::Momo, // or 'momo', 'cc', 'spenn' ]); // If success == 1, redirect user to $result['url']
Payment method amount limits (RWF)
| Method | pmethod |
Minimum | Maximum |
|---|---|---|---|
| Mobile Money (MTN / Airtel) | momo |
100 | 5,000,000 |
| Credit / Debit Card | cc |
1,000 | 10,000,000 |
| SPENN wallet | spenn |
100 | 1,000,000 |
Check payment status
use KPay; $status = KPay::checkStatus('ORDER123456789'); // statusid: '01' (success), '02' (failed), '03' (pending)
Webhook (Callback)
By default the package registers:
POST /kpay/callback
K-Pay sends a POST to your callback URL and requires the endpoint to respond:
{ "tid": "...", "refid": "...", "reply": "OK" }
The controller dispatches events based on statusid. K-Pay callbacks only send 01 (success) or 02 (failed); 03 (pending) is only returned by checkStatus.
statusid |
Event dispatched |
|---|---|
01 |
KPay\LaravelKPay\Events\PaymentSucceeded |
02 |
KPay\LaravelKPay\Events\PaymentFailed |
03 |
KPay\LaravelKPay\Events\PaymentPending |
Each event exposes typed properties alongside the raw $payload array:
use KPay\LaravelKPay\Events\PaymentSucceeded; // In your listener: public function handle(PaymentSucceeded $event): void { $event->tid; // K-Pay transaction ID $event->refid; // your merchant reference $event->statusid; // '01' $event->statusdesc; // human-readable status $event->payaccount; // mobile/card account used $event->payload; // full raw payload array }
To customize the path or middleware:
KPAY_CALLBACK_PATH=kpay/callback KPAY_CALLBACK_MIDDLEWARE=api KPAY_CALLBACK_ENABLED=true
Enums
use KPay\LaravelKPay\Enums\PaymentMethod; use KPay\LaravelKPay\Enums\PaymentStatus; PaymentMethod::Momo->value; // 'momo' PaymentMethod::Card->value; // 'cc' PaymentMethod::Spenn->value; // 'spenn' PaymentStatus::Succeeded->value; // '01' PaymentStatus::Failed->value; // '02' PaymentStatus::Pending->value; // '03'
Error handling
The package throws typed exceptions you can catch:
use KPay\LaravelKPay\Exceptions\KPayApiException; use KPay\LaravelKPay\Exceptions\KPayException; try { $result = KPay::pay([...]); } catch (KPayApiException $e) { // API-level error returned by K-Pay $e->retcode; // e.g. 604 $e->reply; // e.g. 'DUPLICATE_REFID' } catch (\InvalidArgumentException $e) { // Validation failure (missing field, invalid pmethod, amount out of range) } catch (KPayException $e) { // Any other package exception }
K-Pay API error codes
retcode |
reply |
Description |
|---|---|---|
| 0 | PENDING | Payment initiated successfully |
| 600 | INVALID_REQUEST | Missing or invalid parameters |
| 601 | INVALID_API_KEY | API key inactive or not found |
| 602 | INVALID_AUTH | Authentication credentials invalid |
| 603 | IP_NOT_WHITELISTED | Unauthorized IP address |
| 604 | DUPLICATE_REFID | Reference ID already processed |
| 605 | AMOUNT_OUT_OF_RANGE | Amount outside allowed limits |
| 606 | TARGET_AUTHORIZATION_ERROR | Provider rejected transaction |
| 607 | INSUFFICIENT_FUNDS | Insufficient customer balance |
| 608 | TIMEOUT | Transaction timed out |
| 609 | CANCELLED | Customer cancelled |
Testing
composer test
Contributing
Please follow our commit message convention (Conventional Commits). See CONTRIBUTING.md.
License
MIT