SSLCommerz Payment Gateway Integration:
The 2026 Ultimate Technical Guide
1. What is SSLCommerz?
SSLCommerz, a flagship product of SSL Wireless, is Bangladesh's most trusted and widely adopted online payment gateway. Founded to bridge the digital payment gap in South Asia, SSLCommerz now processes millions of transactions monthly across diverse sectors—e-commerce, education, healthcare, government services, and enterprise ERP systems. It supports Visa, Mastercard, American Express, bKash, Nagad, Rocket, Upay, internet banking (40+ banks), and EMI facilities, making it the most versatile payment aggregator in the region.
For developers, SSLCommerz offers a hosted checkout model—meaning sensitive card data never touches your server, ensuring PCI-DSS compliance out of the box. The gateway handles the entire payment lifecycle: session initialization, customer redirection, secure payment collection, and server-to-server IPN (Instant Payment Notification) validation. This guide dissects every technical nuance, from sandbox experimentation to production hardening, with battle-tested code in 7 languages and frameworks.
2. Sandbox & Production Setup
Before writing a single line of code, you must register on the SSLCommerz merchant panel and obtain your Store ID and Store Password. SSLCommerz provides two distinct environments:
| Environment | API Base URL | Purpose |
|---|---|---|
| Sandbox | https://sandbox.sslcommerz.com | Testing with dummy cards, bKash/Nagad sandbox accounts |
| Production (Live) | https://securepay.sslcommerz.com | Real money transactions with actual customers |
Sandbox Registration Steps
- Visit https://developer.sslcommerz.com and sign up for a sandbox account.
- After email verification, log in and navigate to "Sandbox Store" → "Create New Store".
- Fill in your store name, website URL, and callback URLs (you can use localhost or ngrok for local testing).
- Once created, note down the Store ID (e.g.,
testbox) and Store Password (e.g.,qwerty). - Under "IPN Settings", configure your IPN listener URL where SSLCommerz will send server-to-server notifications.
qwerty). Never reuse sandbox credentials in production. Production credentials are issued after business verification by the SSLCommerz team.
Production Go-Live Checklist
- ✅ Business registration documents submitted and verified
- ✅ Bank account linked for settlement
- ✅ Production Store ID and Password received via email
- ✅ IPN URL switched to production endpoint
- ✅ All callback URLs use HTTPS (mandatory for production)
- ✅ Tested with 1 BDT transaction before going fully live
3. Integration Flow & Endpoints
The SSLCommerz integration follows a strict three-step lifecycle: Session Initialization → Customer Redirection → Server-Side Validation. Missing any step compromises security and reliability.
POST to SSLCommerz
Initiate Session
Returns Gateway URL
sessionkey + URL
Redirected to Gateway
Pays via bKash/Card/etc.
to success/fail URL
+ val_id
Validates via API
GET with val_id
Core API Endpoints
| Action | HTTP Method | Sandbox URL | Production URL |
|---|---|---|---|
| Initiate Payment | POST | https://sandbox.sslcommerz.com/gwprocess/v4/api.php | https://securepay.sslcommerz.com/gwprocess/v4/api.php |
| Validate Transaction | GET | https://sandbox.sslcommerz.com/validator/api/validationserverAPI.php | https://securepay.sslcommerz.com/validator/api/validationserverAPI.php |
| Transaction Query | GET | https://sandbox.sslcommerz.com/validator/api/merchantTransIDvalidationAPI.php | https://securepay.sslcommerz.com/validator/api/merchantTransIDvalidationAPI.php |
| Refund Request | GET | https://sandbox.sslcommerz.com/validator/api/merchantTransIDvalidationAPI.php (with refund params) | Same structure, production endpoint |
4. Initiate Payment (API Call)
The payment initiation is a server-side POST request with application/x-www-form-urlencoded payload. Below is the exhaustive parameter reference:
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
store_id | String | ✅ Yes | Merchant Store ID | testbox |
store_passwd | String | ✅ Yes | Merchant Store Password | qwerty |
total_amount | Decimal | ✅ Yes | Total transaction amount | 1250.00 |
currency | String | ✅ Yes | Currency code | BDT or USD |
tran_id | String | ✅ Yes | Unique transaction ID (your system) | INV-20260728-001 |
success_url | String | ✅ Yes | Redirect URL on success | https://yoursite.com/payment/success |
fail_url | String | ✅ Yes | Redirect URL on failure | https://yoursite.com/payment/fail |
cancel_url | String | ✅ Yes | Redirect URL on cancellation | https://yoursite.com/payment/cancel |
cus_name | String | ✅ Yes | Customer full name | Rahim Uddin |
cus_email | String | ✅ Yes | Customer email | rahim@example.com |
cus_phone | String | ✅ Yes | Customer mobile number | 01712345678 |
cus_add1 | String | Optional | Customer address line 1 | 123 Gulshan Avenue |
cus_city | String | Optional | Customer city | Dhaka |
cus_country | String | Optional | Customer country | Bangladesh |
shipping_method | String | Optional | Shipping method | Courier |
product_name | String | Optional | Product description | Smartphone XYZ |
product_category | String | Optional | Product category | Electronics |
product_profile | String | Optional | Profile type | general or physical-goods |
Expected JSON Response
A successful initiation returns:
status is not "SUCCESS", check failedreason for details. Common causes: invalid store credentials, missing required fields, or IP not whitelisted (in production).
5. Redirect & Customer Action
Once your backend receives the GatewayPageURL, you must redirect the customer's browser to this URL. The customer then interacts with the SSLCommerz hosted payment page—selecting their preferred payment method among:
- Cards: Visa, Mastercard, American Express, Nexus, etc.
- Mobile Banking: bKash, Nagad, Rocket, Upay, mCash
- Internet Banking: 40+ Bangladeshi banks including DBBL, EBL, Brac Bank, City Bank, etc.
- EMI: Installment plans via partner banks
After the customer completes or abandons the payment, SSLCommerz redirects the browser to your predefined success_url, fail_url, or cancel_url with POST data containing the val_id (validation ID) and transaction summary.
success_url. A malicious user could forge this request. Always validate server-side using the val_id.
6. IPN Handling & Validation
What is IPN (Instant Payment Notification)?
IPN is a server-to-server POST request sent asynchronously by SSLCommerz to your designated IPN listener URL. It carries the same val_id and transaction data. IPN is the safety net—even if the customer closes their browser immediately after payment, your server still receives the IPN and can update the order status.
Step-by-Step Validation
- Receive the
val_idfrom either the redirect POST or the IPN POST. - Call the Validation API with a GET request to:
https://sandbox.sslcommerz.com/validator/api/validationserverAPI.php?val_id={VAL_ID}&store_id={STORE_ID}&store_passwd={STORE_PASSWORD}&v=1&format=json - Parse the JSON response and verify these critical fields:
statusmust be"VALID"or"VALIDATED"amountmust match your original order total exactly (watch for decimal precision!)tran_idmust match the transaction ID stored in your databasecurrencymust match your expected currency
- Only after all checks pass, update the order status to "Paid" and trigger fulfillment (email confirmation, inventory deduction, etc.).
PHP IPN Listener Example
// ipn_listener.php - SSLCommerz IPN Handler
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$val_id = $_POST['val_id'] ?? null;
$store_id = 'your_store_id';
$store_passwd = 'your_store_password';
if (!$val_id) { http_response_code(400); exit('Missing val_id'); }
$validation_url = "https://sandbox.sslcommerz.com/validator/api/validationserverAPI.php"
. "?val_id=" . urlencode($val_id)
. "&store_id=" . urlencode($store_id)
. "&store_passwd=" . urlencode($store_passwd)
. "&v=1&format=json";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $validation_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if ($data['status'] === 'VALID' || $data['status'] === 'VALIDATED') {
// Verify amount and tran_id match your database
$db_order = getOrderByTranId($data['tran_id']);
if ($db_order && floatval($data['amount']) === floatval($db_order['total'])) {
updateOrderStatus($data['tran_id'], 'Paid');
logPayment($data);
}
}
exit('OK');
}
7. Transaction Query & Refund
Transaction Query by tran_id
You can query any transaction's status using your own tran_id:
GET https://sandbox.sslcommerz.com/validator/api/merchantTransIDvalidationAPI.php
?tran_id=INV-20260728-001
&store_id=testbox
&store_passwd=qwerty
&v=1
&format=json
Refund API
SSLCommerz supports refunds via the same query endpoint with additional parameters. A refund can be full or partial:
GET https://sandbox.sslcommerz.com/validator/api/merchantTransIDvalidationAPI.php
?tran_id=INV-20260728-001
&store_id=testbox
&store_passwd=qwerty
&refund_amount=500.00
&refund_remarks=Customer+requested+partial+refund
&v=1
&format=json
refund_amount cannot exceed the original transaction amount. Always validate the refund response status before updating your system.
8. Complete Code (7 Languages & Frameworks)
Below are production-ready integration snippets for the most popular backend languages and frameworks. Each follows the three-step lifecycle rigorously.
8.1 PHP (Vanilla)
// initiate_payment.php
$payload = [
'store_id' => 'testbox',
'store_passwd' => 'qwerty',
'total_amount' => '1500.00',
'currency' => 'BDT',
'tran_id' => 'ORD-' . uniqid(),
'success_url' => 'https://yoursite.com/success.php',
'fail_url' => 'https://yoursite.com/fail.php',
'cancel_url' => 'https://yoursite.com/cancel.php',
'cus_name' => 'Rahim Uddin',
'cus_email' => 'rahim@example.com',
'cus_phone' => '01712345678',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://sandbox.sslcommerz.com/gwprocess/v4/api.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if ($result['status'] === 'SUCCESS') {
header('Location: ' . $result['GatewayPageURL']);
exit;
} else {
die('Payment initiation failed: ' . $result['failedreason']);
}
8.2 Laravel (PHP Framework)
// App\Http\Controllers\PaymentController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class PaymentController extends Controller
{
public function initiate(Request $request)
{
$tranId = 'INV-' . uniqid();
$response = Http::asForm()->post('https://sandbox.sslcommerz.com/gwprocess/v4/api.php', [
'store_id' => config('sslcommerz.store_id'),
'store_passwd' => config('sslcommerz.store_password'),
'total_amount' => $request->amount,
'currency' => 'BDT',
'tran_id' => $tranId,
'success_url' => route('payment.success'),
'fail_url' => route('payment.fail'),
'cancel_url' => route('payment.cancel'),
'cus_name' => $request->name,
'cus_email' => $request->email,
'cus_phone' => $request->phone,
]);
if ($response->json('status') === 'SUCCESS') {
// Save order with $tranId in database
return redirect()->away($response->json('GatewayPageURL'));
}
return back()->with('error', 'Payment initiation failed.');
}
}
8.3 Node.js (Express)
// paymentController.js
const axios = require('axios');
const qs = require('qs');
exports.initiatePayment = async (req, res) => {
const tranId = `INV-${Date.now()}`;
const payload = {
store_id: process.env.SSLCOMMERZ_STORE_ID,
store_passwd: process.env.SSLCOMMERZ_STORE_PASSWORD,
total_amount: req.body.amount,
currency: 'BDT',
tran_id: tranId,
success_url: `${process.env.BASE_URL}/payment/success`,
fail_url: `${process.env.BASE_URL}/payment/fail`,
cancel_url: `${process.env.BASE_URL}/payment/cancel`,
cus_name: req.body.name,
cus_email: req.body.email,
cus_phone: req.body.phone,
};
try {
const response = await axios.post(
'https://sandbox.sslcommerz.com/gwprocess/v4/api.php',
qs.stringify(payload),
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
);
if (response.data.status === 'SUCCESS') {
return res.redirect(response.data.GatewayPageURL);
}
res.status(500).json({ error: response.data.failedreason });
} catch (err) {
res.status(500).json({ error: err.message });
}
};
8.4 Python (Flask)
import requests
import uuid
from flask import Flask, request, redirect
app = Flask(__name__)
@app.route('/pay', methods=['POST'])
def initiate_payment():
tran_id = f"INV-{uuid.uuid4().hex[:12]}"
payload = {
'store_id': 'testbox',
'store_passwd': 'qwerty',
'total_amount': request.form['amount'],
'currency': 'BDT',
'tran_id': tran_id,
'success_url': 'https://yoursite.com/success',
'fail_url': 'https://yoursite.com/fail',
'cancel_url': 'https://yoursite.com/cancel',
'cus_name': request.form['name'],
'cus_email': request.form['email'],
'cus_phone': request.form['phone'],
}
r = requests.post(
'https://sandbox.sslcommerz.com/gwprocess/v4/api.php',
data=payload
)
result = r.json()
if result.get('status') == 'SUCCESS':
return redirect(result['GatewayPageURL'])
return f"Error: {result.get('failedreason')}", 500
8.5 Java (Spring Boot)
// PaymentService.java
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import java.util.*;
@Service
public class PaymentService {
private final WebClient webClient = WebClient.create();
public String initiatePayment(PaymentRequest req) {
String tranId = "INV-" + UUID.randomUUID().toString().substring(0, 12);
Map<String, String> payload = new HashMap<>();
payload.put("store_id", "testbox");
payload.put("store_passwd", "qwerty");
payload.put("total_amount", req.getAmount().toString());
payload.put("currency", "BDT");
payload.put("tran_id", tranId);
// ... add all other fields
Map response = webClient.post()
.uri("https://sandbox.sslcommerz.com/gwprocess/v4/api.php")
.body(BodyInserters.fromFormData(payload))
.retrieve()
.bodyToMono(Map.class)
.block();
if ("SUCCESS".equals(response.get("status"))) {
return (String) response.get("GatewayPageURL");
}
throw new RuntimeException("Payment failed");
}
}
8.6 C# (.NET 8)
// PaymentController.cs
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/payment")]
public class PaymentController : ControllerBase
{
private readonly HttpClient _httpClient;
public PaymentController(HttpClient httpClient) { _httpClient = httpClient; }
[HttpPost("initiate")]
public async Task<IActionResult> Initiate(PaymentDto dto)
{
var tranId = $"INV-{Guid.NewGuid().ToString()[..12]}";
var payload = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "store_id", "testbox" },
{ "store_passwd", "qwerty" },
{ "total_amount", dto.Amount.ToString("F2") },
{ "currency", "BDT" },
{ "tran_id", tranId },
// ... add all other fields
});
var response = await _httpClient.PostAsync(
"https://sandbox.sslcommerz.com/gwprocess/v4/api.php", payload);
var result = await response.Content.ReadFromJsonAsync<Dictionary<string, object>>();
if (result["status"].ToString() == "SUCCESS")
return Redirect(result["GatewayPageURL"].ToString());
return BadRequest(result["failedreason"]);
}
}
8.7 Ruby on Rails
# payments_controller.rb
class PaymentsController < ApplicationController
def initiate
tran_id = "INV-#{SecureRandom.hex(6)}"
payload = {
store_id: ENV['SSLCOMMERZ_STORE_ID'],
store_passwd: ENV['SSLCOMMERZ_STORE_PASSWORD'],
total_amount: params[:amount],
currency: 'BDT',
tran_id: tran_id,
success_url: success_payment_url,
fail_url: fail_payment_url,
cancel_url: cancel_payment_url,
cus_name: params[:name],
cus_email: params[:email],
cus_phone: params[:phone]
}
response = HTTParty.post(
'https://sandbox.sslcommerz.com/gwprocess/v4/api.php',
body: payload
)
result = JSON.parse(response.body)
if result['status'] == 'SUCCESS'
redirect_to result['GatewayPageURL'], allow_other_host: true
else
flash[:error] = result['failedreason']
redirect_to cart_path
end
end
end
9. Mobile App Integration (Android & iOS)
For mobile apps, SSLCommerz recommends using WebView-based hosted checkout rather than native SDKs (which SSLCommerz does not officially provide as of 2026). The approach:
- Backend initiates the payment session via API and returns
GatewayPageURL. - Mobile app opens the URL in a WebView (Android:
WebView, iOS:WKWebView). - Intercept redirects by monitoring URL changes. When the WebView navigates to your
success_urlpattern, extract theval_idfrom the URL or POST body. - Send
val_idto your backend for server-side validation (never validate on the device). - Display result to the user based on backend validation response.
Android WebView Example (Kotlin)
// PaymentActivity.kt
class PaymentActivity : AppCompatActivity() {
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
webView = findViewById(R.id.webView)
webView.settings.javaScriptEnabled = true
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
if (url.contains("/payment/success")) {
// Extract val_id and send to backend for validation
validatePaymentOnServer(url)
return true
}
return super.shouldOverrideUrlLoading(view, url)
}
}
// Load GatewayPageURL obtained from your backend
webView.loadUrl(gatewayPageUrl)
}
}
iOS WKWebView Example (Swift)
// PaymentViewController.swift
import WebKit
class PaymentViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView = WKWebView(frame: view.bounds)
webView.navigationDelegate = self
view.addSubview(webView)
webView.load(URLRequest(url: URL(string: gatewayPageUrl)!))
}
func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url?.absoluteString,
url.contains("/payment/success") {
validatePaymentOnServer(url: url)
decisionHandler(.cancel)
return
}
decisionHandler(.allow)
}
}
10. WooCommerce & WordPress Integration
SSLCommerz provides an official WordPress/WooCommerce plugin available on the WordPress plugin repository. However, for custom implementations or headless WooCommerce setups, you can integrate directly.
Official Plugin Method
- Go to Plugins → Add New in your WordPress admin.
- Search for "SSLCommerz" and install the official plugin by SSL Wireless.
- Navigate to WooCommerce → Settings → Payments → SSLCommerz.
- Enter your Store ID and Store Password for sandbox or production.
- Enable the payment method and save.
Headless/Custom WooCommerce Integration
If you're using WooCommerce as a headless backend (e.g., with React or Next.js frontend), you can call the WooCommerce REST API to create an order, then use the SSLCommerz API directly for payment processing. The key is to store the SSLCommerz tran_id as order meta data for later reconciliation.
11. Error Codes & Troubleshooting
Below are the most common operational issues faced by developers, DBAs, and MIS teams when integrating SSLCommerz with enterprise systems:
| Error/Issue | Symptom | Root Cause | Solution |
|---|---|---|---|
| IP Whitelisting | Production API returns "IP not allowed" | SSLCommerz whitelists server IPs in production | Email SSLCommerz support with your production server's static IP |
| Amount Mismatch | Validation passes but order not marked paid | Decimal precision mismatch (e.g., 1250 vs 1250.00) | Cast both amounts to float with 2 decimal places before comparison |
| Duplicate IPN | Same order processed twice | SSLCommerz may send IPN multiple times | Implement idempotency: check if order is already "Paid" before updating |
| Session Timeout | GatewayPageURL returns "Session Expired" | Session key has a TTL (~30 minutes) | Re-initiate payment if user takes too long |
| SSL Certificate Error | cURL error 60: SSL certificate problem | Outdated CA bundle on server | Update ca-certificates package; ensure CURLOPT_SSL_VERIFYPEER is true |
| val_id Missing | Redirect has no val_id | Payment was cancelled or failed silently | Check fail_url and cancel_url handlers; log all POST data |
| Database Deadlock | Order update hangs under high load | Multiple IPN + redirect hitting same row | Use row-level locking or optimistic locking with version numbers |
| ERP Sync Failure | Payment captured but ERP invoice not updated | Network timeout between systems | Implement retry queue (RabbitMQ, Redis) for ERP sync |
12. Security & Best Practices
- Always validate server-side: Never trust the browser redirect. Always call the Validation API with val_id.
- Use HTTPS everywhere: All callback URLs and IPN endpoints must use HTTPS in production.
- Store credentials securely: Use environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault). Never hardcode passwords.
- Implement idempotency: Check if the transaction ID already exists in your database with a "Paid" status before updating again.
- Log everything: Log all IPN payloads, validation responses, and errors for auditing and debugging.
- Rate limiting: Protect your IPN endpoint from abuse with rate limiting.
- Verify amounts precisely: Use decimal or string comparison for amounts to avoid floating-point rounding errors.
- Set reasonable timeouts: cURL/HTTP client timeouts should be 30-60 seconds to handle network latency.
13. Role‑Based Insights
For Developers
Focus on the three-step lifecycle. The most common pitfall is skipping server-side validation. Always test with sandbox dummy cards: Card Number: 4111111111111111, Exp: 12/28, CVV: 123. For bKash sandbox, use 01XXXXXXXXX format with password 123456 and OTP 123456.
For Architects
Design your system with an event-driven architecture. Treat IPN as the source of truth, not the redirect. Use a message queue to decouple payment processing from order fulfillment. This allows retries and prevents data loss during high traffic.
For DBAs
Create a dedicated payment_transactions table with columns: tran_id (unique index), val_id, amount, status, ssl_response_json (TEXT/JSONB), created_at, updated_at. Index tran_id for fast lookups. Use transactions with row-level locking to prevent race conditions.
For MIS & Finance Teams
Reconcile daily: Export SSLCommerz merchant panel reports and cross-check with your internal order database. Discrepancies often arise from IPN failures or network issues. Set up automated reconciliation scripts that run every 6 hours.
14. Real‑Life Business Cases
Case 1: Large E-Commerce Platform (500K+ Monthly Orders)
Challenge: During flash sales, 10,000+ concurrent payment attempts caused IPN processing bottlenecks. Orders were marked "Pending" indefinitely.
Solution: Implemented a Redis queue for IPN processing with 50 worker processes. Added idempotency checks using Redis locks. Reduced processing time from 45 seconds to under 2 seconds per transaction.
Case 2: University Tuition Fee Collection
Challenge: Students needed to pay semester fees via multiple methods (bKash, Nagad, cards). The finance team needed real-time ERP (Oracle) updates.
Solution: Integrated SSLCommerz with Oracle Financials via REST API. IPN triggers an Oracle stored procedure that updates the student ledger in real-time. Reduced manual reconciliation from 3 days to zero.
Case 3: SaaS Subscription Platform
Challenge: Recurring monthly billing with SSLCommerz (which doesn't natively support subscriptions).
Solution: Built a custom subscription engine that stores card tokens (via SSLCommerz tokenization where available) and triggers monthly payment API calls. Combined with IPN for confirmation.
15. ERP Integration Benchmarks
SSLCommerz integrates with virtually any ERP system via its REST API. Below is a benchmark of integration complexity and performance across popular ERP platforms:
SAP S/4HANA
Integration via SAP BTP Middleware
Complexity: High | Latency: ~3-5sMicrosoft Dynamics 365
Via Power Automate & Custom Connector
Complexity: Medium | Latency: ~2-3sOracle E-Business Suite
REST API with Oracle Integration Cloud
Complexity: High | Latency: ~4-6sOdoo (Community/Enterprise)
Native module + Webhook receiver
Complexity: Low | Latency: ~1-2sNextERP / Sun Systems
Custom API Gateway integration
Complexity: High | Latency: ~5-8sCustom In-House ERP (SQL Server)
Direct stored procedure call from IPN handler
Complexity: Low | Latency: ~0.5-1sCustom In-House ERP (Oracle DB)
PL/SQL procedure via OCI or REST wrapper
Complexity: Medium | Latency: ~1-2sRecommended Integration Pattern for ERPs
- IPN Listener receives payment confirmation from SSLCommerz.
- Message Queue (RabbitMQ/Kafka/Redis) buffers the event.
- ERP Adapter Service consumes the event and calls the ERP's API or database procedure.
- Dead Letter Queue captures failed attempts for manual reconciliation.

0 Comments
thanks for your comments!