webmobyle / paychangu-payments
Drop-in Paychangu payments for Laravel with Card, Mobile Money and Bank payment options
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.8
- illuminate/support: ^10|^11|^12
- nesbot/carbon: ^2.72|^3.8
README
A clean, modern Laravel integration for Paychangu that supports hosted checkout, mobile money, card payments, webhook verification, and flexible payment recording.
This package is designed to be simple, extensible, and production-ready โ modeled after the structure of the webmobyle/dpo-payments package.
๐ Features
- Paychangu Hosted Checkout support
- Card and Mobile Money payment methods
- Automatic creation & tracking of
PaychanguChargerecords - Webhook verification with HMAC-SHA256
- Configurable
callback_urlandreturn_url - Elegant, Laravel-native API
- Laravel 10/11/12 support
See CHANGELOG.md for release history.
๐ฆ Installation
Install via Composer:
composer require webmobyle/paychangu-payments
Publish the configuration and migrations:
php artisan vendor:publish --provider="Webmobyle\PaychanguPayments\PaychanguPaymentsServiceProvider" --tag=paychangu-config
php artisan vendor:publish --provider="Webmobyle\PaychanguPayments\PaychanguPaymentsServiceProvider" --tag=paychangu-migrations
Run migrations:
php artisan migrate
โ๏ธ Configuration
Add these keys to your .env:
PAYCHANGU_PUBLIC_KEY=pub-xxx
PAYCHANGU_SECRET_KEY=sec-xxx
# For browser redirect after checkout
PAYCHANGU_RETURN_URL=https://your-domain.com/paychangu/callback
# For retun in case of cacellation or failure
PAYCHANGU_RETURN_URL=https://your-domain.com/paychangu/return
# For webhooks (server-to-server)
PAYCHANGU_CALLBACK_URL=https://your-domain.com/paychangu/webhook
# Webhook signature verification
PAYCHANGU_WEBHOOK_SECRET=your_webhook_secret_here
PAYCHANGU_CURRENCY=MWK
๐งฉ How It Works
Initiate a Payment
use Webmobyle\PaychanguPayments\PaychanguService;
public function createOrder()
{
$order = Order::create([
'order_number' => 'TST-'.now()->format('YmdHis'),
'total_amount' => 10000,
'email' => 'customer@example.com',
]);
$paychangu = app(PaychanguService::class);
$response = $paychangu->initiate(
payable: $order,
amount: $order->total_amount,
customer: [
'email' => $order->email,
'first_name' => 'John',
'last_name' => 'Mzoma',
],
description: "Payment for Order #{$order->order_number}"
);
return redirect($response['checkout_url']);
}
Add the payments trait to your payable model
For example, App\Models\Order:
use Webmobyle\PaychanguPayments\Traits\HasPaychanguPayments;
class Order extends Model
{
use HasPaychanguPayments;
// ...
}
Sample Order Table Migration
public function up(): void
{
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->string('order_number')->unique();
$table->unsignedBigInteger('total_amount'); // store in MWK
$table->enum('payment_status', ['PENDING', 'PAID'])->default('PENDING');
$table->timestamp('paid_at')->nullable();
$table->timestamps();
});
}
If you want to customize the look of the results page in a given project
php artisan vendor:publish --provider="Webmobyle\PaychanguPayments\PaychanguPaymentsServiceProvider" --tag=paychangu-views
Then in your app, you can listen for this event to update orders, wallets, etc.
Listener in your app
<?php
namespace App\Listeners;
use Webmobyle\PaychanguPayments\Events\PaychanguPaymentVerified;
class MarkOrderPaidFromPaychangu
{
public function handle(PaychanguPaymentVerified $event): void
{
$charge = $event->charge;
$payable = $charge->payable;
// Only handle for Order model, ignore others
if (! $payable instanceof \App\Models\Order) {
return;
}
if ($charge->isSuccessful()) {
// Your custom logic. Example:
if ($payable->payment_status !== 'PAID') {
$payable->payment_status = 'PAID';
$payable->paid_at = now();
$payable->save();
}
}
}
}
Register in EventServiceProvider
In app/Providers/EventServiceProvider.php:
protected $listen = [
\Webmobyle\PaychanguPayments\Events\PaychanguPaymentVerified::class => [
\App\Listeners\MarkOrderPaidFromPaychangu::class,
],
];
Like so;
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* @var array<class-string, array<int, class-string>>
*/
protected $listen = [
\Webmobyle\PaychanguPayments\Events\PaychanguPaymentVerified::class => [
\App\Listeners\MarkOrderPaidFromPaychangu::class,
],
];
/**
* Register services.
*/
public function register(): void
{
//
}
/**
* Bootstrap services.
*/
public function boot(): void
{
//
}
}
๐ Callback (Browser Redirect)
Handled automatically by the package.
Route:
/paychangu/callback
โฌ ๏ธ Return (Browser Redirect)
Implement this route and view for situations where the user cancels or there a is failure.
Route:
/paychangu/return
๐ก Webhook Handling
Handled automatically by the package.
Webhook endpoint:
POST /paychangu/webhook
The package:
- Verifies signature
- Re-verifies the transaction via Paychangu API
- Updates the charge
- Fires an event
๐งพ Events
PaychanguPaymentVerified
Triggered when a payment is successfully verified.
๐ Model: PaychanguCharge
Tracks all payment attempts and confirmations.
This model conects to a `mysqldatabase connection by default. To modify this behaviour add the following configuration key in theconfig/database.php` file.
'paychangu_connection' => env('PAYCHANGU_DB_CONNECTION', 'mysql'),
๐งฑ Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.2 |
| Laravel | 10.x - 12.x |
| GuzzleHTTP | ^7.8 |
๐ฆ Versioning
This package follows Semantic Versioning (SemVer) โ tag releases like v1.0.0, v1.1.0, etc.
๐ชช License
This package is open-sourced software licensed under the MIT License.
๐ค Author
Barnett Temwa Msiska
Founder, Webmobyle Limited
๐ง barnett@webmobyle.com
โญ Support
If you find this package useful, please star it on Packagist or Bitbucket.
Contributions, pull requests, and issues are welcome!
Email: contact@webmobyle.com