A production-ready Laravel package for SSLCommerz payment gateway — supports hosted & checkout modes, IPN with hash verification, order validation, refunds, transaction queries. Laravel 9–12, PHP 8.1–8.5.
rayhan-bapari/sslcommerz is a Laravel package for a production-ready laravel package for sslcommerz payment gateway — supports hosted & checkout modes, ipn with hash verification, order validation, refunds, transaction queries. laravel 9–12, php 8.1–8.5..
It currently has 0 GitHub stars and 10 downloads on Packagist (latest version v1.0.0).
Install it with composer require rayhan-bapari/sslcommerz.
Discover more Laravel packages by rayhan-bapari
or browse all Laravel packages to compare alternatives.
Last updated
A production-ready Laravel package for SSLCommerz payment gateway — the most popular payment aggregator in Bangladesh.
Features:
tran_id and sessionkeyPaymentData DTO covering all API fieldsPaymentResponse object with clean API| Dependency | Version | | ---------- | ------------------------------- | | PHP | ^8.1 | | Laravel | ^9.0 | ^10.0 | ^11.0 | ^12.0 | | ext-curl | * | | ext-json | * |
composer require rayhan-bapari/sslcommerz
php artisan vendor:publish --tag=sslcommerz-config
php artisan vendor:publish --tag=sslcommerz-migrations
php artisan migrate
Add the following to your .env:
# --- Environment ---
SSLCZ_SANDBOX=true # true = sandbox, false = live
# --- Store Credentials ---
# Sandbox registration: https://developer.sslcommerz.com/registration/
SSLCZ_STORE_ID=your_store_id
SSLCZ_STORE_PASSWORD=your_store_password
# --- Default Currency ---
SSLCZ_CURRENCY=BDT
# --- Callback URLs (can be overridden per-payment) ---
SSLCZ_SUCCESS_URL=https://yourdomain.com/sslcommerz/success
SSLCZ_FAIL_URL=https://yourdomain.com/sslcommerz/fail
SSLCZ_CANCEL_URL=https://yourdomain.com/sslcommerz/cancel
SSLCZ_IPN_URL=https://yourdomain.com/sslcommerz/ipn
# --- Payment display mode ---
SSLCZ_DISPLAY_TYPE=hosted # 'hosted' (redirect) or 'checkout' (popup)
# --- IPN ---
SSLCZ_IPN_ENABLED=true
SSLCZ_IPN_PATH=sslcommerz/ipn
SSLCZ_IPN_LOG=true
SSLCommerz POSTs to your callback and IPN URLs. Exclude them from CSRF verification:
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
'sslcommerz/success',
'sslcommerz/fail',
'sslcommerz/cancel',
'sslcommerz/ipn',
];
Session issue? If your session is destroyed after SSLCommerz redirects back, add
'same_site' => 'none'inconfig/session.php.
use RayhanBapari\SslcommerzPayment\Facades\Sslcommerz;
use RayhanBapari\SslcommerzPayment\DTOs\PaymentData;
use RayhanBapari\SslcommerzPayment\Contracts\SslcommerzPaymentInterface;
public function __construct(protected SslcommerzPaymentInterface $sslcz) {}
use RayhanBapari\SslcommerzPayment\DTOs\PaymentData;
use RayhanBapari\SslcommerzPayment\Facades\Sslcommerz;
public function initiatePayment(Request $request)
{
$dto = new PaymentData();
$dto->tran_id = 'INV-' . uniqid();
$dto->total_amount = 500.00;
$dto->currency = 'BDT';
// Customer
$dto->cus_name = $request->user()->name;
$dto->cus_email = $request->user()->email;
$dto->cus_phone = $request->user()->phone;
$dto->cus_add1 = '123 Dhanmondi';
$dto->cus_city = 'Dhaka';
$dto->cus_country = 'Bangladesh';
$dto->cus_postcode = '1209';
// Product
$dto->product_name = 'Premium Subscription';
$dto->product_category = 'subscription';
$dto->product_profile = 'non-physical-goods';
// Shipping (set to NO if digital)
$dto->shipping_method = 'NO';
// Pass-through — get them back in success/fail/cancel/ipn callbacks
$dto->value_a = (string) $request->user()->id;
$dto->value_b = 'order-reference';
$response = Sslcommerz::initiatePayment($dto);
if ($response->success()) {
return redirect($response->gatewayPageURL());
}
return back()->with('error', 'Could not initiate payment: ' . $response->error());
}
Define routes for SSLCommerz to POST back to:
// routes/web.php
Route::post('sslcommerz/success', [PaymentController::class, 'success'])->name('sslcommerz.success');
Route::post('sslcommerz/fail', [PaymentController::class, 'fail'])->name('sslcommerz.fail');
Route::post('sslcommerz/cancel', [PaymentController::class, 'cancel'])->name('sslcommerz.cancel');
// PaymentController.php
public function success(Request $request)
{
// Step 1: Verify hash
if (!Sslcommerz::verifyIpnHash($request->post())) {
abort(403, 'Invalid signature.');
}
// Step 2: Server-side validation
$validation = Sslcommerz::orderValidate($request->val_id);
if (!in_array($validation['status'] ?? '', ['VALID', 'VALIDATED'])) {
return redirect()->route('checkout')->with('error', 'Payment validation failed.');
}
// Step 3: Confirm the amount matches your order
$paidAmount = (float) $validation['amount'];
// ... compare with your stored order amount
// Step 4: Fulfill order using $request->value_a (your user ID), tran_id, bank_tran_id
$bankTranId = $request->bank_tran_id; // Save this — needed for refunds
return redirect()->route('dashboard')->with('success', 'Payment successful!');
}
public function fail(Request $request)
{
return redirect()->route('checkout')->with('error', 'Payment failed. Please try again.');
}
public function cancel(Request $request)
{
return redirect()->route('checkout')->with('info', 'Payment cancelled.');
}
The package auto-registers POST /sslcommerz/ipn. Subscribe to the event:
// app/Providers/EventServiceProvider.php
protected $listen = [
'sslcommerz.ipn' => [
App\Listeners\HandleSslcommerzIpn::class,
],
];
// app/Listeners/HandleSslcommerzIpn.php
namespace App\Listeners;
class HandleSslcommerzIpn
{
public function handle(array $payload): void
{
if (!$payload['verified']) {
return; // Hash check passed but server validation failed
}
$tranId = $payload['tran_id'];
$status = $payload['status']; // VALID | VALIDATED
$bankTranId = $payload['bank_tran_id']; // Save for refunds
$amount = $payload['amount'];
$userId = $payload['value_a']; // Your pass-through field
// Update your order in the database here
}
}
Note: IPN does not work on localhost. Use a public URL (e.g. ngrok for local dev). Also configure the IPN URL in your SSLCommerz merchant panel.
// By your tran_id
$result = Sslcommerz::transactionQueryById('INV-12345');
// By SSLCommerz sessionkey
$result = Sslcommerz::transactionQueryBySessionId('session_abc123');
// You need the bank_tran_id from the original transaction
$result = Sslcommerz::initiateRefund(
bankTranId: '1709162345070ANJdZV8LyI4cMw',
refundAmount: 50.00,
refundRemarks: 'Customer request',
refe_id: 'REF-TRACK-001' // optional tracking reference
);
// $result['status'] → 'success' | 'failed' | 'processing'
// $result['refund_ref_id'] → save this for status checking
// Check refund status
$status = Sslcommerz::refundStatus($result['refund_ref_id']);
// $status['status'] → 'refunded' | 'processing' | 'cancelled'
Note: Your public server IP must be registered with SSLCommerz for live refunds.
For embedded checkout, set SSLCZ_DISPLAY_TYPE=checkout and add the SSLCommerz embed script to your blade template:
<button id="sslczPayBtn" postdata="" endpoint="/sslcommerz/pay-via-ajax">Pay Now</button>
<script>
var obj = {};
obj.cus_name = '{{ auth()->user()->name }}';
obj.cus_email = '{{ auth()->user()->email }}';
obj.amount = '500';
$('#sslczPayBtn').prop('postdata', obj);
</script>
{{-- Sandbox --}}
<script>
(function (w, d) {
var s = d.createElement('script');
s.src =
'https://sandbox.sslcommerz.com/embed.min.js?' + Math.random().toString(36).substring(7);
d.getElementsByTagName('script')[0].parentNode.insertBefore(
s,
d.getElementsByTagName('script')[0]
);
})(window, document);
</script>
For live, replace the sandbox embed URL with:
https://seamless-epay.sslcommerz.com/embed.min.js
| Table | Purpose |
| ---------------- | ------------------------------ |
| sslcz_ipn_logs | Raw + parsed IPN POST payloads |
use RayhanBapari\SslcommerzPayment\Exceptions\SslcommerzException;
use RayhanBapari\SslcommerzPayment\Exceptions\SslcommerzIpnException;
try {
$response = Sslcommerz::initiatePayment($dto);
} catch (SslcommerzException $e) {
// Configuration or API communication error
Log::error('SSLCommerz error: ' . $e->getMessage());
}
Get free sandbox credentials: https://developer.sslcommerz.com/registration/
Set SSLCZ_SANDBOX=true and use your sandbox store_id and store_password.
| Status | Meaning |
| --------------------- | ------------------------------------------ |
| VALID | Transaction is valid — fulfill immediately |
| VALIDATED | Already validated once — still safe |
| INVALID_TRANSACTION | Something is wrong |
| FAILED | Payment failed at gateway |
| CANCELLED | Customer cancelled |
| UNATTEMPTED | Customer did not attempt |
| EXPIRED | Session expired |
MIT © Rayhan Bapari