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.
A comprehensive solution for integrating bKash payments into Laravel applications.
You can install the package via composer:
composer require sabitahmad/laravel-bkash
You can publish and run the migrations with:
php artisan vendor:publish --tag="laravel-bkash-migrations"
php artisan migrate
You can publish the config file with:
php artisan vendor:publish --tag="laravel-bkash-config"
This is the contents of the published config file:
return [
'sandbox' => env('BKASH_SANDBOX', true),
'log_transactions' => env('BKASH_LOG_TRANSACTIONS', true),
'credentials' => [
'app_key' => env('BKASH_APP_KEY'),
'app_secret' => env('BKASH_APP_SECRET'),
'username' => env('BKASH_USERNAME'),
'password' => env('BKASH_PASSWORD'),
],
'base_url' => [
'sandbox' => 'https://tokenized.sandbox.bka.sh/v1.2.0-beta/tokenized/checkout',
'production' => 'https://tokenized.pay.bka.sh/v1.2.0-beta/tokenized/checkout',
],
'endpoints' => [
'token' => '/token/grant',
// ... other endpoints
],
'callback_url' => env('BKASH_CALLBACK_URL', '/bkash/callback'),
'redirect_url' => env('BKASH_REDIRECT_URL', '/payment/redirect'),
];
Optionally, you can publish the views using
Add the following environment variables to your .env file:
# Required Configuration
BKASH_SANDBOX=true
BKASH_APP_KEY=your_app_key
BKASH_APP_SECRET=your_app_secret
BKASH_USERNAME=your_username
BKASH_PASSWORD=your_password
# URL Configuration
BKASH_CALLBACK_URL=/bkash/callback
BKASH_REDIRECT_URL=/payment/redirect
# Optional Configuration
BKASH_LOG_TRANSACTIONS=true
BKASH_TIMEOUT=30
BKASH_RETRY_ATTEMPTS=3
BKASH_RETRY_DELAY=1000
BKASH_TOKEN_CACHE_TTL=3300
BKASH_CURRENCY=BDT
# Validation Settings
BKASH_STRICT_VALIDATION=true
BKASH_MAX_AMOUNT=999999.99
BKASH_MIN_AMOUNT=1.00
use SabitAhmad\Bkash\Facades\Bkash;
use SabitAhmad\Bkash\Exceptions\BkashException;
try {
$agreement = Bkash::createAgreement('CUST-001');
if ($agreement->isSuccess()) {
// Redirect user to bKash for agreement
return redirect()->away($agreement->getAgreementUrl());
}
throw new Exception('Agreement creation failed: ' . $agreement->getErrorMessage());
} catch (BkashException $e) {
// Handle exception
}
// After user completes agreement on bKash page
$agreement = Bkash::executeAgreement($paymentId);
if ($agreement->isSuccess()) {
$agreementId = $agreement->getAgreementId();
// Store agreementId for future payments
}
try {
$payment = Bkash::createPayment(
payerReference: 'CUST-001',
amount: 100.50,
invoiceNumber: 'INV-001'
);
if ($payment->isSuccess()) {
return redirect()->away($payment->getPaymentUrl());
}
throw new Exception('Payment creation failed: ' . $payment->getErrorMessage());
} catch (BkashException $e) {
// Handle exception
}
try {
$payment = Bkash::createPayment(
payerReference: 'CUST-001',
amount: 100.50,
invoiceNumber: 'INV-001',
callbackURL: '/payment/callback',
agreementId: 'AGR123456' // Use existing agreement
);
if ($payment->isSuccess()) {
return redirect()->away($payment->getPaymentUrl());
}
} catch (BkashException $e) {
// Handle exception
}
Execute Payment
$execution = Bkash::executePayment($paymentId);
if ($execution->getTransactionStatus() === 'Completed') {
// Payment successful
$trxId = $execution->getTrxId();
}
Handle CallbackRoute::post('/bkash/callback', function (Request $request) {
$payment = Bkash::executePayment($request->paymentID);
if ($payment->isSuccess()) {
event(new PaymentCompleted($payment));
return redirect('/success');
}
return redirect('/failed');
});
$refund = Bkash::refundPayment('TRX123456', 100.50, 'Customer requested refund');
if ($refund->isSuccess()) {
$refundId = $refund->getRefundId();
echo "Refund successful. Refund ID: {$refundId}";
}
$query = Bkash::queryPayment('PAY123456');
if ($query->isCompleted()) {
echo "Payment completed successfully";
echo "Transaction ID: " . $query->getTrxId();
}
$search = Bkash::searchTransaction('TRX123456');
if ($search->isSuccess()) {
$transactions = $search->getTransactions();
foreach ($transactions as $transaction) {
echo "Amount: " . $transaction['amount'];
echo "Status: " . $transaction['transactionStatus'];
}
}
$refundStatus = Bkash::refundStatus('PAY123456', 'REF789012');
if ($refundStatus->isSuccess()) {
echo "Refund Status: " . $refundStatus->getTransactionStatus();
}
// Query Agreement
$agreement = Bkash::queryAgreement('AGR123456');
// Cancel Agreement
$cancelResult = Bkash::cancelAgreement('AGR123456');
use SabitAhmad\Bkash\Helpers\BkashHelper;
$helper = new BkashHelper(app(Bkash::class));
// Process complete payment flow
$payment = $helper->processPayment('CUST-001', 100.50, 'INV-001');
// Handle callback
$result = $helper->handleCallback($request->all());
// Get payment status with detailed info
$status = $helper->getPaymentStatus('PAY123456');
// Generate unique references
$payerRef = BkashHelper::generatePayerReference('CUSTOMER');
$invoiceNum = BkashHelper::generateInvoiceNumber('ORDER');
| Method | Returns | Description |
|---|---|---|
isSuccess() |
bool |
Whether operation succeeded |
hasError() |
bool |
Whether operation has error |
getErrorMessage() |
?string |
Error message if failed |
getStatusCode() |
?string |
bKash status code |
getStatusMessage() |
?string |
bKash status message |
getErrorCode() |
?string |
bKash error code |
getRawData() |
array |
Complete API response |
toArray() |
array |
Response as array |
| Method | Returns | Description |
|---|---|---|
getPaymentId() |
?string |
Payment ID |
getPaymentUrl() |
?string |
Redirect URL for payment |
getTrxId() |
?string |
bKash transaction ID |
getAmount() |
?float |
Transaction amount |
getCustomerMsisdn() |
?string |
Customer phone number |
getTransactionStatus() |
?string |
"Completed"/"Failed" etc |
getInvoiceNumber() |
?string |
Merchant invoice number |
getPayerReference() |
?string |
Payer reference |
getCurrency() |
?string |
Transaction currency |
getIntent() |
?string |
Payment intent |
getMode() |
?string |
Payment mode |
getPaymentExecuteTime() |
?Carbon |
Execution timestamp |
getCreateTime() |
?Carbon |
Creation timestamp |
getUpdateTime() |
?Carbon |
Last update timestamp |
isCompleted() |
bool |
Whether payment completed |
isCancelled() |
bool |
Whether payment cancelled |
isFailed() |
bool |
Whether payment failed |
| Method | Returns | Description |
|---|---|---|
getAgreementId() |
?string |
Agreement ID |
getAgreementUrl() |
?string |
Redirect URL for agreement |
getAgreementStatus() |
?string |
Agreement status |
getPayerReference() |
?string |
Payer reference |
getCustomerMsisdn() |
?string |
Customer phone number |
getAgreementExecuteTime() |
?Carbon |
Agreement execution time |
| Method | Returns | Description |
|---|---|---|
getRefundId() |
?string |
Refund transaction ID |
getOriginalPaymentId() |
?string |
Original payment ID |
getRefundAmount() |
?float |
Refunded amount |
getTransactionStatus() |
?string |
Refund status |
getRefundTime() |
?Carbon |
Refund timestamp |
getCharge() |
?float |
Refund charge |
getTrxId() |
?string |
Transaction ID |
getPaymentId() |
?string |
Payment ID |
getCurrency() |
?string |
Currency |
getReason() |
?string |
Refund reason |
| Method | Returns | Description |
|---|---|---|
getPaymentId() |
?string |
Payment ID |
getTrxId() |
?string |
Transaction ID |
getTransactionStatus() |
?string |
Current payment status |
getAmount() |
?float |
Transaction amount |
getCustomerMsisdn() |
?string |
Customer phone number |
getMerchantInvoiceNumber() |
?string |
Invoice number |
getCurrency() |
?string |
Transaction currency |
getIntent() |
?string |
Payment intent |
getInitiationTime() |
?Carbon |
Transaction initiation time |
getCompletedTime() |
?Carbon |
Transaction completion time |
isCompleted() |
bool |
Whether transaction completed |
isCancelled() |
bool |
Whether transaction cancelled |
isFailed() |
bool |
Whether transaction failed |
| Method | Returns | Description |
|---|---|---|
getTransactions() |
array |
Array of transactions |
getTransactionCount() |
int |
Number of transactions |
getFirstTransaction() |
?array |
First transaction |
getTransactionByTrxId() |
?array |
Find transaction by trx ID |
getTransactionByPaymentId() |
?array |
Find transaction by payment ID |
See examples/BkashController.php for a complete implementation example showing:
The package dispatches the following events:
SabitAhmad\Bkash\Events\PaymentCompleted - When a payment is successfully completedSabitAhmad\Bkash\Events\PaymentFailed - When a payment failsSabitAhmad\Bkash\Events\AgreementCreated - When an agreement is successfully createdYou can listen to these events in your EventServiceProvider:
protected $listen = [
\SabitAhmad\Bkash\Events\PaymentCompleted::class => [
\App\Listeners\HandlePaymentCompleted::class,
],
\SabitAhmad\Bkash\Events\PaymentFailed::class => [
\App\Listeners\HandlePaymentFailed::class,
],
];
The package supports extensive configuration options:
composer test
Please see CHANGELOG for more information on what has changed recently.
If you are upgrading from v2.0.x, please note the following changes:
urls configuration array has been simplified. If you previously published the config file, you may want to republish it or update your config to use the new base_url and endpoints format. The package maintains backward compatibility for existing configurations.bkash_payments table has two new columns: payer_reference and invoice_number. Please publish the updated migration and run php artisan migrate.'Completed') with the new SabitAhmad\Bkash\Enums\TransactionStatus class constants.SabitAhmad\Bkash\Contracts\BkashInterface instead of the concrete Bkash class.BkashInterface for easier mocking and testing.payer_reference and invoice_number for faster queries, eliminating dependency on JSON columns.TransactionStatus constants for cleaner code.php artisan bkash:status to quickly verify configurations.The MIT License (MIT). Please see License File for more information.
How can I help you explore Laravel packages today?