sabitahmad/laravel-bkash
Integrate bKash payments in Laravel (API v1.2.0) with tokenized and regular checkout, sandbox/production switching, auto token refresh, payment and agreement operations (create/execute/query/refund/search), transaction logging, retries, and validation.
Installation:
composer require sabitahmad/laravel-bkash
php artisan vendor:publish --tag="laravel-bkash-migrations"
php artisan vendor:publish --tag="laravel-bkash-config"
php artisan migrate
Environment Setup:
Add these to .env:
BKASH_SANDBOX=true
BKASH_APP_KEY=your_app_key
BKASH_APP_SECRET=your_app_secret
BKASH_USERNAME=your_username
BKASH_PASSWORD=your_password
BKASH_CALLBACK_URL=/bkash/callback
First Use Case: Initiate a payment in a controller:
use SabitAhmad\Bkash\Facades\Bkash;
$payment = Bkash::createPayment(
payerReference: 'CUST-1001',
amount: 100.50,
invoiceNumber: 'INV-1001'
);
if ($payment->isSuccess()) {
return redirect()->away($payment->getPaymentUrl());
}
config/bkash.php (published via vendor:publish)SabitAhmad\Bkash\Facades\Bkash (primary entry point)examples/BkashController.php (if included in package)// Create Agreement
$agreement = Bkash::createAgreement('CUST-1001');
if ($agreement->isSuccess()) {
return redirect()->away($agreement->getAgreementUrl());
}
// Handle Callback (after user completes agreement)
$execution = Bkash::executeAgreement($request->paymentID);
if ($execution->isSuccess()) {
$agreementId = $execution->getAgreementId();
// Store for future payments
}
// Initiate Payment
$payment = Bkash::createPayment(
payerReference: 'CUST-1001',
amount: 100.50,
invoiceNumber: 'INV-1001',
callbackURL: '/payment/callback'
);
if ($payment->isSuccess()) {
return redirect()->away($payment->getPaymentUrl());
}
// Handle Callback
$execution = Bkash::executePayment($request->paymentID);
if ($execution->isCompleted()) {
event(new PaymentCompleted($execution));
}
$payment = Bkash::createPayment(
payerReference: 'CUST-1001',
amount: 100.50,
invoiceNumber: 'INV-1002',
agreementId: 'AGR123456' // Pre-existing agreement
);
Route::post('/bkash/callback', function (Request $request) {
$response = Bkash::executePayment($request->paymentID);
if ($response->isCompleted()) {
// Update order status, send confirmation, etc.
event(new PaymentCompleted($response));
return response()->json(['status' => 'success']);
}
return response()->json(['status' => 'failed'], 400);
});
Enable in config/bkash.php:
'log_transactions' => env('BKASH_LOG_TRANSACTIONS', true),
Logs are stored in bkash_transactions table (migrated via vendor:publish).
try {
$payment = Bkash::createPayment(...);
if (!$payment->isSuccess()) {
throw new \Exception($payment->getErrorMessage());
}
} catch (SabitAhmad\Bkash\Exceptions\BkashException $e) {
Log::error('bKash Error: ' . $e->getMessage());
return back()->with('error', 'Payment failed. Please try again.');
}
Configure retries in .env:
BKASH_RETRY_ATTEMPTS=3
BKASH_RETRY_DELAY=1000
The package automatically retries failed API calls.
Toggle with:
// In config/bkash.php
'sandbox' => env('BKASH_SANDBOX', true),
Use sandbox (true) for testing, set to false for production.
// Create agreement for recurring payments
$agreement = Bkash::createAgreement('SUBSCRIBER_123');
// Store agreement ID in user model
$user->bkash_agreement_id = $agreement->getAgreementId();
$user->save();
// For subsequent payments
$payment = Bkash::createPayment(
payerReference: 'SUBSCRIBER_123',
amount: 50.00,
invoiceNumber: 'SUB_'.now()->format('YmdHis'),
agreementId: $user->bkash_agreement_id
);
$refund = Bkash::refundPayment(
paymentId: 'PAY123456',
amount: 100.50,
reason: 'Customer requested refund'
);
if ($refund->isSuccess()) {
// Update order status, notify customer, etc.
$order->status = 'refunded';
$order->save();
}
$query = Bkash::queryPayment('PAY123456');
if ($query->isCompleted()) {
// Payment is confirmed
$trxId = $query->getTrxId();
} elseif ($query->isFailed()) {
// Handle failure
}
$search = Bkash::searchTransaction('TRX123456');
$transactions = $search->getTransactions();
foreach ($transactions as $tx) {
if ($tx['transactionStatus'] === 'Completed') {
// Process completed transaction
}
}
Listen for payment events in EventServiceProvider:
protected $listen = [
\SabitAhmad\Bkash\Events\PaymentCompleted::class => [
\App\Listeners\UpdateOrderStatus::class,
\App\Listeners\SendConfirmationEmail::class,
],
\SabitAhmad\Bkash\Events\PaymentFailed::class => [
\App\Listeners\NotifyAdmin::class,
],
];
BKASH_TOKEN_CACHE_TTL=3300 seconds).BKASH_TOKEN_CACHE_TTL in .env or handle token refresh manually:
$token = Bkash::getToken(); // Auto-refreshes if expired
callbackURL during payment creation.https://):
$payment = Bkash::createPayment(..., callbackURL: 'https://yourdomain.com/bkash/callback');
true) and production (false) modes..env variables and test thoroughly in sandbox before going live.BKASH_MIN_AMOUNT) and maximum (BKASH_MAX_AMOUNT) amounts.if ($amount < config('bkash.min_amount')) {
throw new \InvalidArgumentException('Amount too low');
}
01712345678).$msisdn = preg_replace('/[^0-9]/', '', $request->phone);
if (strlen($msisdn) !== 11) { // +88 prefix
throw new \InvalidArgumentException('Invalid phone number');
}
// In config/bkash.php
'log_transactions' => true,
How can I help you explore Laravel packages today?