Map and Location Illustration 1

Nagad支付配置教程

Nagad支付配置教程

📋 目录


🚀 Nagad平台介绍

什么是Nagad?

Nagad是孟加拉国邮政部门推出的官方数字支付平台,于2019年正式上线。作为政府背景的金融科技服务,Nagad在孟加拉国数字支付市场占据重要地位。

核心优势

  • 政府支持:国家邮政部门运营,政策扶持力度大
  • 网络覆盖:依托全国9,000+邮政网点和60万+代理商
  • 安全可靠:银行级安全标准,符合监管要求
  • 功能完善:支持转账、缴费、商户支付等全场景

市场数据

用户规模:4,800万+ 注册用户
日交易量:1,200万笔
市场份额:18%(移动支付领域)
商户数量:50万+ 活跃商户

主要服务

  • 个人服务:转账汇款、话费充值、账单缴费
  • 商户服务:线上支付、POS收款、批量转账
  • 政府服务:补贴发放、税费缴纳、公共缴费

📝 商户申请步骤

商户类型分级

等级 适用对象 月限额 费率 结算周期
基础商户 个体户、小店 300万塔卡 1.99%起 T+2
标准商户 中小企业 1,500万塔卡 1.75%起 T+1
企业商户 大型企业 无限制 1.55%起 T+0可选

申请材料准备

个人商户

必需材料:
✓ 国民身份证(NID)扫描件
✓ 手机号实名认证
✓ 银行账户证明
✓ 营业场所照片
✓ 业务说明书

企业商户

必需材料:
✓ 营业执照(Trade License)
✓ 税务登记证(TIN Certificate)
✓ 公司章程
✓ 法人身份证明
✓ 银行开户许可证
✓ 近12个月财务报表

申请流程时间

  • 基础商户:7-10个工作日
  • 标准商户:12-15个工作日
  • 企业商户:20-25个工作日

🔌 API接口说明

环境配置

bash
# 沙盒环境
API_URL=https://api-sandbox.mynagad.com/api/dfs

# 生产环境
API_URL=https://api.mynagad.com/api/dfs

核心接口流程

mermaid
sequenceDiagram
    participant 商户 as 商户系统
    participant Nagad as Nagad API
    participant 用户 as 用户
    
    商户->>Nagad: 1. 初始化支付
    Nagad->>商户: 2. 返回支付链接
    商户->>用户: 3. 跳转支付页面
    用户->>Nagad: 4. 完成支付
    Nagad->>商户: 5. 支付回调
    商户->>Nagad: 6. 确认支付状态

1. 支付初始化

http
POST /check-out/initialize/{merchant_id}
Content-Type: application/json
X-KM-Api-Version: v-0.2.0
X-KM-IP-V4: {client_ip}
X-KM-Client-Type: PC_WEB
X-KM-Signature: {digital_signature}

请求参数:
{
    "account_number": "01XXXXXXXXX",    // 商户手机号
    "amount": "100.50",                 // 交易金额
    "currency": "BDT",
    "challenge": "32位随机字符串",
    "datetime": "20241215120000",       // YYYYMMDDHHmmss
    "order_id": "ORDER_001",           // 商户订单号
    "product_name": "商品名称",
    "callback_url": "https://yoursite.com/callback"
}

成功响应:
{
    "status": "Success",
    "statusCode": "000",
    "redirectGatewayURL": "https://api.mynagad.com/redirect-url",
    "paymentReferenceId": "NGD_PAY_001",
    "callBackUrl": "https://yoursite.com/callback"
}

2. 支付完成确认

http
POST /check-out/complete/{payment_reference_id}

请求参数:
{
    "paymentRefId": "NGD_PAY_001",
    "challenge": "32位随机字符串"
}

成功响应:
{
    "status": "Success",
    "statusCode": "000",
    "gatwayTransactionId": "TXN_123456",
    "amount": "100.50",
    "orderId": "ORDER_001",
    "paymentDateTime": "2024-12-15 12:30:45"
}

3. 支付状态查询

http
GET /verify/payment/{payment_reference_id}

响应:
{
    "status": "Success",
    "statusCode": "000",
    "transactionStatus": "Success",    // Success/Pending/Failed
    "amount": "100.50",
    "orderId": "ORDER_001"
}

💻 代码集成示例

Node.js示例

javascript
const crypto = require('crypto');
const axios = require('axios');
const fs = require('fs');

class NagadPayment {
    constructor(config) {
        this.merchantId = config.merchantId;
        this.baseUrl = config.sandbox 
            ? 'https://api-sandbox.mynagad.com/api/dfs'
            : 'https://api.mynagad.com/api/dfs';
        
        // 加载RSA密钥
        this.privateKey = fs.readFileSync(config.privateKeyPath, 'utf8');
        this.publicKey = fs.readFileSync(config.publicKeyPath, 'utf8');
    }
    
    // 创建支付
    async createPayment(paymentData) {
        const url = `${this.baseUrl}/check-out/initialize/${this.merchantId}`;
        
        const requestData = {
            account_number: paymentData.merchantPhone,
            amount: paymentData.amount.toFixed(2),
            currency: 'BDT',
            challenge: this.generateChallenge(),
            datetime: this.getCurrentDateTime(),
            order_id: paymentData.orderId,
            product_name: paymentData.productName,
            callback_url: paymentData.callbackUrl
        };
        
        const headers = {
            'Content-Type': 'application/json',
            'X-KM-Api-Version': 'v-0.2.0',
            'X-KM-IP-V4': paymentData.clientIp || '127.0.0.1',
            'X-KM-Client-Type': 'PC_WEB',
            'X-KM-Signature': this.generateSignature(requestData)
        };
        
        try {
            const response = await axios.post(url, requestData, { headers });
            return { success: true, data: response.data };
        } catch (error) {
            return { success: false, error: error.response?.data || error.message };
        }
    }
    
    // 完成支付
    async completePayment(paymentRefId, challenge) {
        const url = `${this.baseUrl}/check-out/complete/${paymentRefId}`;
        
        const requestData = {
            paymentRefId: paymentRefId,
            challenge: challenge
        };
        
        const headers = {
            'Content-Type': 'application/json',
            'X-KM-Api-Version': 'v-0.2.0',
            'X-KM-IP-V4': '127.0.0.1',
            'X-KM-Client-Type': 'PC_WEB',
            'X-KM-Signature': this.generateSignature(requestData)
        };
        
        try {
            const response = await axios.post(url, requestData, { headers });
            return { success: true, data: response.data };
        } catch (error) {
            return { success: false, error: error.response?.data || error.message };
        }
    }
    
    // 生成数字签名
    generateSignature(data) {
        // 排序数据
        const sortedData = this.sortObject(data);
        const jsonString = JSON.stringify(sortedData);
        
        // 创建签名
        const sign = crypto.createSign('RSA-SHA256');
        sign.update(jsonString, 'utf8');
        return sign.sign(this.privateKey, 'base64');
    }
    
    // 递归排序对象
    sortObject(obj) {
        if (typeof obj !== 'object' || obj === null) return obj;
        if (Array.isArray(obj)) return obj.map(item => this.sortObject(item));
        
        const sorted = {};
        Object.keys(obj).sort().forEach(key => {
            sorted[key] = this.sortObject(obj[key]);
        });
        return sorted;
    }
    
    // 生成32位随机字符串
    generateChallenge() {
        return crypto.randomBytes(16).toString('hex');
    }
    
    // 获取当前时间戳
    getCurrentDateTime() {
        const now = new Date();
        return now.getFullYear().toString() +
               (now.getMonth() + 1).toString().padStart(2, '0') +
               now.getDate().toString().padStart(2, '0') +
               now.getHours().toString().padStart(2, '0') +
               now.getMinutes().toString().padStart(2, '0') +
               now.getSeconds().toString().padStart(2, '0');
    }
}

// 使用示例
const nagad = new NagadPayment({
    merchantId: 'YOUR_MERCHANT_ID',
    privateKeyPath: './keys/private_key.pem',
    publicKeyPath: './keys/public_key.pem',
    sandbox: true
});

// 创建支付
const result = await nagad.createPayment({
    merchantPhone: '01XXXXXXXXX',
    amount: 100.50,
    orderId: 'ORDER_001',
    productName: '测试商品',
    callbackUrl: 'https://yoursite.com/nagad/callback',
    clientIp: '192.168.1.1'
});

if (result.success) {
    console.log('支付链接:', result.data.redirectGatewayURL);
} else {
    console.error('支付创建失败:', result.error);
}

PHP示例

php
<?php
class NagadPayment {
    private $merchantId;
    private $baseUrl;
    private $privateKey;
    
    public function __construct($config) {
        $this->merchantId = $config['merchant_id'];
        $this->baseUrl = $config['sandbox'] 
            ? 'https://api-sandbox.mynagad.com/api/dfs'
            : 'https://api.mynagad.com/api/dfs';
        $this->privateKey = file_get_contents($config['private_key_path']);
    }
    
    public function createPayment($paymentData) {
        $url = $this->baseUrl . '/check-out/initialize/' . $this->merchantId;
        
        $requestData = [
            'account_number' => $paymentData['merchant_phone'],
            'amount' => number_format($paymentData['amount'], 2, '.', ''),
            'currency' => 'BDT',
            'challenge' => bin2hex(random_bytes(16)),
            'datetime' => date('YmdHis'),
            'order_id' => $paymentData['order_id'],
            'product_name' => $paymentData['product_name'],
            'callback_url' => $paymentData['callback_url']
        ];
        
        $headers = [
            'Content-Type: application/json',
            'X-KM-Api-Version: v-0.2.0',
            'X-KM-IP-V4: ' . ($_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'),
            'X-KM-Client-Type: PC_WEB',
            'X-KM-Signature: ' . $this->generateSignature($requestData)
        ];
        
        $response = $this->makeRequest('POST', $url, $requestData, $headers);
        return $response;
    }
    
    private function generateSignature($data) {
        ksort($data);
        $jsonString = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        
        $signature = '';
        openssl_sign($jsonString, $signature, $this->privateKey, OPENSSL_ALGO_SHA256);
        return base64_encode($signature);
    }
    
    private function makeRequest($method, $url, $data, $headers) {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_POST => ($method === 'POST'),
            CURLOPT_POSTFIELDS => ($method === 'POST') ? json_encode($data) : null
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        return json_decode($response, true);
    }
}

// 使用示例
$nagad = new NagadPayment([
    'merchant_id' => 'YOUR_MERCHANT_ID',
    'private_key_path' => './keys/private_key.pem',
    'sandbox' => true
]);

$result = $nagad->createPayment([
    'merchant_phone' => '01XXXXXXXXX',
    'amount' => 100.50,
    'order_id' => 'ORDER_001',
    'product_name' => '测试商品',
    'callback_url' => 'https://yoursite.com/nagad/callback'
]);

if ($result['status'] === 'Success') {
    header('Location: ' . $result['redirectGatewayURL']);
} else {
    echo '支付创建失败: ' . $result['message'];
}
?>

🔒 安全配置要点

1. RSA密钥管理

bash
# 生成2048位RSA密钥对
openssl genrsa -out private_key.pem 2048
openssl rsa -in private_key.pem -pubout -out public_key.pem

# 设置安全权限
chmod 600 private_key.pem
chmod 644 public_key.pem

2. IP白名单配置

javascript
// Nagad官方IP段
const NAGAD_IPS = [
    '103.205.128.0/24',
    '103.205.129.0/24', 
    '202.51.181.0/24'
];

// 验证回调IP
function validateCallbackIP(clientIP) {
    return NAGAD_IPS.some(ip => isIPInRange(clientIP, ip));
}

3. 签名验证

javascript
// 验证回调签名
function verifyCallback(callbackData, receivedSignature) {
    const expectedSignature = generateSignature(callbackData);
    return expectedSignature === receivedSignature;
}

// 处理回调
app.post('/nagad/callback', (req, res) => {
    const signature = req.headers['x-km-signature'];
    
    if (!verifyCallback(req.body, signature)) {
        return res.status(400).json({ error: 'Invalid signature' });
    }
    
    // 处理支付结果...
});

❓ 常见问题解决

错误码说明

错误码 含义 解决方案
100 请求格式错误 检查JSON格式和必需参数
102 数字签名无效 检查私钥和签名算法
103 商户凭证无效 验证商户ID和密钥
200 余额不足 提醒客户充值
300 系统内部错误 稍后重试或联系技术支持

常见问题

Q: 如何获得测试环境凭证? A: 联系Nagad技术支持或我们的客服 @zfxt01

Q: 支付成功但未收到回调怎么办? A: 使用支付查询接口主动查询订单状态

Q: 签名验证总是失败? A: 检查数据排序、JSON格式和RSA密钥是否正确

Q: 生产环境如何切换? A: 更改baseUrl并使用正式商户凭证

技术支持

如果遇到集成问题,可通过以下方式获得帮助:


本教程涵盖了Nagad支付集成的核心要点,帮助开发者快速接入孟加拉国主流支付方式。如需更详细的技术支持,请联系我们的专业团队。

Share This Story, Choose Your Platform!