Chuyển tới nội dung chính

Snapshot trạng thái thanh toán

API snapshot cho phép các bên external (không phải Payment Hub) báo cáo trạng thái thanh toán hoặc refund (thành công hoặc thất bại) để Payment Hub ghi nhận (snapshot) lại trạng thái trên hệ thống của mình (không gọi sang payment provider). Đây là tính năng tùy chọn, không phải tất cả các bên đều cần sử dụng.

Tổng quan

Payment Hub hỗ trợ 2 loại snapshot:

  • Snapshot Transaction: Báo cáo trạng thái thanh toán (COMPLETED/FAILED)
  • Snapshot Refund: Báo cáo trạng thái refund (COMPLETED/FAILED)

Cả 2 API đều:

  • Ghi nhận (snapshot) trạng thái payment/refund trực tiếp trên transaction/refund tại Payment Hub (theo dữ liệu external gửi lên)
  • Không thực hiện bất kỳ nghiệp vụ nào với payment provider (không capture/refund/... trên provider; chỉ xử lý nội bộ trong Payment Hub)
  • Verify secureHash và validate tính đúng đắn của dữ liệu (merchant, user, payment method, provider, transaction, v.v.) theo đúng rule của từng API
  • Routing qua MuleSoft (giống các API khác)

1. Snapshot Transaction Status

Snapshot trạng thái thanh toán từ external system vào Payment Hub.

Endpoint: POST /api/payments/v1/transactions/snapshot

Headers:

HeaderRequiredMô tả
X-Payment-API-KeyAPI key của merchant/terminal
X-Request-IDUnique request ID (UUID) để đảm bảo idempotency và request tracing
X-TimestampUnix timestamp in seconds
X-MiniApp-User-IDID mà VSF cung cấp cho user MiniApp để SuperApp hiển thị & quản trị. PnL tạo transaction cho user nào thì truyền đúng miniAppUserId của user đó lên. Payment sẽ enrich chính xác thông tin v-app-user-id từ IAM. Nếu không enrich được sẽ trả về lỗi
X-Auth-AudienceAudience identifier (thường là v-app)
client_idClient ID để authenticate với MuleSoft
client_secretClient secret để authenticate với MuleSoft
Content-Typeapplication/json
Lưu ý quan trọng
  • Bắt buộc gửi header X-Request-ID (UUID) cho mỗi request để đảm bảo idempotency và request tracing
  • Bắt buộc gửi header X-Timestamp (Unix timestamp in seconds) cho validation và security
  • API có cơ chế kiểm tra duplicate request dựa trên X-Request-ID

Request Body:

Request body bao gồm các thông tin cơ bản tương tự như initPayment (trừ paymentTypeskipHolding):

{
"orderId": "ORDER_001",
"referenceId": "REF_123456",
"amount": 300000.0,
"currency": "VND",
"description": "Payment for order: OrderId_1761297780725",
"providerId": "067d848c-2fc8-4565-985e-f18b78fb9c7e",
"paymentMethodCode": "INTERNATIONAL_CARD",
"status": "COMPLETED",
"processedAt": 1705320600000,
"providerTransactionId": "provider_txn_001",
"businessUnitId": "BU_VINFAST_001",
"branchId": "BR_HN_001",
"orderInfo": {
"customerName": "TestCustomer",
"customerEmail": "[email protected]",
"customerPhone": "0123456789",
"orderCreatedAt": 1761297780725,
"items": [
{
"name": "Test Item",
"sku": "SKU_001",
"quantity": 1,
"unitPrice": 100000.0,
"description": "Description for Test Item",
"categoryCode": "CAT_ELECTRONICS",
"categoryName": "Electronics"
}
]
},
"secureHash": "a1b2c3d4e5f6..."
}
FieldTypeRequiredMô tả
orderIdstringID đơn hàng
referenceIdstringMã tham chiếu
amountnumberSố tiền thanh toán (integer hoặc float, minor unit)
currencystringĐơn vị tiền tệ (VD: VND, USD)
descriptionstringMô tả đơn hàng
providerIdstringID payment provider
paymentMethodCodestringMã phương thức thanh toán
statusstringTrạng thái thanh toán: COMPLETED hoặc FAILED
processedAtnumberUnix timestamp in milliseconds (UTC) - thời điểm xử lý thanh toán
providerTransactionIdstringID giao dịch từ payment provider (nếu có)
businessUnitIdstringMã cơ sở kinh doanh (Business Unit ID)
branchIdstringMã chi nhánh
orderInfoobjectThông tin đơn hàng chi tiết (CustomerOrderInfo)
orderInfo.customerNamestringTên khách hàng
orderInfo.customerEmailstringEmail khách hàng
orderInfo.customerPhonestringSố điện thoại khách hàng
orderInfo.orderCreatedAtnumberUnix timestamp (milliseconds) khi đơn hàng được tạo
orderInfo.itemsarrayDanh sách sản phẩm/dịch vụ trong đơn hàng
orderInfo.items[].namestringTên sản phẩm
orderInfo.items[].skustringMã SKU sản phẩm
orderInfo.items[].quantitynumberSố lượng
orderInfo.items[].unitPricenumberGiá đơn vị
orderInfo.items[].descriptionstringMô tả sản phẩm
orderInfo.items[].categoryCodestringMã danh mục/ngành hàng (optional)
orderInfo.items[].categoryNamestringTên danh mục/ngành hàng (optional)
secureHashstringChữ ký SHA-256 để verify tính toàn vẹn dữ liệu

Lưu ý:

  • Bắt buộc phải truyền cả orderIdreferenceId (cặp định danh transaction ở Payment Hub)
  • Payment Hub sẽ kiểm tra transaction theo cặp orderId + referenceId:
    • Nếu đã tồn tại: không snapshot và trả lỗi 409 (4091 Duplicate referenceId)
    • Nếu chưa tồn tại: tạo transaction và ghi nhận (snapshot) trạng thái theo dữ liệu request
  • status chỉ chấp nhận giá trị COMPLETED hoặc FAILED
  • Nếu status = FAILED, bắt buộc phải truyền errorCodeerrorMessage trong request body

SecureHash Formula:

Công thức tương tự như initPayment nhưng không có paymentTypeskipHolding, và có thêm statusprocessedAt:

HMAC-SHA-256(secretKey, orderId + '|' + referenceId + '|' + amount + '|' + currency + '|' + orderInfo.orderCreatedAt + '|' + branchId + '|' + businessUnitId + '|' + status + '|' + processedAt + '|' + timestamp)

Lưu ý:

  • timestamp trong secureHash là giá trị X-Timestamp header (Unix timestamp in seconds), không phải processedAt
  • Lưu ý Amount Hash: amount được lấy phần nguyên (integer part string) để hash.
  • Thứ tự append: orderId|referenceId|amount|currency|orderCreatedAtbranchId (nếu có) → businessUnitId (nếu có) → statusprocessedAttimestamp
  • KHÔNGpaymentTypeskipHolding trong secureHash

Success Response (200):

{
"code": 0,
"message": "Thành công"
}

Error Responses:

HTTP StatusCodeMessageMô tả
4004001Invalid requestRequest không hợp lệ
4004016Invalid statusStatus không hợp lệ (chỉ chấp nhận COMPLETED hoặc FAILED)
4004017Missing error informationThiếu errorCode/errorMessage khi status = FAILED
4094091Duplicate referenceIdTransaction đã tồn tại theo cặp orderId + referenceId
4014100Invalid API keyAPI Key không hợp lệ
4034200Resource does not belong to this userGiao dịch không thuộc merchant/terminal
4044302User not foundKhông thể enrich thông tin từ X-MiniApp-User-ID (không gọi được IAM hoặc user không tồn tại)
5005000Internal server errorLỗi hệ thống

Example (status COMPLETED):

curl -X 'POST' \
'https://api.example.com/api/payments/v1/transactions/snapshot' \
-H 'X-Payment-API-Key: <your_api_key>' \
-H 'X-Request-ID: 550e8400-e29b-41d4-a716-446655440000' \
-H 'X-Timestamp: 1760677974' \
-H 'X-MiniApp-User-ID: 109306626' \
-H 'X-Auth-Audience: v-app' \
-H 'client_id: YOUR_CLIENT_ID' \
-H 'client_secret: YOUR_CLIENT_SECRET' \
-H 'Content-Type: application/json' \
-d '{
"orderId": "ORDER_001",
"referenceId": "REF_123456",
"amount": 300000.0,
"currency": "VND",
"description": "Payment for order: OrderId_1761297780725",
"providerId": "067d848c-2fc8-4565-985e-f18b78fb9c7e",
"paymentMethodCode": "INTERNATIONAL_CARD",
"status": "COMPLETED",
"processedAt": 1705320600000,
"providerTransactionId": "provider_txn_001",
"businessUnitId": "BU_VINFAST_001",
"branchId": "BR_HN_001",
"orderInfo": {
"customerName": "TestCustomer",
"customerEmail": "[email protected]",
"customerPhone": "0123456789",
"orderCreatedAt": 1761297780725,
"items": [
{
"name": "Test Item",
"sku": "SKU_001",
"quantity": 1,
"unitPrice": 100000.0,
"description": "Description for Test Item",
"categoryCode": "CAT_ELECTRONICS",
"categoryName": "Electronics"
}
]
},
"secureHash": "a1b2c3d4e5f6..."
}'

Example (status FAILED):

curl -X 'POST' \
'https://api.example.com/api/payments/v1/transactions/snapshot' \
-H 'X-Payment-API-Key: <your_api_key>' \
-H 'X-Request-ID: 550e8400-e29b-41d4-a716-446655440001' \
-H 'X-Timestamp: 1760677974' \
-H 'X-MiniApp-User-ID: 109306626' \
-H 'X-Auth-Audience: v-app' \
-H 'client_id: YOUR_CLIENT_ID' \
-H 'client_secret: YOUR_CLIENT_SECRET' \
-H 'Content-Type: application/json' \
-d '{
"orderId": "ORDER_001",
"referenceId": "REF_123456",
"amount": 300000.0,
"currency": "VND",
"description": "Payment for order: OrderId_1761297780725",
"providerId": "067d848c-2fc8-4565-985e-f18b78fb9c7e",
"paymentMethodCode": "INTERNATIONAL_CARD",
"status": "FAILED",
"processedAt": 1705320600000,
"providerTransactionId": "provider_txn_001",
"businessUnitId": "BU_VINFAST_001",
"branchId": "BR_HN_001",
"orderInfo": {
"customerName": "TestCustomer",
"customerEmail": "[email protected]",
"customerPhone": "0123456789",
"orderCreatedAt": 1761297780725,
"items": [
{
"name": "Test Item",
"sku": "SKU_001",
"quantity": 1,
"unitPrice": 100000.0,
"description": "Description for Test Item",
"categoryCode": "CAT_ELECTRONICS",
"categoryName": "Electronics"
}
]
},
"errorCode": "PAYMENT_FAILED",
"errorMessage": "Insufficient funds",
"secureHash": "a1b2c3d4e5f6..."
}'

JavaScript Example:

// Example: Snapshot transaction status
const snapshotTransactionStatus = async (paymentData, secretKey, paymentApiKey, userId, clientId, clientSecret) => {
// Generate timestamp (Unix timestamp in seconds)
const timestamp = Math.floor(Date.now() / 1000)

// Generate secureHash (tương tự initPayment nhưng không có paymentType và skipHolding)
// Base: orderId|referenceId|amount|currency|orderCreatedAt
// Append branchId if exists, then businessUnitId if exists, then status, then processedAt, then timestamp
let rawDataString = `${paymentData.orderId}|${paymentData.referenceId}|${paymentData.amount}|${paymentData.currency}|${paymentData.orderInfo.orderCreatedAt}`
if (paymentData.branchId) {
rawDataString += `|${paymentData.branchId}`
}
if (paymentData.businessUnitId) {
rawDataString += `|${paymentData.businessUnitId}`
}
rawDataString += `|${paymentData.status}|${paymentData.processedAt}|${timestamp}`
const secureHash = await generateSecureHash(rawDataString, secretKey)

// Generate unique request ID for idempotency
const requestId = crypto.randomUUID()

const requestBody = {
...paymentData,
secureHash,
}

const response = await fetch('{MULE_INTERNAL_BASE_URL}/payment-hub/api/payments/v1/transactions/snapshot', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Payment-API-Key': paymentApiKey,
'X-Request-ID': requestId,
'X-Timestamp': timestamp.toString(),
'X-MiniApp-User-ID': userId,
'X-Auth-Audience': 'v-app',
'client_id': clientId,
'client_secret': clientSecret,
},
body: JSON.stringify(requestBody),
})

return response.json()
}

// Helper function to generate secureHash (HMAC-SHA-256)
async function generateSecureHash(data, hashKey) {
const encoder = new TextEncoder()
const keyData = encoder.encode(hashKey)
const cryptoKey = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign'],
)
const message = encoder.encode(data)
const signature = await crypto.subtle.sign('HMAC', cryptoKey, message)
const hashArray = Array.from(new Uint8Array(signature))
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
}

Lưu ý về logic xử lý:

  • Payment Hub sẽ:
    1. Verify secureHash trước khi xử lý
    2. Enrich thông tin v-app-user-id từ IAM dựa trên X-MiniApp-User-ID header
    3. Kiểm tra transaction theo cặp orderId + referenceId:
      • Nếu đã tồn tại: trả 409 / 4091 và không snapshot
      • Nếu chưa tồn tại: tạo transaction và ghi nhận (snapshot) trạng thái theo dữ liệu request
    4. Update các field liên quan theo thiết kế nội bộ (status, processedAt, providerTransactionId, error info nếu có, v.v.)
    5. Không gọi sang payment provider, không thực hiện capture/refund/... trên provider
    6. Trả về kết quả đồng bộ cho client

2. Snapshot Refund Status

Snapshot trạng thái refund từ external system vào Payment Hub.

Endpoint: POST /api/payments/v1/refunds/snapshot

Headers:

HeaderRequiredMô tả
X-Payment-API-KeyAPI key của merchant/terminal
X-Request-IDUnique request ID (UUID) để đảm bảo idempotency và request tracing
X-TimestampUnix timestamp in seconds
Content-Typeapplication/json
Lưu ý quan trọng
  • Bắt buộc gửi header X-Request-ID (UUID) cho mỗi request để đảm bảo idempotency và request tracing
  • Bắt buộc gửi header X-Timestamp (Unix timestamp in seconds) cho validation và security
  • API có cơ chế kiểm tra duplicate request dựa trên X-Request-ID

Request Body:

{
"transactionId": "txn_123456789",
"amount": 100000,
"currency": "VND",
"refundReferenceId": "refund_001",
"refundType": "full",
"status": "COMPLETED",
"processedAt": 1705320600000,
"secureHash": "a1b2c3d4e5f6..."
}
FieldTypeRequiredMô tả
transactionIdstringID của giao dịch cần refund
amountnumberSố tiền refund (integer minor unit)
currencystringĐơn vị tiền tệ (VD: VND, USD)
refundReferenceIdstringReference ID cho refund
refundTypestringLoại refund: full hoặc partial
statusstringTrạng thái refund: COMPLETED hoặc FAILED
processedAtnumberUnix timestamp in milliseconds (UTC) - thời điểm xử lý refund
errorCodestringMã lỗi (bắt buộc nếu status = FAILED)
errorMessagestringThông báo lỗi (bắt buộc nếu status = FAILED)
secureHashstringChữ ký SHA-256 để verify tính toàn vẹn dữ liệu

Lưu ý:

  • Bắt buộc phải truyền transactionId (ID của transaction gốc cần refund)
  • status chỉ chấp nhận giá trị COMPLETED hoặc FAILED
  • Nếu status = FAILED, bắt buộc phải truyền errorCodeerrorMessage

SecureHash Formula:

HMAC-SHA-256(secretKey, transactionId + '|' + amount + '|' + currency + '|' + refundReferenceId + '|' + refundType + '|' + status + '|' + processedAt + '|' + timestamp)

Lưu ý:

  • timestamp trong secureHash là giá trị X-Timestamp header (Unix timestamp in seconds), không phải processedAt
  • Lưu ý Amount Hash: amount được lấy phần nguyên (integer part string) để hash.
  • Thứ tự: transactionId|amount|currency|refundReferenceId|refundType|status|processedAt|timestamp

Success Response (200):

{
"code": 0,
"message": "Thành công"
}

Error Responses:

HTTP StatusCodeMessageMô tả
4004001Invalid requestRequest không hợp lệ
4004016Invalid statusStatus không hợp lệ (chỉ chấp nhận COMPLETED hoặc FAILED)
4004017Missing error informationThiếu errorCode/errorMessage khi status = FAILED
4094092Duplicate refundReferenceIdRefund đã tồn tại theo transactionId + refundReferenceId
4014100Invalid API keyAPI Key không hợp lệ
4034200Resource does not belong to this userRefund không thuộc merchant/terminal
4044301Transaction not foundKhông tìm thấy giao dịch
5005000Internal server errorLỗi hệ thống

Example (status COMPLETED):

curl -X 'POST' \
'https://api.example.com/api/payments/v1/refunds/snapshot' \
-H 'X-Payment-API-Key: <your_api_key>' \
-H 'X-Request-ID: 550e8400-e29b-41d4-a716-446655440000' \
-H 'X-Timestamp: 1760677974' \
-H 'Content-Type: application/json' \
-d '{
"transactionId": "txn_123456789",
"amount": 100000,
"currency": "VND",
"refundReferenceId": "refund_001",
"refundType": "full",
"status": "COMPLETED",
"processedAt": 1705320600000,
"secureHash": "a1b2c3d4e5f6..."
}'

Example (status FAILED):

curl -X 'POST' \
'https://api.example.com/api/payments/v1/refunds/snapshot' \
-H 'X-Payment-API-Key: <your_api_key>' \
-H 'X-Request-ID: 550e8400-e29b-41d4-a716-446655440001' \
-H 'X-Timestamp: 1760677974' \
-H 'Content-Type: application/json' \
-d '{
"transactionId": "txn_123456789",
"amount": 100000,
"currency": "VND",
"refundReferenceId": "refund_001",
"refundType": "full",
"status": "FAILED",
"processedAt": 1705320600000,
"errorCode": "REFUND_FAILED",
"errorMessage": "Insufficient balance",
"secureHash": "a1b2c3d4e5f6..."
}'

JavaScript Example:

// Example: Snapshot refund status
const snapshotRefundStatus = async (refundData, secretKey, paymentApiKey, userId) => {
// Generate timestamp (Unix timestamp in seconds)
const timestamp = Math.floor(Date.now() / 1000)

// Generate secureHash
// transactionId|amount|currency|refundReferenceId|refundType|status|processedAt|timestamp
const rawDataString = `${refundData.transactionId}|${refundData.amount}|${refundData.currency}|${refundData.refundReferenceId}|${refundData.refundType}|${refundData.status}|${refundData.processedAt}|${timestamp}`
const secureHash = await generateSecureHash(rawDataString, secretKey)

// Generate unique request ID for idempotency
const requestId = crypto.randomUUID()

const requestBody = {
...refundData,
secureHash,
}

const response = await fetch('/api/payments/v1/refunds/snapshot', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Payment-API-Key': paymentApiKey,
'X-Request-ID': requestId,
'X-Timestamp': timestamp.toString()
},
body: JSON.stringify(requestBody),
})

return response.json()
}

// Helper function to generate secureHash (HMAC-SHA-256)
async function generateSecureHash(data, hashKey) {
const encoder = new TextEncoder()
const keyData = encoder.encode(hashKey)
const cryptoKey = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign'],
)
const message = encoder.encode(data)
const signature = await crypto.subtle.sign('HMAC', cryptoKey, message)
const hashArray = Array.from(new Uint8Array(signature))
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
}

Lưu ý về logic xử lý:

  • Payment Hub sẽ:
    1. Verify secureHash trước khi xử lý
    2. Tìm transaction dựa trên transactionId
    3. Kiểm tra refund theo transactionId + refundReferenceId:
      • Nếu đã tồn tại: trả 409 / 4092 và không snapshot
      • Nếu chưa tồn tại: tạo refund và ghi nhận (snapshot) trạng thái theo dữ liệu request
    4. Không gọi sang payment provider, không thực hiện refund/void/... trên provider
    5. Trả về kết quả đồng bộ cho client

Sinh SecureHash cho Snapshot APIs

Công thức và Format

Sử dụng HMAC-SHA-256 với format data tương ứng cho từng API:

APIRaw Data String Format
Snapshot TransactionorderId + '|' + referenceId + '|' + amount + '|' + currency + '|' + orderCreatedAt + '|' + branchId + '|' + businessUnitId + '|' + status + '|' + processedAt + '|' + timestamp
Lưu ý: Không có paymentTypeskipHolding trong secureHash
Snapshot RefundtransactionId + '|' + amount + '|' + currency + '|' + refundReferenceId + '|' + refundType + '|' + status + '|' + processedAt + '|' + timestamp

Sample Code

async function getExpectedHash(data, hashKey) {
const encoder = new TextEncoder()
const keyData = encoder.encode(hashKey)
const cryptoKey = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign'],
)
const message = encoder.encode(data)
const signature = await crypto.subtle.sign('HMAC', cryptoKey, message)
const hashArray = Array.from(new Uint8Array(signature))
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
}

// Example for Snapshot Transaction
const snapshotTransactionData = {
orderId: 'ORDER_001',
referenceId: 'REF_123456',
amount: '300000',
currency: 'VND',
orderCreatedAt: '1761297780725',
branchId: 'BR_HN_001',
businessUnitId: 'BU_VINFAST_001',
status: 'COMPLETED',
processedAt: '1705320600000',
timestamp: '1760677974',
}
getExpectedHash(
`${snapshotTransactionData.orderId}|${snapshotTransactionData.referenceId}|${snapshotTransactionData.amount}|${snapshotTransactionData.currency}|${snapshotTransactionData.orderCreatedAt}|${snapshotTransactionData.branchId}|${snapshotTransactionData.businessUnitId}|${snapshotTransactionData.status}|${snapshotTransactionData.processedAt}|${snapshotTransactionData.timestamp}`,
'sk_dev_xx7ca9hvyneral068d06mr2l5tb3',
).then(h => console.log('Snapshot Transaction Hash =', h))

// Example for Snapshot Refund
const snapshotRefundData = {
transactionId: 'txn_123456789',
amount: '100000',
currency: 'VND',
refundReferenceId: 'refund_001',
refundType: 'full',
status: 'COMPLETED',
processedAt: '1705320600000',
timestamp: '1760677974',
}
getExpectedHash(
`${snapshotRefundData.transactionId}|${snapshotRefundData.amount}|${snapshotRefundData.currency}|${snapshotRefundData.refundReferenceId}|${snapshotRefundData.refundType}|${snapshotRefundData.status}|${snapshotRefundData.processedAt}|${snapshotRefundData.timestamp}`,
'sk_dev_xx7ca9hvyneral068d06mr2l5tb3',
).then(h => console.log('Snapshot Refund Hash =', h))

Lưu ý quan trọng

  • Sử dụng HMAC-SHA-256 để tạo chữ ký số
  • Format dữ liệu cần ký khác nhau cho mỗi loại snapshot:
    • Snapshot Transaction: orderId|referenceId|amount|currency|orderCreatedAt|branchId|businessUnitId|status|processedAt|timestamp
      • Lưu ý: Không có paymentTypeskipHolding trong secureHash
    • Snapshot Refund: transactionId|amount|currency|refundReferenceId|refundType|status|processedAt|timestamp
  • Luôn giữ secretKey ở backend, không được expose ra client
  • Kiểm tra kỹ format dữ liệu trước khi ký
  • Lưu ý Amount Hash: amount được lấy phần nguyên (integer part string) để hash.
  • timestamp trong secureHash là giá trị X-Timestamp header (Unix timestamp in seconds), không phải processedAt

Routing qua Mule (Payment Hub)

Quan trọng: Các API snapshot được gọi trực tiếp từ Order Backend của MiniApp tới Payment Hub thông qua MuleSoft, không được gọi trực tiếp tới Payment Hub.

Internal (PnL)

Kết nối Internal dành cho các PnL trong Vingroup.

Base URL trên Mule (endpoint tới Payment Hub):

  • DEV: {MULE_INTERNAL_BASE_URL}/payment-hub/
  • SIT: {MULE_INTERNAL_BASE_URL}/sit/payment-hub/
  • UAT: {MULE_INTERNAL_BASE_URL}/uat/payment-hub/
  • Production: {MULE_INTERNAL_PROD_URL}/payment-hub/

Lưu ý: Với môi trường Production, các bên kết nối sẽ được team Mule cấp key riêng (client_idclient_secret). Với môi trường DEV/SIT/UAT dùng chung key.

External (Đối tác)

Kết nối External dành cho các đối tác bên ngoài Vingroup. Chỉ hỗ trợ 2 môi trường: ProductionUAT.

Base URL trên Mule (endpoint tới Payment Hub):

  • UAT: https://test-api.vingroup.net:7445/payment-hub/
  • Production: https://api-cloud.vingroup.net/payment-hub/

Yêu cầu kết nối External:

  • Tất cả các request từ đối tác external cần cung cấp danh sách IPs để whitelist
  • Phía Mule sẽ cấp client_idclient_secret riêng cho từng đối tác
  • Có whitelist và limit access theo endpoint

Quy tắc chung:

  • Yêu cầu các header cơ bản: X-Payment-API-Key, X-Request-ID, X-Timestamp (hoặc theo từng API doc). Thêm header để pass MuleSoft: client_id, client_secret, v.v. (với snapshot transaction).
  • Các request được forward qua Mule tới Payment Hub — đảm bảo token/client/config phù hợp với Mule khi gọi.

Liên kết liên quan