Skip to content

VNPAY QR MMS Provider

The VNPAY QR MMS (Multi-Merchant System) provider enables dynamic QR code payments. Customers scan the QR code using any Vietnamese banking app to complete payment.

Overview

AttributeValue
Provider KeyVNPAY_QR_MMS
Payment Method100_QR_CODE
SettlementT+1
QR StandardVietQR / EMVCo

Features

  • Dynamic QR codes - Unique QR per transaction
  • Multi-bank support - Works with 40+ Vietnamese banks
  • Real-time IPN - Instant payment notifications
  • Automatic reconciliation - Daily settlement reports

Configuration

VNPAY QR MMS uses dynamic credential resolution via the credentialGetter pattern. Secret keys are fetched at runtime, allowing different merchants to have different credentials.

Application Configuration

typescript
import { MQPayComponent, MQPayBindingKeys, IMQPayOptions } from '@nx-3rd/mq-pay';

class MyApplication extends BaseApplication {
  preConfigure() {
    this.bind<IMQPayOptions>({ key: MQPayBindingKeys.MQ_PAY_CLIENT_OPTIONS })
      .toValue({
        // Credential getter for dynamic per-merchant secrets
        credentialGetter: async ({ provider, action, types, context }) => {
          // Fetch credentials from your secure storage (database, vault, etc.)
          return fetchCredentialsFromSecureStorage({ provider, action, types, context });
        },

        vnpayQrMMS: {
          enable: true,
          isDefault: true,
          enableController: true,

          // Required: VNPAY App ID
          appId: 'your-app-id',

          // Required: Master merchant code
          masterMerchantCode: 'your-merchant-code',

          // Environment flag
          isProduction: process.env.NODE_ENV === 'production',

          // Optional: Custom notification handler
          onPaymentNotification: async (ipnData) => {
            console.log('QR Payment received:', ipnData);
          },
        },
      });

    this.component(MQPayComponent);
  }
}

Configuration Options

OptionTypeRequiredDescription
enablebooleanYesEnable this provider
isDefaultbooleanYesUse as default provider
enableControllerbooleanYesAuto-register IPN endpoint
appIdstringYesVNPAY App ID from merchant registration
masterMerchantCodestringYesVNPAY merchant code
isProductionbooleanYestrue for production environment
onPaymentNotificationfunctionNoCustom IPN handler callback

Credential Mapping

Secret keys are fetched dynamically via credentialGetter:

Secret KeyActionType
createQr.requestCREATE_PAYMENTREQUEST
createQr.responseCREATE_PAYMENTRESPONSE
createQr.ipnVERIFY_IPNIPN
checkTransaction.requestCHECK_TRANSACTIONREQUEST
checkTransaction.responseCHECK_TRANSACTIONRESPONSE
refund.requestREFUNDREQUEST
refund.responseREFUNDRESPONSE

Payment Flow

API Usage

Create QR Payment

typescript
const response = await paymentService.checkout({
  source: {
    type: 'Order',
    id: 'order-uuid-123',
    uid: 'ORD-2024-001',
  },
  payment: {
    provider: 'VNPAY_QR_MMS',
    method: '100_QR_CODE',
    total: 150000,
    currency: 'VND',
  },
  expiration: {
    mode: 'duration',
    milliseconds: 300000, // 5 minutes
  },
});

// Response
{
  transaction: {
    id: 'txn-uuid',
    number: 'TXN001',
    status: '100_NEW',
    total: '150000.0000',
  },
  attempt: {
    id: 'att-uuid',
    code: 'ATT001',
    status: '204_SENT',
    provider: 'VNPAY_QR_MMS',
    method: '100_QR_CODE',
  },
  payment: {
    qrCode: '00020101021238570010A00000072701...',
    qrUrl: 'https://api.vnpay.vn/qrpay/...',
    qrDataUrl: 'data:image/png;base64,...',
    expiresAt: '2024-01-15T10:35:00Z',
  },
}

Query Payment Status

typescript
const status = await paymentService.queryStatus({
  attemptId: 'att-uuid',
});

// Response
{
  attempt: {
    id: 'att-uuid',
    status: '302_SUCCESS',
    paidAt: '2024-01-15T10:32:15Z',
  },
  providerData: {
    bankCode: 'VCB',
    bankTransactionNo: '20240115123456',
    customerName: 'NGUYEN VAN A',
  },
}

IPN (Instant Payment Notification)

IPN Endpoint

When enableController: true, MQ-Pay automatically registers:

POST /api/mq-pay/vnpay/qr-mms/ipn

IPN Data Structure

typescript
interface VNPayQrIPNData {
  vnp_TxnRef: string;        // Your attempt code (ATT001)
  vnp_TransactionNo: string; // VNPAY transaction number
  vnp_Amount: number;        // Amount in VND (multiply by 100)
  vnp_ResponseCode: string;  // '00' = success
  vnp_BankCode: string;      // VCB, TCB, MB, etc.
  vnp_PayDate: string;       // YYYYMMDDHHmmss
  vnp_SecureHash: string;    // HMAC-SHA512 signature
}

Response Codes

CodeDescriptionAction
00SuccessPayment completed
07Suspicious transactionContact VNPAY
11TimeoutQR expired
24CancelledCustomer cancelled
51Insufficient fundsCustomer issue
75Bank maintenanceRetry later

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.