sslcommerz/laravel

Production-ready Laravel package for SSLCOMMERZ payment gateway integration (API v4)

Maintainers

Package info

github.com/bdmotaleb/sslcommerz

Homepage

Issues

pkg:composer/sslcommerz/laravel

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 0

dev-main 2026-05-05 08:53 UTC

This package is auto-updated.

Last update: 2026-05-05 08:54:19 UTC


README

Table of Contents

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_KEY is required for recurring payments (Easycheckout). SSLCOMMERZ_LOG_CHANNEL lets 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.

  1. Publish the Controller Stub:

    php artisan vendor:publish --tag=sslcommerz-controller
  2. Update Configuration: In your config/sslcommerz.php, update the controller option to point to your new controller:

    'routes' => [
        'controller' => \App\Http\Controllers\SslcommerzCallbackController::class,
        // ...
    ],
  3. Customize Logic: Edit app/Http/Controllers/SslcommerzCallbackController.php to 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:

  1. Hash Verification: All IPN callbacks are verified using SSLCOMMERZ's MD5 signature algorithm
  2. API Validation: Every successful payment is validated server-side via the Order Validation API
  3. CSRF Exemption: Only callback routes from SSLCOMMERZ are CSRF-exempt
  4. Logging: All gateway interactions are logged for audit trails
  5. Environment Isolation: Separate endpoints for sandbox and production

Best Practices

  • Always validate transactions via the API, never trust callback data alone
  • Monitor risk_level in validation responses (0 = Safe, 1 = Risky)
  • Use value_a through value_d to 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.