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
| Attribute | Value |
|---|---|
| Provider Key | VNPAY_QR_MMS |
| Payment Method | 100_QR_CODE |
| Settlement | T+1 |
| QR Standard | VietQR / 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
| Option | Type | Required | Description |
|---|---|---|---|
enable | boolean | Yes | Enable this provider |
isDefault | boolean | Yes | Use as default provider |
enableController | boolean | Yes | Auto-register IPN endpoint |
appId | string | Yes | VNPAY App ID from merchant registration |
masterMerchantCode | string | Yes | VNPAY merchant code |
isProduction | boolean | Yes | true for production environment |
onPaymentNotification | function | No | Custom IPN handler callback |
Credential Mapping
Secret keys are fetched dynamically via credentialGetter:
| Secret Key | Action | Type |
|---|---|---|
createQr.request | CREATE_PAYMENT | REQUEST |
createQr.response | CREATE_PAYMENT | RESPONSE |
createQr.ipn | VERIFY_IPN | IPN |
checkTransaction.request | CHECK_TRANSACTION | REQUEST |
checkTransaction.response | CHECK_TRANSACTION | RESPONSE |
refund.request | REFUND | REQUEST |
refund.response | REFUND | RESPONSE |
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/ipnIPN 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
| Code | Description | Action |
|---|---|---|
00 | Success | Payment completed |
07 | Suspicious transaction | Contact VNPAY |
11 | Timeout | QR expired |
24 | Cancelled | Customer cancelled |
51 | Insufficient funds | Customer issue |
75 | Bank maintenance | Retry later |