sslcommerz / laravel
Production-ready Laravel package for SSLCOMMERZ payment gateway integration (API v4)
Requires
- php: ^8.1
- illuminate/events: ^10.0|^11.0|^12.0|^13.0
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/log: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0|^11.0
- phpunit/phpunit: ^10.0|^11.0
This package is auto-updated.
Last update: 2026-05-05 08:54:19 UTC
README
Table of Contents
- Installation
- Configuration
- Quick Start
- Payment Flow
- Usage
- Callback Handling
- Events
- Hash Verification
- Custom Controllers
- Testing
- API Reference
- Security
- Troubleshooting
Installation
composer require sslcommerz/laravel
Publish Configuration
php artisan vendor:publish --tag=sslcommerz-config
Publish Routes (Optional)
php artisan vendor:publish --tag=sslcommerz-routes
Publish Everything
php artisan vendor:publish --tag=sslcommerz
Configuration
Add these variables to your .env file:
SSLCOMMERZ_SANDBOX=true SSLCOMMERZ_STORE_ID=your_store_id SSLCOMMERZ_STORE_PASSWORD=your_store_password SSLCOMMERZ_LOG_ENABLED=true SSLCOMMERZ_LOG_CHANNEL=stack SSLCOMMERZ_SALT_KEY=your_salt_key
# Your application URL (IMPORTANT: SSLCOMMERZ sends callbacks to this URL) APP_URL=https://yourdomain.com
Note:
SSLCOMMERZ_SALT_KEYis required for recurring payments (Easycheckout).SSLCOMMERZ_LOG_CHANNELlets you pick a Laravel log channel.
Quick Start
use Sslcommerz\Laravel\Facades\SSLCOMMERZ; // In your controller public function checkout(Request $request) { // Simply pass an array of parameters to initiate payment $response = SSLCOMMERZ::initiate([ 'tran_id' => 'ORDER_' . uniqid(), 'total_amount' => 1500.00, 'cus_name' => $request->name, 'cus_email' => $request->email, // ... other parameters as needed ... ]); // Check if initiation was successful if ($response->isSuccessful()) { return $response->redirect(); // Fluent redirect to SSLCOMMERZ } return back()->with('error', $response->failedReason); }
Sandbox Test Credentials
Register at https://developer.sslcommerz.com/registration/ to get your sandbox credentials.
Test Card Numbers:
| Card Type | Number | Expiry | CVV |
|---|---|---|---|
| VISA | 4111111111111111 | 12/36 | 111 |
| Mastercard | 5111111111111111 | 12/36 | 111 |
| Amex | 371111111111111 | 12/36 | 111 |
Mobile OTP: 111111 or 123456
Custom Controllers
You can easily override the default callback behavior.
-
Publish the Controller Stub:
php artisan vendor:publish --tag=sslcommerz-controller
-
Update Configuration: In your
config/sslcommerz.php, update thecontrolleroption to point to your new controller:'routes' => [ 'controller' => \App\Http\Controllers\SslcommerzCallbackController::class, // ... ],
-
Customize Logic: Edit
app/Http/Controllers/SslcommerzCallbackController.phpto suit your needs.
Note: If you want to customize the URLs, you can also publish the routes:
php artisan vendor:publish --tag=sslcommerz-routes
Payment Flow
┌──────────┐ ┌──────────────┐ ┌─────────────┐
│ Customer │────▶│ Your Server │────▶│ SSLCOMMERZ │
│ Browser │ │ (Laravel) │ │ API │
└──────────┘ └──────────────┘ └─────────────┘
│ │ │
│ 1. Checkout │ │
│─────────────────▶│ │
│ │ 2. Create Session │
│ │────────────────────▶│
│ │ 3. GatewayPageURL │
│ │◀────────────────────│
│ 4. Redirect │ │
│◀─────────────────│ │
│ │ │
│ 5. Pay on SSLCOMMERZ page │
│───────────────────────────────────────▶│
│ │ │
│ │ 6. IPN Notification │
│ │◀────────────────────│
│ │ 7. Validate (API) │
│ │────────────────────▶│
│ │ 8. VALID │
│ │◀────────────────────│
│ │ │
│ 9. Redirect to success_url │
│◀───────────────────────────────────────│
│ │ │
Usage
Initiate Payment
use Sslcommerz\Laravel\Facades\SSLCOMMERZ; $response = SSLCOMMERZ::initiate([ 'tran_id' => 'ORDER_' . uniqid(), 'total_amount' => 1000.00, 'cus_name' => 'John Doe', 'cus_email' => 'john@example.com', 'cus_phone' => '01711111111', // ... other parameters as needed ... ]); // Response behaves like an array and an object if ($response['status'] === 'SUCCESS') { return $response->redirect(); }
Specialized Parameters (API v4)
| Category | Parameters |
|---|---|
| Airline | pnr, hours_till_departure, flight_type, journey_from_to, third_party_booking |
| Travel | hotel_name, length_of_stay, check_in_time, hotel_city |
| Telecom | product_type, topup_number, country_topup |
| Logistics | logistic_pickup_id, logistic_delivery_type |
Recurring Payments (Easycheckout)
SSLCOMMERZ supports recurring payments via a schedule parameter.
1. Configure SALT Key:
Add SSLCOMMERZ_SALT_KEY to your .env file. This key is provided by the SSLCOMMERZ team.
2. Initiate Recurring Payment:
use Sslcommerz\Laravel\Facades\SSLCOMMERZ; // 1. Prepare schedule data $schedule = json_encode([ 'refer' => 'REF1234', // Plan ID from Merchant Panel 'acct_no' => 'CUS_001', // Customer account reference 'type' => 'monthly', 'dayofmonth' => '24', ]); // 2. Encrypt the schedule $encryptedSchedule = SSLCOMMERZ::getEncryptionService()->encrypt($schedule); // 3. Initiate payment $response = SSLCOMMERZ::initiate([ // ... mandatory fields ... 'schedule' => $encryptedSchedule, ]); if ($response->isSuccessful()) { // If successful, a subscription_id will be returned in the callback/response $subscriptionId = $response->subscriptionId; }
3. Manage Subscriptions:
// Check status $status = SSLCOMMERZ::getSubscriptionStatus($refer, $subscriptionId); // Disable temporarily SSLCOMMERZ::disableSubscription($refer, $subscriptionId); // Re-enable SSLCOMMERZ::enableSubscription($refer, $subscriptionId); // Cancel permanently SSLCOMMERZ::cancelSubscription($refer, $subscriptionId);
Validate Transaction
$validation = SSLCOMMERZ::validate($valId); if ($validation->isSuccessful()) { // Payment confirmed - access via array or object echo "Amount: " . $validation['amount']; echo "Bank Transaction: " . $validation->bankTranId; }
Refund
// Simply pass an array $refund = SSLCOMMERZ::refund([ 'bank_tran_id' => $bankTranId, 'refund_amount' => 500.00, 'refund_remarks' => 'Customer requested refund', ]); if ($refund->isSuccessful()) { echo "Refund Reference: " . $refund['refund_ref_id']; }
Query Transaction
$result = SSLCOMMERZ::queryTransaction('ORDER_001'); if ($result->hasTransactions()) { $latest = $result->getLatestSuccessful(); echo "Status: " . $latest['status']; }
Callback Handling
The package registers these routes automatically:
| Route | Name | Purpose |
|---|---|---|
POST /ssl/success |
sslcommerz.success |
Successful payment |
POST /ssl/fail |
sslcommerz.fail |
Failed payment |
POST /ssl/cancel |
sslcommerz.cancel |
Cancelled payment |
POST /ssl/ipn |
sslcommerz.ipn |
Instant Payment Notification |
All routes exclude CSRF verification since SSLCOMMERZ sends POST requests.
By default, the prefix is ssl. You can change it via sslcommerz.routes.prefix in config/sslcommerz.php, or publish routes to customize paths.
Redirect URLs After Payment
Define your own routes and views to show the payment result to the user:
// routes/web.php Route::get('/payment/success', function () { return view('payment.success'); });
Events
Listen to these events in your EventServiceProvider:
use Sslcommerz\Laravel\Events\PaymentSucceeded; use Sslcommerz\Laravel\Events\PaymentFailed; use Sslcommerz\Laravel\Events\PaymentCancelled; use Sslcommerz\Laravel\Events\IpnReceived; use Sslcommerz\Laravel\Events\RefundInitiated; protected $listen = [ PaymentSucceeded::class => [ UpdateOrderStatus::class, SendPaymentConfirmation::class, ], PaymentFailed::class => [ HandleFailedPayment::class, ], IpnReceived::class => [ ProcessIpnNotification::class, ], ];
Persistence (Handling Orders)
Since this package is database-agnostic, you should handle transaction persistence in your own application using listeners.
Example Listener:
namespace App\Listeners; use Sslcommerz\Laravel\Events\PaymentSucceeded; use App\Models\Order; class UpdateOrderStatus { public function handle(PaymentSucceeded $event): void { // Access callback data via $event->payment // Access API validation data via $event->validation $tranId = $event->payment->tranId; $orderId = $event->payment->valueA; // Your custom reference Order::where('id', $orderId)->update([ 'status' => 'paid', 'paid_at' => now(), 'payment_id' => $tranId, ]); } }
Hash Verification
The package automatically verifies hash signatures on IPN callbacks. You can also verify manually:
$isValid = SSLCOMMERZ::verifyHash($request->all());
Or use the middleware on your own routes:
Route::middleware('sslcommerz.verify') ->post('/custom-callback', [CustomController::class, 'handle']);
Testing
Run Package Tests
composer install ./vendor/bin/phpunit
Mock in Your Application Tests
use Sslcommerz\Laravel\Facades\SSLCOMMERZ; use Sslcommerz\Laravel\DTOs\PaymentResponseDTO; SSLCOMMERZ::shouldReceive('initiate') ->once() ->andReturn(PaymentResponseDTO::fromApiResponse([ 'status' => 'SUCCESS', 'GatewayPageURL' => 'https://sandbox.sslcommerz.com/gw.php', 'sessionkey' => 'TEST_SESSION', ]));
API Reference
SSLCOMMERZ::initiate(PaymentRequestDTO|array $request): PaymentResponseDTO
Creates a payment session. If an array is passed, it is automatically converted to a DTO with sensible defaults.
SSLCOMMERZ::validate(string $valId): ValidationResponseDTO
Validates a transaction using the validation ID from callback/IPN.
SSLCOMMERZ::refund(RefundRequestDTO|array $request): RefundResponseDTO
Initiates a refund for a previously successful transaction.
SSLCOMMERZ::queryTransaction(string $tranId): TransactionQueryDTO
Queries all transactions associated with a merchant transaction ID.
SSLCOMMERZ::queryBySession(string $sessionKey): ValidationResponseDTO
Queries transaction status by SSLCOMMERZ session key.
SSLCOMMERZ::queryRefundStatus(string $refundRefId): RefundResponseDTO
Checks the current status of a refund request.
SSLCOMMERZ::verifyHash(array $data): bool
Verifies the MD5 hash signature of callback data.
Security
This package implements multiple layers of security:
- Hash Verification: All IPN callbacks are verified using SSLCOMMERZ's MD5 signature algorithm
- API Validation: Every successful payment is validated server-side via the Order Validation API
- CSRF Exemption: Only callback routes from SSLCOMMERZ are CSRF-exempt
- Logging: All gateway interactions are logged for audit trails
- Environment Isolation: Separate endpoints for sandbox and production
Best Practices
- Always validate transactions via the API, never trust callback data alone
- Monitor
risk_levelin validation responses (0 = Safe, 1 = Risky) - Use
value_athroughvalue_dto pass your own references - Set up IPN as the primary notification method (works even if user closes browser)
- Register your production IP at SSLCOMMERZ for refund API access
Troubleshooting
| Issue | Solution |
|---|---|
| "Invalid Store ID" | Check SSLCOMMERZ_STORE_ID in .env |
| CSRF token mismatch | Callback routes already exclude CSRF — check if you overrode routes |
| IPN not received | Ensure your server is reachable from internet on port 80/443 |
| Hash verification fails | Verify SSLCOMMERZ_STORE_PASSWORD matches your SSLCOMMERZ dashboard |
| Connection timeout | Whitelist SSLCOMMERZ IPs: 103.26.139.87 (sandbox), 103.26.139.81 (live) |
License
MIT License. See LICENSE for details.