Blog
vietqrpayment-apiintegrationqr-code

VietQR là gì? Hướng dẫn tích hợp API tạo QR thanh toán từ đầu đến cuối

Tìm hiểu VietQR hoạt động như thế nào, sự khác biệt giữa QR tĩnh và QR động, và hướng dẫn tích hợp API để tạo mã QR thanh toán trong ứng dụng của bạn.

TConnect Team 10 tháng 4, 2026 5 min read

VietQR là gì?

VietQR là tiêu chuẩn mã QR thanh toán ngân hàng tại Việt Nam, được Napas và Ngân hàng Nhà nước Việt Nam ban hành. Một mã QR VietQR chứa đầy đủ thông tin để thực hiện chuyển khoản ngân hàng: số tài khoản, tên ngân hàng, số tiền (tuỳ chọn), nội dung chuyển khoản.

Điểm đặc biệt: VietQR hoạt động cross-bank. Khách hàng dùng app ngân hàng bất kỳ đều quét được — không cần cùng ngân hàng với merchant.

QR tĩnh vs QR động

QR tĩnhQR động
Số tiềnKhông cố định — khách tự nhậpCố định trong QR
Nội dungCố địnhCó thể kèm mã đơn hàng
Dùng khiQuầy thanh toán đơn giản, donateCheckout e-commerce, kiosk
Đối soátKhó tự độngDễ tự động qua order_id

Với hầu hết hệ thống B2B và e-commerce, QR động là lựa chọn đúng — bạn gắn order_id vào QR và nhận IPN callback khi thanh toán thành công.

Kiến trúc tích hợp

[Ứng dụng của bạn]


POST /openapi/v1/qr  ──►  [TConnect API]  ──►  [Ngân hàng / Napas]
      │                                                │
      │◄─── qr_content / image_png_base64 ────────────┘


[Render QR cho khách hàng]

      │ Khách quét & thanh toán

[TConnect IPN Callback] ──► [Backend của bạn] ──► Cập nhật đơn hàng

Bước 1: Lấy service_code

Trước khi tạo QR, gọi API Get Services để lấy service_code phù hợp với ngân hàng bạn dùng.

curl -X GET "https://sme-open-api-sandbox.tconnect.vn/openapi/v1/services?payment_method=qr&limit=10&page=1" \
  -H "Partner-Code: YOUR_PARTNER_CODE" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response trả về danh sách service, ví dụ "code": "bidv-qr". Đây là giá trị bạn sẽ truyền vào header x-service-code.

Bước 2: Tạo Virtual Account

VA (Virtual Account / Tài khoản ảo) là số tài khoản định danh cho merchant. Tạo một lần, dùng mãi.

// Tạo Virtual Account một lần, dùng mãi
payload = {
    bank_code:    "970454",   // BIDV
    account_name: "CONG TY THUONG MAI ABC"
}
encrypt payload then POST to /openapi/v1/va/va-account/create
// Response: { "va_number": "VA100023312", "status": "active" }

Bước 3: Tạo QR cho đơn hàng

// Khởi tạo client và đăng nhập
client = new TConnectClient(base_url, partner_code, aes_key)
client.login(username, password, client_id, client_secret)
 
// Tạo QR cho đơn hàng
qr_response = client.create_qr(
    order_id:     "ORDER_20260510_001",
    va:           "VA100023312",
    bincode:      "970454",
    service_code: "bidv-qr",
    amount:       250000   // 250,000 VND — truyền 0 cho QR tĩnh
)
 
// qr_response.image_png_base64 → dùng trong <img src="data:image/png;base64,...">
// qr_response.qr_content       → dùng render bằng thư viện QR code

Hiển thị trong React

// Component hiển thị ảnh QR từ base64 data
function PaymentQR(qrData):
    render image:
        src = "data:image/png;base64," + qrData.image_png_base64
        alt = "QR thanh toán"
        size = 192 x 192 px

Bước 4: Nhận IPN khi thanh toán thành công

// IPN endpoint: POST /webhook/tconnect/ipn
function ipn_handler(request):
    body = parse_json(request)
    txn  = decrypt_aes(body.data, AES_KEY)
 
    // Idempotency check
    if is_processed(txn.request_id):
        return { status: "ok" }
 
    mark_order_paid(txn.order_id, txn.amount)
    return { status: "ok" }   // Bắt buộc trả 200

Quan trọng: TConnect retry IPN nếu không nhận được HTTP 200. Luôn implement idempotency bằng request_id.

Xử lý edge cases

QR hết hạn: QR VietQR không có TTL cứng, nhưng bạn nên tự set timeout phía backend (ví dụ: 15 phút) và huỷ đơn nếu quá hạn.

Duplicate IPN: Xảy ra khi network retry. Dùng request_id làm unique key để tránh charge 2 lần.

Amount mismatch: Kiểm tra txn["amount"] trong IPN so với expected_amount của đơn hàng trước khi mark paid.

Kết luận

VietQR đơn giản hơn card payment và phổ biến hơn nhiều tại Việt Nam (đặc biệt với SME). Luồng tích hợp:

  1. Login → lấy token
  2. Get Services → lấy service_code
  3. Create VA → lấy va_number
  4. Create QR → hiển thị cho khách
  5. IPN Callback → cập nhật đơn hàng

Toàn bộ luồng có thể implement trong dưới 4 giờ với Sandbox của TConnect.

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

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