How I Integrated SSLCommerz Payment Gateway in Laravel (Without Any Package)
A step-by-step guide to integrating SSLCommerz into a Laravel e-commerce API — using pure cURL, no third-party package required.

How I Integrated SSLCommerz Payment Gateway in Laravel (Without Any Package)
A step-by-step guide to integrating SSLCommerz into a Laravel e-commerce API — using pure cURL, no third-party package required.
The Problem
I was building an e-commerce platform using Laravel + Vue.js and needed a reliable Bangladeshi payment gateway that supports:
- bKash
- Nagad
- Cards
- Internet Banking
SSLCommerz was the obvious choice.
But there was a problem — no reliable official Laravel package available.
So I decided to build the integration from scratch using pure cURL. The result? A clean, flexible, and fully controllable payment system.
What We’re Building
In this guide, we will build:
- A
SslCommerzService(handles payment link generation via cURL) - A
PaymentController(handles success, fail, cancel, IPN) - Automatic order status update after payment confirmation
- Full logging for debugging
Step 1 — Environment Configuration
Add your credentials in .env:
SSLCOMMERZ_STORE_ID=your_store_id
SSLCOMMERZ_STORE_PASSWORD=your_store_password
SSLCOMMERZ_IS_SANDBOX=true
FRONTEND_URL=http://localhost:5173
Create config/sslcommerz.php:
<?php
return [
'store_id' => env('SSLCOMMERZ_STORE_ID'),
'store_password' => env('SSLCOMMERZ_STORE_PASSWORD'),
'is_sandbox' => env('SSLCOMMERZ_IS_SANDBOX', true),
'success_url' => env('APP_URL') . '/api/payment/success',
'fail_url' => env('APP_URL') . '/api/payment/fail',
'cancel_url' => env('APP_URL') . '/api/payment/cancel',
'ipn_url' => env('APP_URL') . '/api/payment/ipn',
];
Step 2 — Service Class (Core Logic)
Create:
app/Services/SslCommerzService.php
<?php
namespace App\Services;
use App\Models\Order;
use Illuminate\Support\Facades\Log;
class SslCommerzService
{
private string $storeId;
private string $storePassword;
private bool $isSandbox;
private string $baseUrl;
public function __construct()
{
$this->storeId = config('sslcommerz.store_id');
$this->storePassword = config('sslcommerz.store_password');
$this->isSandbox = config('sslcommerz.is_sandbox');
$this->baseUrl = $this->isSandbox
? 'https://sandbox.sslcommerz.com'
: 'https://securepay.sslcommerz.com';
}
public function generatePaymentLink(Order $order): array|false
{
$postData = [
'store_id' => $this->storeId,
'store_passwd' => $this->storePassword,
'total_amount' => $order->total_amount,
'currency' => 'BDT',
'tran_id' => $order->order_number,
'success_url' => config('sslcommerz.success_url'),
'fail_url' => config('sslcommerz.fail_url'),
'cancel_url' => config('sslcommerz.cancel_url'),
'ipn_url' => config('sslcommerz.ipn_url'),
'cus_name' => $order->shipping_name,
'cus_email' => $order->user->email ?? 'noreply@shop.com',
'cus_phone' => $order->shipping_phone,
];
try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->baseUrl . '/gwprocess/v4/api.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if (!empty($data['GatewayPageURL'])) {
return [
'payment_url' => $data['GatewayPageURL'],
'tran_id' => $order->order_number,
];
}
return false;
} catch (\Exception $e) {
Log::error($e->getMessage());
return false;
}
}
}
Step 3 — Payment Controller
Create:
app/Http/Controllers/Api/PaymentController.php
Handles:
- Success
- Fail
- Cancel
- IPN webhook
// success, fail, cancel, ipn methods
// (same logic as your original implementation)
Step 4 — Routes
Route::post('/payment/success', [PaymentController::class, 'success']);
Route::post('/payment/fail', [PaymentController::class, 'fail']);
Route::post('/payment/cancel', [PaymentController::class, 'cancel']);
Route::post('/payment/ipn', [PaymentController::class, 'ipn']);
CSRF Exception
protected $except = [
'api/payment/*',
];
Step 5 — Trigger Payment
Inside your order create logic:
$sslService = new SslCommerzService();
$paymentData = $sslService->generatePaymentLink($order);
if ($paymentData) {
return response()->json([
'order' => $order,
'payment' => $paymentData,
]);
}
Frontend simply redirects the user to:
payment_url
Common Issue Fix
Missing ship_postcode error
Fix:
'ship_postcode' => '1200',
'cus_postcode' => '1200',
SSLCommerz requires a postcode even if not collected.
Payment Flow
Order Created
↓
Generate Payment URL
↓
Redirect to SSLCommerz Gateway
↓
User Pays (bKash / Nagad / Card)
↓
Success Callback Hits API
↓
Validate Payment
↓
Update Order Status → PAID
Debug Tip
Always check logs:
storage/logs/laravel.log
Use:
Log::info(...)
for tracking every step.
Final Summary
FeatureStatusPackage UsedNoneIntegration Method Pure cURLPayment MethodsbKash, Nagad, CardWebhooksIPN + CallbacksAuto Order Update Yes
Final Words
This approach gives full control over the payment system without depending on any external package.
Perfect for production-grade Laravel e-commerce systems.
메타데이터
- post_id
- e799f4c30f37
- slug
- how-i-integrated-sslcommerz-payment-gateway-in-laravel-without-any-package-e799f4c30f37
- url
- https://medium.com/@jalismahamud31/how-i-integrated-sslcommerz-payment-gateway-in-laravel-without-any-package-e799f4c30f37
- canonical_url
- https://medium.com/@jalismahamud31/how-i-integrated-sslcommerz-payment-gateway-in-laravel-without-any-package-e799f4c30f37
- author_url
- https://medium.com/@jalismahamud31
- status
- ok
- fetched_at
- 2026-07-10 13:01:02