Blog
virtual-accountva-billinghoc-phivien-phiretailpayment-api

Tài khoản ảo (Virtual Account) là gì? Ứng dụng trong VA Billing, học phí, viện phí và retail

Tài khoản ảo (VA) không chỉ là một số tài khoản. Tìm hiểu cách VA billing hoạt động trong thanh toán 1 lần, đặt cọc nhiều lần, thu học phí tự động, thanh toán viện phí và giao dịch bán lẻ.

TConnect Team 5 tháng 2, 2026 9 min read

Tài khoản ảo (Virtual Account) là gì?

Virtual Account (VA) — hay còn gọi là tài khoản ảo, tài khoản định danh — là một số tài khoản ngân hàng được tạo ra và gắn với một merchant cụ thể. Về mặt kỹ thuật, VA không phải tài khoản thật theo nghĩa truyền thống: không có số dư riêng, không mở được bằng CMND. Thay vào đó, VA là một alias (bí danh) được ngân hàng nhận diện và định tuyến vào tài khoản master của merchant.

Khi khách hàng chuyển khoản vào số VA, ngân hàng nhận diện giao dịch, gắn metadata (số VA, số tiền, nội dung) và thông báo về hệ thống của merchant qua IPN callback.

VA khác tài khoản thông thường như thế nào?

Tài khoản ngân hàng thườngVirtual Account
Cách tạoMở tại chi nhánh, cần giấy tờTạo qua API trong vài giây
Số lượngGiới hạnTạo được hàng nghìn VA/ngày
Số dưCó số dư riêngKhông có số dư — tiền vào master account
Nhận diện giao dịchDựa vào nội dung chuyển khoảnDựa vào chính số VA → chính xác 100%
AutomationKhó đối soát tự độngĐối soát tự động qua va_number

Hai mô hình VA Billing chính

Mô hình 1: VA 1 lần (One-time VA)

Tạo một VA mới cho mỗi giao dịch / đơn hàng. Sau khi thanh toán xong, VA hết hiệu lực.

[Đơn hàng #1001] → [VA: VA100001] → [Khách chuyển 500,000đ] → [IPN: PAID ✓]
[Đơn hàng #1002] → [VA: VA100002] → [Khách chuyển 320,000đ] → [IPN: PAID ✓]

Ưu điểm: Mỗi giao dịch được định danh tuyệt đối, không nhầm lẫn.

Phù hợp với: E-commerce checkout, đặt cọc dịch vụ, thanh toán hóa đơn một lần.

Mô hình 2: VA nhiều lần (Persistent VA)

Một VA được gán cố định cho một khách hàng / hợp đồng. Khách hàng chuyển khoản vào VA đó mỗi kỳ.

Học sinh Nguyễn Văn A
  └─ VA: VA200050 (cố định cả năm học)
       ├─ Tháng 9:   chuyển 2,500,000đ  →  IPN: Sep fee PAID ✓
       └─ Tháng 10:  chuyển 2,500,000đ  →  IPN: Oct fee PAID ✓

Ưu điểm: Khách hàng nhớ một số tài khoản duy nhất, không cần thao tác thêm mỗi kỳ.

Phù hợp với: Học phí định kỳ, viện phí theo đợt điều trị, thuê mặt bằng, subscription.


Ứng dụng thực tế

1. Thanh toán học phí (Giáo dục)

Đây là use case phù hợp nhất với mô hình Persistent VA.

Luồng hiện tại (thủ công):

  • Phụ huynh chuyển khoản vào tài khoản chung của trường
  • Kế toán đối chiếu nội dung chuyển khoản thủ công để xác định học sinh
  • Sai nội dung → nhầm học sinh → mất nhiều ngày đối soát

Luồng với VA:

1. Nhập học
   └─ POST /openapi/v1/va/va-account/create
        { bank_code: "970403", account_name: "NGUYEN VAN A - LOP 10A1" }
        → VA mới: VA300125
 
2. Gửi VA cho phụ huynh
   └─ In trên phiếu thu, gửi qua app/email
 
3. Phụ huynh chuyển khoản vào VA300125 (hàng tháng)
   └─ Hệ thống tự nhận diện: học sinh A, 2,500,000đ
 
4. IPN Callback tự động
   └─ { order_id: "SCHOOL-A-SEP2026", amount: 2500000 }
      → Cập nhật trạng thái học phí trong phần mềm quản lý

Kết quả: Xoá bỏ hoàn toàn bước đối soát thủ công. Kế toán chỉ cần xem báo cáo.

2. Thanh toán viện phí (Y tế)

Y tế có thêm yêu cầu phức tạp hơn giáo dục: cùng một bệnh nhân có thể có nhiều đợt điều trị, mỗi đợt nhiều lần thanh toán (thuốc, thủ thuật, giường bệnh...).

Mô hình đề xuất:

Bệnh nhân vào viện → Tạo VA cho đợt điều trị
  └─ VA: VA400200  "NGUYEN THI B - DOT DIEU TRI 15052026"

       ├─ Lần 1: Viện phí khám ban đầu        500,000đ
       ├─ Lần 2: Tiền thuốc ngày 1          1,200,000đ
       ├─ Lần 3: Phí phẫu thuật            15,000,000đ
       └─ Lần 4: Tiền phòng 3 ngày          1,500,000đ

            └─ Mỗi IPN: loại viện phí + mã đợt điều trị
               → HIS tự cập nhật từng khoản phí

Tích hợp với hệ thống HIS (Hospital Information System):

# Tiếp nhận bệnh nhân
POST /openapi/v1/va/va-account/create
  bank_code: "970415"  (Vietinbank)
  account_name: "{patient.name} - {admission.code}"
→ Lưu va_number vào bản ghi đợt điều trị
 
# IPN Handler
function handleIPN(encryptedData):
    txn = AES_decrypt(encryptedData)
    admission = db.find(txn.order_id)
    admission.addPayment(amount=txn.amount, ref=txn.retrieval_ref_no)
    return 200 OK

3. Bán lẻ (Retail)

Retail có đặc thù: hàng nghìn giao dịch/ngày với nhiều quầy, nhiều nhân viên thu ngân.

Mô hình QR + VA:

Quầy thu ngân #1  →  VA cố định #1  →  QR động theo order_id
Quầy thu ngân #2  →  VA cố định #2  →  QR động theo order_id

Mỗi QR được tạo với order_id chứa mã quầy + mã đơn, giúp đối soát chi tiết đến từng giao dịch.

# POS tạo QR khi khách checkout
POST /openapi/v1/qr/create
  order_id: "STORE01-CASH01-{invoice.id}"
  va: store.va_number
  bincode: "970454"
  service_code: "bidv-qr"
  amount: invoice.total
→ Hiển thị QR trên màn hình khách
 
# Sau khi nhận IPN → POS tự đóng đơn

Đối soát cuối ca: Báo cáo tổng hợp theo order_id prefix, tự động khớp với POS system.

4. Subscription và dịch vụ định kỳ (SaaS)

Với SaaS B2B, mỗi khách hàng doanh nghiệp có VA riêng. Hệ thống gửi thông báo trước kỳ gia hạn, khách chuyển khoản vào VA → hệ thống tự kích hoạt tiếp.

Doanh nghiệp ABC
  └─ VA: VA500010 (hợp đồng năm 2026)
       ├─ Tháng 5/2026:  1,200,000đ → Gia hạn tháng 6 ✓
       ├─ Tháng 6/2026:  1,200,000đ → Gia hạn tháng 7 ✓
       └─ ...

Mô hình này đặc biệt phù hợp với doanh nghiệp Việt Nam vì phần lớn kế toán doanh nghiệp ưa chuyển khoản ngân hàng hơn thẻ khi thanh toán B2B.


Tạo VA qua TConnect API

# 1. Login
POST /openapi/v1/auth/login
  { partner_code: "YOUR_PARTNER_CODE", ... }
→ access_token
 
# 2. Tạo VA
POST /openapi/v1/va/va-account/create
  { bank_code: "970454", account_name: "NGUYEN VAN A LOP 10A1" }
// Response
{ "va_number": "VA100023312", "bank_code": "970454",
  "account_name": "NGUYEN VAN A LOP 10A1", "status": "active" }

Sau đó dùng va_number này khi tạo QR:

POST /openapi/v1/qr/create
  { order_id: "SCHOOL-NGUYENVANA-SEP2026", va: "VA100023312",
    bincode: "970454", service_code: "bidv-qr", amount: 2500000 }

Lưu ý kỹ thuật quan trọng

Đặt tên account_name chuẩn

account_name hiển thị trên màn hình ứng dụng ngân hàng của người chuyển tiền. Đặt rõ ràng giúp khách hàng xác nhận đúng trước khi chuyển. Ví dụ:

  • "TRUONG THPT XYZ - NGUYEN VAN A 10A1"
  • "student_12345" (khách không nhận ra)

Idempotency trong IPN

function handleIPN(encryptedData):
    txn = AES_decrypt(encryptedData)
 
    # Kiểm tra đã xử lý chưa (idempotency)
    if cache.exists("ipn:" + txn.request_id):
        return 200 OK  # Trả 200 để TConnect không retry
 
    cache.set("ipn:" + txn.request_id, ttl=24h)
    processPayment(txn)
    return 200 OK

Xử lý chuyển thiếu / thừa tiền

Với học phí / viện phí, khách đôi khi chuyển sai số tiền:

if txn.amount < expected_amount:
    admission.addPartialPayment(txn.amount)
    # Gửi thông báo yêu cầu nộp bổ sung
elif txn.amount > expected_amount:
    admission.addOverpayment(txn.amount - expected_amount)
    # Cờ để xử lý hoàn tiền thừa
else:
    admission.markFullyPaid()

Kết luận

VA không chỉ là "một số tài khoản ngân hàng khác." Đây là công cụ automation mạnh nhất trong hệ sinh thái thanh toán Việt Nam cho các tổ chức xử lý nhiều giao dịch có tính chất định kỳ hoặc cần đối soát tự động.

Use caseMô hình VALợi ích chính
E-commerceOne-time VA mỗi đơnĐối soát tự động 100%
Học phíPersistent VA mỗi học sinhXoá đối soát thủ công
Viện phíPersistent VA mỗi đợt điều trịTích hợp trực tiếp HIS
Retail POSPersistent VA mỗi quầy + QR độngTốc độ + đối soát ca
SaaS B2BPersistent VA mỗi khách hàngPhù hợp hành vi kế toán VN

Bắt đầu với Sandbox TConnect để test toàn bộ luồng VA + QR + IPN trong môi trường an toàn, không cần KYB.

Bắt đầu tích hợp ngay

Sandbox miễn phí · Tài liệu API đầy đủ · Hỗ trợ kỹ thuật