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

Tích hợp thanh toán

Yêu cầu thông tin tích hợp thanh toán

Quy trình onboard Mini App

Khi Mini App onboard, hệ thống sẽ tạo:

  • Merchant: Đại diện cho Mini App
  • Terminal: Đại diện cho điểm thanh toán (tương ứng với một tài khoản nhận tiền tại Cổng thanh toán). Tùy theo business của Merchant, một Merchant có thể cấu hình nhiều Terminal (nhiều tài khoản nhận tiền khác nhau). Payment Hub sẽ cấp paymentApiKey tương ứng cho từng Terminal. Các team PnL / Product cần quản lý mapping giữa Terminal và paymentApiKey để đảm bảo gửi đúng paymentApiKey cho mỗi request.
  • Cấu hình phương thức thanh toán theo cổng: Merchant có thể enable nhiều phương thức thanh toán tương ứng với các Cổng thanh toán khác nhau. Sau khi Merchant hoàn tất ký kết hợp đồng với từng Cổng thanh toán, thông tin cấu hình/enable phương thức sẽ được khai báo trên Payment Hub để các phương thức đủ điều kiện có thể hiển thị và sử dụng trong luồng thanh toán.

Payment Service sẽ generate và cấp credentials cho MiniApp/Order Backend để kết nối:

  • paymentApiKey: Xác định terminal, được quản lý theo terminal với các thuộc tính:

    • status: Trạng thái của key
    • expiredTime: Thời gian hết hạn
    • Audit info: Thông tin người tạo/cập nhật, thời gian cập nhật
    • Được gửi tới Payment Hub qua header trong mỗi request để Payment Service xác định merchant/terminal
    • Lưu ý: paymentApiKey được cấp cho từng Terminal (tài khoản nhận tiền). Các backend cần giữ mapping Terminal ↔ paymentApiKey và luôn sử dụng paymentApiKey tương ứng với Terminal mà đơn hàng thuộc về.
  • Header X-MiniApp-Id: Khi Order Backend gọi các API Payment Hub (init payment, payment methods, cancel, refund, v.v.) có thể gửi header X-MiniApp-Id với giá trị miniAppId (MiniApp ID trong SuperApp) để Payment Service xác định ngữ cảnh MiniApp. Hiện tại optional (khuyến nghị gửi khi tích hợp mới).

  • secretKey: Được cung cấp cho Order Backend để:

    • Tạo secureHash với các request init/cancel/refund payment
    • Validate tính toàn vẹn của request theo thuật toán HMAC-SHA-256

Mini App/Order Backend cần lưu trữ credentials này để authenticate với Payment Service trong mỗi request.

Để tích hợp thanh toán, bạn cần liên hệ team PTNT hoặc submit qua form để nhận được credentials. Sau khi được duyệt, bạn có thể cấu hình thanh toán trực tiếp trên DevCenter, xem hướng dẫn tại đây.

Luồng enable phương thức thanh toán với Merchant/PnL

Để các phương thức thanh toán có thể hiển thị và sử dụng trong thực tế, Merchant/PnL cần hoàn tất quy trình ký kết với cổng thanh toán và khai báo cấu hình trên Payment Hub theo các bước dưới đây:

  1. Ký kết với cổng thanh toán (đối tác thanh toán)

    • PnL/Merchant làm việc với từng cổng thanh toán để ký hợp đồng và kích hoạt kết nối.
    • Sau khi hoàn tất, cổng thanh toán cung cấp bộ thông tin kỹ thuật phục vụ tích hợp.
  2. Nhận thông tin kết nối từ cổng thanh toán

    • Các thông tin thường bao gồm: merchant account, terminal account, MID/TID, API credential, cấu hình 2D/3D (nếu có), hạn mức hoặc điều kiện áp dụng.
    • PnL/Merchant cần kiểm tra chính xác theo từng môi trường (UAT/Production) trước khi khai báo.
  3. Khai báo cấu hình trên Payment Hub

    • PnL/Merchant gửi bộ thông tin kết nối cho team Payment/PTNT để cấu hình provider và enable phương thức thanh toán.
    • Cấu hình được khai báo theo Merchant/Terminal; một Merchant có thể có nhiều Terminal tương ứng nhiều tài khoản nhận tiền.
    • Hệ thống sẽ map phương thức thanh toán với đúng paymentApiKey của từng Terminal.
  4. Verify sau khi enable

    • Backend gọi API Lấy danh sách phương thức thanh toán (Backend) với X-Payment-API-Key tương ứng để kiểm tra phương thức đã được enable đúng chưa.
    • Chỉ các phương thức đủ điều kiện theo terminal + amount + currency mới được trả về.
  5. Checklist trước go-live

    • Xác nhận key kết nối qua Mule (client_id, client_secret) và whitelist IP (nếu áp dụng).
    • Xác nhận webhook/IPN hoạt động ổn định.
    • Test đầy đủ các kịch bản chính: thanh toán thành công, thất bại, timeout, cancel/refund, và fallback 2D/3D (nếu có cấu hình).
Chú ý bảo mật

Payment API Key:

  • paymentApiKey tương ứng với terminal/điểm thanh toán được khai báo trên hệ thống Payment
  • Được gửi qua header X-Payment-API-Key trong mỗi request
  • Backend của MiniApp cần đảm bảo mapping Terminal ↔ paymentApiKey và gửi paymentApiKey tương ứng với Terminal của đơn hàng
  • KHÔNG BAO GIỜ expose ở frontend/client

Secret Key:

  • secretKey được dùng để sinh secureHash cho việc verify tính toàn vẹn của request
  • KHÔNG BAO GIỜ gửi secretKey qua network
  • CHỈ sử dụng ở backend để tạo chữ ký, không được lưu hoặc gửi đi đâu khác

Lưu ý quan trọng:

  • KHÔNG lưu secretKey ở frontend, mobile app, hoặc bất kỳ nơi nào client có thể truy cập
  • Luôn store các keys này ở environment variables hoặc secret management system

Ngoài ra bạn cần cung cấp cho team PTNT:

  • Đăng ký webhook của mình với hệ thống MuleSoft.
  • Thông tin webhook để nhận thông báo trạng thái thanh toán.

Cấu hình Simulator

Để cấu hình cho simulator kết nối được payment server thì cần thiết lập cấu hình theo hướng dẫn trong phần CLI Environment để đảm bảo simulator có thể giao tiếp với payment server một cách chính xác.

Luồng thanh toán MiniApp

Lưu ý: để có thông tin định danh của V-App cho việc thực hiện tạo đơn hàng trên hệ thống bạn cũng như map user id giữa hệ thống của bạn và V-App thì bạn cần thực hiện các bước đăng nhập với V-App thông qua

Luồng thanh toán trong V-App được thực hiện thông qua sự phối hợp giữa MiniApp (frontend) và MiniApp Backend (backend). MiniApp chịu trách nhiệm tương tác với người dùng và gọi các API của V-MiniApp Framework, trong khi MiniApp Backend xử lý logic nghiệp vụ và quản lý trạng thái đơn hàng.

Chi tiết luồng xử lý

1. Khởi tạo thanh toán (MiniApp)

  • Bước 2: MiniApp gọi showPaymentMethod() để hiển thị màn hình chọn phương thức thanh toán
  • Bước 4: MiniApp hiển thị danh sách các phương thức thanh toán có sẵn
  • Bước 5: Người dùng chọn phương thức thanh toán mong muốn
  • Bước 7: MiniApp nhận callback thành công từ showPaymentMethod()

2. Tạo đơn hàng (MiniApp ↔ MiniApp Backend)

  • Bước 8: MiniApp gửi request "create order" đến MiniApp Backend với thông tin đơn hàng
  • Bước 9: MiniApp Backend xử lý và tạo đơn hàng trong hệ thống
  • Bước 10: MiniApp Backend trả về thông tin đơn hàng (orderId, referenceId, secureHash, v.v.) cho MiniApp

3. Khởi tạo thanh toán (MiniApp)


import apis from '@v-miniapp/apis'

apis.showPaymentMethod({
success: (paymentMethod) => {
// tạo đơn hàng, gọi initPayment để thực hiện thanh toán
apis.initPayment({
paymentApiKey: "xxx",
miniAppId: "vinfast_sales", // MiniApp ID trong SuperApp (optional)
orderInfo: {
paymentMethodCode: paymentMethod.code,
providerId: paymentMethod.providerId,
userPaymentMethodId: paymentMethod.userProviderId || "",
paymentType: "3D", // "2D" hoặc "3D", mặc định "3D". Với "2D", user không cần verify token/OTP, hệ thống tự động trừ tiền. Xem lưu ý chi tiết bên dưới.
businessUnitId: "BU_VINFAST_001", // Payment Hub/COV dùng để xác định đơn hàng thuộc cơ sở kinh doanh nào. Trên production cần truyền giá trị này.
branchId: "BR_HN_001", // Payment Hub/COV dùng để xác định đơn hàng thuộc chi nhánh nào. Trên production cần truyền giá trị này.
amount: 100000,
currency: "VND",
description: "Payment for order #123456",
orderId: "Order Id 001",
referenceId: "Reference_123456",
orderInfo: {
customerName: "Nguyen Van A",
customerEmail: "[email protected]",
customerPhone: "+84901234567",
orderCreatedAt: 1640995200000,
items: [
{
name: "Product A",
sku: "Sku 001",
quantity: 2,
unitPrice: 50000,
description: "High quality product",
},
],
notes:"Bill: 001",
},
secureHash: "string",
},
success: (res) => {
apis.alert({ title: "payment", content: res });
},
fail: (err) => {
console.log("errr", err);
},
});
},
});

Lưu ý về paymentType:

  • Phạm vi áp dụng: Chỉ áp dụng với thanh toán thẻ Visa, không áp dụng với ATM.
  • Điều kiện hoạt động: Field này chỉ có tác dụng khi PnL cấu hình riêng MID 2D, 3D (mặc định là 3D). Nếu không cấu hình riêng thì giá trị paymentType truyền vào sẽ không có tác dụng.
  • Fallback behavior: Trong trường hợp không cấu hình MID 2D trên hệ thống nhưng truyền paymentType = "2D" trong giao dịch, hệ thống sẽ tự động fallback về dùng cấu hình MID 3D.

4. Xử lý thanh toán (V-App ↔ User)

  • Bước 13: V-App hiển thị màn hình thanh toán cho người dùng
  • Bước 14: Người dùng thực hiện thanh toán trên V-App
  • Bước 16: MiniApp nhận callback thành công từ initPayment()
  • Bước 17: MiniApp bắt đầu long polling để kiểm tra trạng thái đơn hàng từ MiniApp Backend
  • Bước 18: MiniApp hiển thị trang "thank you" cho người dùng

5. Xử lý thông báo IPN (MiniApp Backend)

  • Bước 19: Payment Service gửi IPN (Instant Payment Notification) đến MiniApp Backend qua webhook POST /api/v1/payment-webhook
  • Bước 20: MiniApp Backend nhận IPN và cập nhật trạng thái đơn hàng trong database

6. Hoàn tất luồng (MiniApp ↔ MiniApp Backend)

  • Bước 21: MiniApp Backend trả về trạng thái đơn hàng cuối cùng cho MiniApp (qua long polling)
  • Bước 22: MiniApp hiển thị trạng thái thành công của đơn hàng cho người dùng

Trách nhiệm của từng thành phần

MiniApp (Frontend)

  • Tương tác với người dùng (hiển thị UI, nhận input)
  • Gọi các API của V-App Framework (showPaymentMethod, initPayment)
  • Xử lý callback và cập nhật UI tương ứng
  • Thực hiện long polling để theo dõi trạng thái đơn hàng
  • Hiển thị kết quả cuối cùng cho người dùng

MiniApp Backend

  • Tạo và quản lý đơn hàng trong hệ thống
  • Sinh mã secureHash cho đơn hàng trước khi trả về cho MiniApp
  • Xử lý webhook IPN từ Payment Service
  • Cập nhật trạng thái đơn hàng trong database
  • Trả về thông tin đơn hàng và trạng thái cho MiniApp
  • Đảm bảo tính nhất quán dữ liệu và xử lý các trường hợp lỗi

API Init Payment từ Backend (qua Mule)

Ngoài luồng thanh toán từ V-App qua Payment SDK (đã mô tả ở trên), Payment Hub cũng hỗ trợ API initPayment được gọi trực tiếp từ Order Backend của các PnL đi qua MuleSoft rồi đẩy tới Payment Core (tương tự như các API cancel/refund/confirm trong Quản lý giao dịch thanh toán).

Xem chi tiết API và hướng dẫn sử dụng tại: Khởi tạo thanh toán từ Backend

Các bước tiếp theo