NICTBD.COM Payment Gateway API Documentation
Build secure payment integration for your website, ecommerce store, Laravel application, PHP project, mobile app or custom platform using NICTBD.COM hosted checkout, PHP SDK, bKash payment gateway, Nagad payment gateway, HMAC signature verification, webhook/IPN and real-time payment verification.
Overview
NICTBD.COM provides an online payment gateway API for Bangladesh merchants who need secure payment collection through hosted checkout. Merchants can create payment sessions using API or PHP SDK, redirect customers to NICTBD.COM checkout, receive payment through supported payment methods, and update orders using webhook/IPN or payment verification API.
Core Features
This documentation covers the main features required for production-level payment gateway integration.
Payment Flow
NICTBD.COM follows a hosted checkout payment flow for secure and simple merchant integration.
API Credentials
After merchant approval, you will receive API credentials from the NICTBD.COM merchant dashboard.
| Credential | Example | Visibility | Usage |
|---|---|---|---|
| Store ID | STORE-2-FRXECLKM |
Public | Identifies your merchant store. |
| API Key | pk_live_xxxxxxxxx |
Public server-side | Used with Store ID for API authentication. |
| Secret Key | sk_live_xxxxxxxxx |
Private | Used to generate and verify HMAC SHA256 signature. Never expose it publicly. |
Create Payment API
Use this endpoint to create a new hosted checkout payment session.
https://www.nictbd.com/api/payment/create
Headers
Content-Type: application/json Accept: application/json
Request Parameters
| Field | Required | Type | Description |
|---|---|---|---|
| store_id | Required | string | Your NICTBD.COM Store ID. |
| api_key | Required | string | Your public API key. |
| amount | Required | decimal | Payment amount with two decimals. Example: 100.00 |
| tran_id | Required | string | Unique order or transaction ID from merchant website. |
| currency | Optional | string | Default: BDT |
| customer_name | Optional | string | Customer full name. |
| customer_mobile | Optional | string | Customer mobile number. |
| customer_email | Optional | Customer email address. | |
| success_url | Required | url | Customer redirect URL after successful payment. |
| failed_url | Required | url | Customer redirect URL after failed payment. |
| cancel_url | Required | url | Customer redirect URL after cancelled or timeout payment. |
| webhook_url | Optional | url | Server-to-server IPN URL for payment notification. |
| signature | Required | string | HMAC SHA256 signature. SDK users do not need to generate this manually. |
JSON Request Example
{
"store_id": "STORE-2-FRXECLKM",
"api_key": "pk_live_xxxxxxxxx",
"amount": "100.00",
"tran_id": "INV20260614010101",
"currency": "BDT",
"customer_name": "Rahim Uddin",
"customer_mobile": "01700000000",
"customer_email": "rahim@example.com",
"success_url": "https://merchant.com/payment/success",
"failed_url": "https://merchant.com/payment/failed",
"cancel_url": "https://merchant.com/payment/cancel",
"webhook_url": "https://merchant.com/api/payment/webhook",
"signature": "generated_hmac_signature"
}
Success Response
{
"status": "success",
"message": "Payment session created successfully.",
"session_id": "PS20260614010101XQBTDXM3J98E",
"payment_url": "https://nictbd.com/pay/PS20260614010101XQBTDXM3J98E"
}
Signature Generation
Signature confirms that the payment request was created from your real merchant server. NICTBD.COM checks this signature before creating a payment session.
store_id|tran_id|amount
STORE-2-FRXECLKM|INV20260614010101|100.00
PHP Signature
$signature = hash_hmac(
"sha256",
$storeId . "|" . $tranId . "|" . $amount,
$secretKey
);
100.00, request amount must also be 100.00.
Hosted Checkout
After successful payment session creation, redirect the customer to the returned
payment_url. Customer will complete payment on the NICTBD.COM hosted checkout page.
header("Location: " . $result["payment_url"]);
exit;
Customer Redirect After Payment
https://merchant.com/payment/success?status=success&tran_id=INV20260614010101&session_id=PS20260614010101XQBTDXM3J98E&message=Payment+completed+successfully.
Official PHP SDK Installation
NICTBD.COM PHP SDK is available for PHP and Laravel projects. Merchants can install it through Composer, create hosted checkout payments, verify payment status and keep Secret Key safely on the backend. Direct REST API is also available for any platform.
composer require nictbd/php-sdk
Basic PHP SDK Usage
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Nictbd\Client;
$client = new Client([
'base_url' => 'https://nictbd.com',
'store_id' => 'STORE-2-FRXECLKM',
'api_key' => 'pk_live_xxxxxxxxx',
'secret_key' => 'sk_live_xxxxxxxxx',
]);
$response = $client->createPayment([
'amount' => 100,
'tran_id' => 'INV' . date('YmdHis'),
'currency' => 'BDT',
'customer_name' => 'Rahim Uddin',
'customer_mobile' => '01700000000',
'customer_email' => 'rahim@example.com',
'success_url' => 'https://merchant.com/payment/success',
'failed_url' => 'https://merchant.com/payment/failed',
'cancel_url' => 'https://merchant.com/payment/cancel',
'webhook_url' => 'https://merchant.com/api/payment/webhook',
]);
if (($response['status'] ?? null) === 'success') {
header('Location: ' . $response['payment_url']);
exit;
}
echo $response['message'] ?? 'Payment create failed';
Laravel SDK Configuration
NICTBD_BASE_URL=https://nictbd.com NICTBD_STORE_ID=STORE-2-FRXECLKM NICTBD_API_KEY=pk_live_xxxxxxxxx NICTBD_SECRET_KEY=sk_live_xxxxxxxxx
'nictbd' => [
'base_url' => env('NICTBD_BASE_URL', 'https://nictbd.com'),
'store_id' => env('NICTBD_STORE_ID'),
'api_key' => env('NICTBD_API_KEY'),
'secret_key' => env('NICTBD_SECRET_KEY'),
],
Laravel SDK Usage
use Illuminate\Http\Request;
use Nictbd\Client;
public function pay(Request $request)
{
$client = new Client([
'base_url' => config('services.nictbd.base_url'),
'store_id' => config('services.nictbd.store_id'),
'api_key' => config('services.nictbd.api_key'),
'secret_key' => config('services.nictbd.secret_key'),
]);
$response = $client->createPayment([
'amount' => 100,
'tran_id' => 'INV' . now()->format('YmdHis'),
'currency' => 'BDT',
'customer_name' => 'Rahim Uddin',
'customer_mobile' => '01700000000',
'customer_email' => 'rahim@example.com',
'success_url' => route('payment.success'),
'failed_url' => route('payment.failed'),
'cancel_url' => route('payment.cancel'),
'webhook_url' => route('payment.webhook'),
]);
if (($response['status'] ?? null) === 'success') {
return redirect()->away($response['payment_url']);
}
return back()->with('error', $response['message'] ?? 'Payment create failed');
}
Official Composer package for PHP projects.
Available NowUse the PHP SDK from Laravel controller, service class or payment module.
SupportedMobile app calls merchant backend. Backend uses SDK or REST API and returns payment_url.
SupportedAny backend language can integrate through JSON REST API and HMAC signature.
Available NowPlatform Integration Examples
Choose SDK or REST API examples below. PHP and Laravel merchants should use the official PHP SDK when possible. Other platforms can use the REST API examples with backend-side HMAC signature.
PHP SDK Integration
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Nictbd\Client;
$client = new Client([
'base_url' => 'https://nictbd.com',
'store_id' => 'STORE-2-FRXECLKM',
'api_key' => 'pk_live_xxxxxxxxx',
'secret_key' => 'sk_live_xxxxxxxxx',
]);
$response = $client->createPayment([
'amount' => 100,
'tran_id' => 'INV' . date('YmdHis'),
'currency' => 'BDT',
'customer_name' => 'Rahim Uddin',
'customer_mobile' => '01700000000',
'customer_email' => 'rahim@example.com',
'success_url' => 'https://merchant.com/payment/success',
'failed_url' => 'https://merchant.com/payment/failed',
'cancel_url' => 'https://merchant.com/payment/cancel',
'webhook_url' => 'https://merchant.com/api/payment/webhook',
]);
if (($response['status'] ?? null) === 'success') {
header('Location: ' . $response['payment_url']);
exit;
}
echo $response['message'] ?? 'Payment create failed';
PHP REST Integration
$storeId = "STORE-2-FRXECLKM";
$apiKey = "pk_live_xxxxxxxxx";
$secret = "sk_live_xxxxxxxxx";
$tranId = "INV" . date("YmdHis");
$amount = "100.00";
$signature = hash_hmac(
"sha256",
$storeId . "|" . $tranId . "|" . $amount,
$secret
);
$payload = [
"store_id" => $storeId,
"api_key" => $apiKey,
"amount" => $amount,
"tran_id" => $tranId,
"currency" => "BDT",
"customer_name" => "Rahim Uddin",
"customer_mobile" => "01700000000",
"customer_email" => "rahim@example.com",
"success_url" => "https://merchant.com/payment/success",
"failed_url" => "https://merchant.com/payment/failed",
"cancel_url" => "https://merchant.com/payment/cancel",
"webhook_url" => "https://merchant.com/api/payment/webhook",
"signature" => $signature
];
$ch = curl_init("https://nictbd.com/api/payment/create");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Accept: application/json"
],
CURLOPT_POSTFIELDS => json_encode($payload)
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if (($result["status"] ?? null) === "success") {
header("Location: " . $result["payment_url"]);
exit;
}
echo $result["message"] ?? "Payment create failed";
Laravel REST Integration
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
public function pay(Request $request)
{
$storeId = config('services.nictbd.store_id');
$apiKey = config('services.nictbd.api_key');
$secretKey = config('services.nictbd.secret_key');
$tranId = 'INV' . now()->format('YmdHis');
$amount = number_format(100, 2, '.', '');
$signature = hash_hmac(
'sha256',
$storeId . '|' . $tranId . '|' . $amount,
$secretKey
);
$payload = [
'store_id' => $storeId,
'api_key' => $apiKey,
'amount' => $amount,
'tran_id' => $tranId,
'currency' => 'BDT',
'customer_name' => 'Rahim Uddin',
'customer_mobile' => '01700000000',
'customer_email' => 'rahim@example.com',
'success_url' => route('payment.success'),
'failed_url' => route('payment.failed'),
'cancel_url' => route('payment.cancel'),
'webhook_url' => route('payment.webhook'),
'signature' => $signature,
];
$response = Http::acceptJson()
->asJson()
->post(config('services.nictbd.base_url') . '/api/payment/create', $payload);
$result = $response->json();
if (($result['status'] ?? null) === 'success') {
return redirect()->away($result['payment_url']);
}
return back()->with('error', $result['message'] ?? 'Payment create failed.');
}
cURL Integration
curl -X POST "https://nictbd.com/api/payment/create" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"store_id": "STORE-2-FRXECLKM",
"api_key": "pk_live_xxxxxxxxx",
"amount": "100.00",
"tran_id": "INV20260614010101",
"currency": "BDT",
"customer_name": "Rahim Uddin",
"customer_mobile": "01700000000",
"customer_email": "rahim@example.com",
"success_url": "https://merchant.com/payment/success",
"failed_url": "https://merchant.com/payment/failed",
"cancel_url": "https://merchant.com/payment/cancel",
"webhook_url": "https://merchant.com/api/payment/webhook",
"signature": "generated_hmac_signature"
}'
PowerShell Integration
$storeId = "STORE-2-FRXECLKM"
$apiKey = "pk_live_xxxxxxxxx"
$tranId = "INV" + (Get-Date -Format "yyyyMMddHHmmss")
$amount = "100.00"
$secret = "sk_live_xxxxxxxxx"
$raw = "$storeId|$tranId|$amount"
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [Text.Encoding]::UTF8.GetBytes($secret)
$signature = ([BitConverter]::ToString(
$hmac.ComputeHash(
[Text.Encoding]::UTF8.GetBytes($raw)
)
)).Replace("-", "").ToLower()
$body = @{
store_id = $storeId
api_key = $apiKey
amount = $amount
tran_id = $tranId
currency = "BDT"
customer_name = "Rahim Uddin"
customer_mobile = "01700000000"
customer_email = "rahim@example.com"
success_url = "https://merchant.com/payment/success"
failed_url = "https://merchant.com/payment/failed"
cancel_url = "https://merchant.com/payment/cancel"
webhook_url = "https://merchant.com/api/payment/webhook"
signature = $signature
} | ConvertTo-Json -Depth 5
Invoke-RestMethod `
-Uri "https://nictbd.com/api/payment/create" `
-Method POST `
-Body $body `
-ContentType "application/json"
Node.js Integration
const crypto = require("crypto");
const storeId = "STORE-2-FRXECLKM";
const apiKey = "pk_live_xxxxxxxxx";
const secret = "sk_live_xxxxxxxxx";
const tranId = "INV" + new Date().toISOString().replace(/\D/g, "").slice(0, 14);
const amount = "100.00";
const raw = `${storeId}|${tranId}|${amount}`;
const signature = crypto
.createHmac("sha256", secret)
.update(raw)
.digest("hex");
const payload = {
store_id: storeId,
api_key: apiKey,
amount: amount,
tran_id: tranId,
currency: "BDT",
customer_name: "Rahim Uddin",
customer_mobile: "01700000000",
customer_email: "rahim@example.com",
success_url: "https://merchant.com/payment/success",
failed_url: "https://merchant.com/payment/failed",
cancel_url: "https://merchant.com/payment/cancel",
webhook_url: "https://merchant.com/api/payment/webhook",
signature: signature
};
const response = await fetch("https://nictbd.com/api/payment/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify(payload)
});
const result = await response.json();
if (result.status === "success") {
console.log("Redirect customer to:", result.payment_url);
} else {
console.log("Payment create failed:", result);
}
Python Integration
import time
import hmac
import hashlib
import requests
store_id = "STORE-2-FRXECLKM"
api_key = "pk_live_xxxxxxxxx"
secret = "sk_live_xxxxxxxxx"
tran_id = "INV" + time.strftime("%Y%m%d%H%M%S")
amount = "100.00"
raw = f"{store_id}|{tran_id}|{amount}"
signature = hmac.new(
secret.encode("utf-8"),
raw.encode("utf-8"),
hashlib.sha256
).hexdigest()
payload = {
"store_id": store_id,
"api_key": api_key,
"amount": amount,
"tran_id": tran_id,
"currency": "BDT",
"customer_name": "Rahim Uddin",
"customer_mobile": "01700000000",
"customer_email": "rahim@example.com",
"success_url": "https://merchant.com/payment/success",
"failed_url": "https://merchant.com/payment/failed",
"cancel_url": "https://merchant.com/payment/cancel",
"webhook_url": "https://merchant.com/api/payment/webhook",
"signature": signature
}
response = requests.post(
"https://nictbd.com/api/payment/create",
json=payload,
headers={"Accept": "application/json"}
)
result = response.json()
if result.get("status") == "success":
print("Redirect customer to:", result["payment_url"])
else:
print("Payment create failed:", result)
Ruby Integration
require "net/http"
require "json"
require "openssl"
require "time"
store_id = "STORE-2-FRXECLKM"
api_key = "pk_live_xxxxxxxxx"
secret = "sk_live_xxxxxxxxx"
tran_id = "INV" + Time.now.strftime("%Y%m%d%H%M%S")
amount = "100.00"
raw = "#{store_id}|#{tran_id}|#{amount}"
signature = OpenSSL::HMAC.hexdigest(
"SHA256",
secret,
raw
)
payload = {
store_id: store_id,
api_key: api_key,
amount: amount,
tran_id: tran_id,
currency: "BDT",
customer_name: "Rahim Uddin",
customer_mobile: "01700000000",
customer_email: "rahim@example.com",
success_url: "https://merchant.com/payment/success",
failed_url: "https://merchant.com/payment/failed",
cancel_url: "https://merchant.com/payment/cancel",
webhook_url: "https://merchant.com/api/payment/webhook",
signature: signature
}
uri = URI("https://nictbd.com/api/payment/create")
request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["Accept"] = "application/json"
request.body = payload.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
result = JSON.parse(response.body)
if result["status"] == "success"
puts "Redirect customer to: #{result["payment_url"]}"
else
puts result
end
Java Integration
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class NictbdPayment {
public static String hmacSha256(String data, String secret) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec key = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(key);
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : hash) {
hex.append(String.format("%02x", b));
}
return hex.toString();
}
public static void main(String[] args) throws Exception {
String storeId = "STORE-2-FRXECLKM";
String apiKey = "pk_live_xxxxxxxxx";
String secret = "sk_live_xxxxxxxxx";
String tranId = "INV" + System.currentTimeMillis();
String amount = "100.00";
String raw = storeId + "|" + tranId + "|" + amount;
String signature = hmacSha256(raw, secret);
String json = """
{
"store_id": "%s",
"api_key": "%s",
"amount": "%s",
"tran_id": "%s",
"currency": "BDT",
"customer_name": "Rahim Uddin",
"customer_mobile": "01700000000",
"customer_email": "rahim@example.com",
"success_url": "https://merchant.com/payment/success",
"failed_url": "https://merchant.com/payment/failed",
"cancel_url": "https://merchant.com/payment/cancel",
"webhook_url": "https://merchant.com/api/payment/webhook",
"signature": "%s"
}
""".formatted(storeId, apiKey, amount, tranId, signature);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://nictbd.com/api/payment/create"))
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
}
}
C# Integration
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
class Program
{
static string HmacSha256(string raw, string secret)
{
var key = Encoding.UTF8.GetBytes(secret);
using var hmac = new HMACSHA256(key);
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(raw));
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
static async Task Main()
{
string storeId = "STORE-2-FRXECLKM";
string apiKey = "pk_live_xxxxxxxxx";
string secret = "sk_live_xxxxxxxxx";
string tranId = "INV" + DateTime.Now.ToString("yyyyMMddHHmmss");
string amount = "100.00";
string raw = $"{storeId}|{tranId}|{amount}";
string signature = HmacSha256(raw, secret);
string json = $@"
{{
""store_id"": ""{storeId}"",
""api_key"": ""{apiKey}"",
""amount"": ""{amount}"",
""tran_id"": ""{tranId}"",
""currency"": ""BDT"",
""customer_name"": ""Rahim Uddin"",
""customer_mobile"": ""01700000000"",
""customer_email"": ""rahim@example.com"",
""success_url"": ""https://merchant.com/payment/success"",
""failed_url"": ""https://merchant.com/payment/failed"",
""cancel_url"": ""https://merchant.com/payment/cancel"",
""webhook_url"": ""https://merchant.com/api/payment/webhook"",
""signature"": ""{signature}""
}}";
using var client = new HttpClient();
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://nictbd.com/api/payment/create", content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}
Go Integration
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"time"
)
func hmacSha256(raw string, secret string) string {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(raw))
return hex.EncodeToString(h.Sum(nil))
}
func main() {
storeId := "STORE-2-FRXECLKM"
apiKey := "pk_live_xxxxxxxxx"
secret := "sk_live_xxxxxxxxx"
tranId := "INV" + time.Now().Format("20060102150405")
amount := "100.00"
raw := storeId + "|" + tranId + "|" + amount
signature := hmacSha256(raw, secret)
jsonBody := fmt.Sprintf(`{
"store_id": "%s",
"api_key": "%s",
"amount": "%s",
"tran_id": "%s",
"currency": "BDT",
"customer_name": "Rahim Uddin",
"customer_mobile": "01700000000",
"customer_email": "rahim@example.com",
"success_url": "https://merchant.com/payment/success",
"failed_url": "https://merchant.com/payment/failed",
"cancel_url": "https://merchant.com/payment/cancel",
"webhook_url": "https://merchant.com/api/payment/webhook",
"signature": "%s"
}`, storeId, apiKey, amount, tranId, signature)
req, _ := http.NewRequest(
"POST",
"https://nictbd.com/api/payment/create",
bytes.NewBuffer([]byte(jsonBody)),
)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Payment create request sent.")
}
Webhook / IPN Notification
After successful payment, NICTBD.COM sends a server-to-server webhook notification to your
webhook_url. Use this webhook/IPN to update your order status automatically.
Webhook Payload
{
"status": "success",
"tran_id": "INV20260614010101",
"transaction_uid": "TXN202606140101ABC",
"gateway_trx_id": "BKH123456789",
"amount": "100.00",
"charge_amount": "2.50",
"merchant_amount": "97.50",
"currency": "BDT",
"payment_method": "bkash",
"customer_name": "Rahim Uddin",
"customer_mobile": "01700000000",
"customer_email": "rahim@example.com",
"paid_at": "2026-06-14 01:10:00",
"signature": "webhook_hmac_signature"
}
Webhook Fields
| Field | Description |
|---|---|
| status | Payment status. Example: success |
| tran_id | Your merchant transaction/order ID. |
| transaction_uid | NICTBD.COM internal transaction ID. |
| gateway_trx_id | Original payment gateway transaction ID from payment provider. |
| amount | Customer paid gross amount. |
| charge_amount | Gateway charge deducted from merchant amount. |
| merchant_amount | Net amount credited or payable to merchant. |
| currency | Payment currency. Default: BDT |
| payment_method | Payment method code. Example: bkash, nagad |
| signature | Webhook HMAC signature. |
Webhook Signature Verify
Before updating your order as paid, verify the webhook signature using your Secret Key. This protects your system from fake payment notifications.
tran_id|amount|status
PHP Webhook Verify
$payload = json_decode(file_get_contents("php://input"), true);
$tranId = $payload["tran_id"] ?? "";
$amount = $payload["amount"] ?? "";
$status = $payload["status"] ?? "";
$signature = $payload["signature"] ?? "";
$secret = "sk_live_xxxxxxxxx";
$raw = $tranId . "|" . $amount . "|" . $status;
$expectedSignature = hash_hmac("sha256", $raw, $secret);
if (!hash_equals($expectedSignature, $signature)) {
http_response_code(401);
echo "Invalid signature";
exit;
}
if ($status === "success") {
// Find your order by $tranId
// Check amount with your order amount
// Update order as paid
// Save gateway_trx_id and transaction_uid
}
http_response_code(200);
echo "OK";
Laravel Webhook Verify
// routes/api.php
Route::post('/payment/webhook', [PaymentWebhookController::class, 'handle'])
->name('payment.webhook');
// Controller
use Illuminate\Http\Request;
public function handle(Request $request)
{
$secret = config('services.nictbd.secret_key');
$tranId = $request->input('tran_id');
$amount = $request->input('amount');
$status = $request->input('status');
$signature = $request->input('signature');
$raw = $tranId . '|' . $amount . '|' . $status;
$expectedSignature = hash_hmac('sha256', $raw, $secret);
if (!hash_equals($expectedSignature, $signature)) {
return response('Invalid signature', 401);
}
if ($status === 'success') {
// $order = Order::where('invoice_no', $tranId)->first();
// if ($order && number_format($order->amount, 2, '.', '') === number_format($amount, 2, '.', '')) {
// $order->update([
// 'payment_status' => 'paid',
// 'gateway_trx_id' => $request->gateway_trx_id,
// 'transaction_uid' => $request->transaction_uid,
// ]);
// }
}
return response('OK', 200);
}
Mobile App Integration
For Android, iOS, Flutter, React Native or any mobile app, do not call NICTBD.COM API directly from the app using Secret Key. Always call your own backend first.
payment_url in WebView, Custom Tab or external browser.
Backend Response to Mobile App
{
"status": "success",
"payment_url": "https://nictbd.com/pay/PS20260614010101XQBTDXM3J98E"
}
Laravel Backend API for Mobile App Using SDK
use Illuminate\Http\Request;
use Nictbd\Client;
public function createMobilePayment(Request $request)
{
$request->validate([
'order_id' => 'required|string',
'amount' => 'required|numeric|min:1',
]);
$client = new Client([
'base_url' => config('services.nictbd.base_url'),
'store_id' => config('services.nictbd.store_id'),
'api_key' => config('services.nictbd.api_key'),
'secret_key' => config('services.nictbd.secret_key'),
]);
$response = $client->createPayment([
'amount' => $request->amount,
'tran_id' => $request->order_id,
'currency' => 'BDT',
'customer_name' => $request->customer_name,
'customer_mobile' => $request->customer_mobile,
'customer_email' => $request->customer_email,
'success_url' => route('payment.success'),
'failed_url' => route('payment.failed'),
'cancel_url' => route('payment.cancel'),
'webhook_url' => route('payment.webhook'),
]);
return response()->json($response);
}
Flutter Example
// 1. Call your backend to create payment // 2. Backend returns payment_url // 3. Open payment_url using url_launcher or WebView final paymentUrl = response['payment_url']; // url_launcher example: // await launchUrl( // Uri.parse(paymentUrl), // mode: LaunchMode.externalApplication // );
Android Kotlin Example
// Open NICTBD.COM hosted checkout URL val intent = Intent(Intent.ACTION_VIEW, Uri.parse(paymentUrl)) startActivity(intent)
React Native Example
import { Linking } from "react-native";
// paymentUrl returned from your backend
Linking.openURL(paymentUrl);
Secret Key inside APK, IPA, Flutter app, React Native app or frontend code.
Secret Key must stay on your backend server only.
Payment Verify / Status API
Merchants can verify payment status using Store ID, API Key, transaction ID and signature. This is useful for checking the final payment status before order delivery.
https://www.nictbd.com/api/payment/verify
Recommended Verify Signature
store_id|tran_id
Note: This signature authenticates the merchant request. Amount is not included because transaction data is already stored and secured in the system.
Verify Request
{
"store_id": "STORE-2-FRXECLKM",
"api_key": "pk_live_xxxxxxxxx",
"tran_id": "INV20260614010101",
"signature": "generated_verify_signature"
}
PHP SDK Verify Payment
use Nictbd\Client;
$client = new Client([
'base_url' => 'https://nictbd.com',
'store_id' => 'STORE-2-FRXECLKM',
'api_key' => 'pk_live_xxxxxxxxx',
'secret_key' => 'sk_live_xxxxxxxxx',
]);
$response = $client->verifyPayment([
'tran_id' => 'INV20260614010101',
]);
if (($response['status'] ?? null) === 'success') {
// Payment verified successfully
}
Verify Response
{
"status": "success",
"tran_id": "INV20260614010101",
"transaction_uid": "TXN202606140101ABC",
"gateway_trx_id": "BKH123456789",
"amount": "100.00",
"charge_amount": "2.50",
"merchant_amount": "97.50",
"currency": "BDT",
"payment_method": "bkash",
"paid_at": "2026-06-14 01:10:00"
}
Error Codes
NICTBD.COM API returns JSON error responses when a payment request is invalid.
| HTTP Code | Message | Reason | Solution |
|---|---|---|---|
| 401 | Invalid merchant credentials. | Store ID or API Key is wrong or inactive. | Check merchant dashboard API credentials. |
| 401 | Invalid signature. | HMAC signature mismatch. | Use exact raw string: store_id|tran_id|amount. |
| 422 | Duplicate transaction ID. | Same tran_id already used. |
Use unique invoice/order ID for every payment. |
| 422 | Validation failed. | Required field missing or invalid format. | Check request parameters and URL fields. |
| 500 | Something went wrong. | Temporary server or processing issue. | Retry later or contact NICTBD.COM support. |
Security Checklist
Follow this checklist before going live with NICTBD.COM payment gateway integration.
- Use HTTPS on your website, webhook URL and success/failed/cancel URLs.
- Keep Secret Key only on your backend server.
- Never expose Secret Key in frontend JavaScript or mobile app code.
- Always verify webhook signature before updating order status.
- Use unique
tran_idfor every payment request. - Store gateway transaction ID for future support and reconciliation.
- Do not deliver service only based on customer redirect. Confirm webhook or status verify first.
- Log request, response and webhook payload for troubleshooting.
- Handle duplicate webhook safely to avoid double order processing.
- Do not change order status if amount does not match your order amount.