API tạo mã QR ngân hàng ACB (VietQR động) theo đơn hàng
Video hướng dẫn
Xem transcript video (9 phần)
QR điền sẵn đúng đơn
Khách gõ sai số tiền hoặc nội dung chuyển khoản thì hệ thống rất khó khớp đơn. Trong video này, mình tạo VietQR động từ API ACB, điền sẵn tài khoản, số tiền và mã đơn, hiển thị QR rồi nhận webhook sau khi khách quét. Bạn cũng sẽ biết cách hủy mã tạo nhầm và xử lý các lỗi trường bắt buộc.
Điều kiện tạo QR
Endpoint tạo là POST /api/v1/acb/qr-payment/generate, cần Bearer và X-Client-Secret. Điều kiện là tài khoản ACB đã nối và đã có tài khoản ảo. Nếu chưa muốn gọi API, dashboard có mục Tạo QR để chọn VA, nhập số tiền rồi tải ảnh. Qua API, response quan trọng nhất là qr_data_url, chuỗi dữ liệu dùng để thư viện của bạn vẽ thành ảnh QR.
Thông tin bên nhận
Nhóm nhận tiền gồm ownerNumber là số tài khoản ACB, ownerType nhận PER cho cá nhân hoặc ORG cho doanh nghiệp. merchantId là mã đơn vị chấp nhận thanh toán và terminalId là mã điểm bán, cả hai do ACB cấp và hiển thị trong mục Tạo QR. beneficiaryName là tên người hoặc đơn vị hưởng hiện trên ứng dụng ngân hàng của khách.
Thông tin đơn hàng
Nhóm đơn hàng gồm orderId, mã duy nhất cho mỗi lần thanh toán; virtualAccountPrefix, đầu số VA dài từ một đến mười ký tự; và amount, số nguyên VND từ không đến một tỷ. Số không cho khách tự nhập tiền. description là nội dung chuyển khoản, còn traceNumber là mã theo dõi riêng để tra soát. Bạn có thể thêm userId, mã ưu đãi và additionalInfo khi cần.
Vẽ QR từ response
Response trả bản ghi QR với id, virtual_account_number, thông tin đơn và qr_data_url. Đây là dữ liệu QR theo chuẩn VietQR EMVCo. Dùng chuỗi qr_data_url với thư viện vẽ QR, chẳng hạn qrcode trong Node, rồi gắn ảnh vào trang thanh toán. Lưu id để hủy khi đơn bị hủy hoặc đổi số tiền. Đừng dùng virtualAccountPrefix thay cho virtual_account_number, vì số đầy đủ do ACB trả về.
Hủy QR tạo nhầm
Nếu QR tạo nhầm và khách chưa trả, gọi DELETE /api/v1/acb/qr-payment/{qr_code_id}/cancellation. Request cần Bearer, X-Client-Secret và body khớp lúc tạo gồm ownerNumber, ownerType, orderId, amount; traceNumber là tùy chọn. Chỉ hủy mã cũ trước khi tạo mã thay thế với cùng đơn. Khi ứng dụng ngân hàng báo QR hết hạn, cũng hủy mã cũ rồi tạo lại.
Khớp đơn sau khi quét
Khi khách quét và chuyển tiền, ACB báo cho MONA Pay rồi webhook mang amount, description, transfer_date, transaction_code, account_number, bank_name và type. Khớp đơn bằng số VA trong account_number hoặc mã đơn nằm trong description. Trước khi đổi trạng thái đã thanh toán, so amount với tổng đơn và chống trùng bằng transaction_code. Giao dịch QR đi qua đúng luồng webhook như tiền vào VA.
Sửa lỗi tạo QR
Nếu tạo QR trả bốn trăm, kiểm tra tài khoản đã đăng ký đúng đầu số VA và hai mã merchantId, terminalId. Bốn trăm hai mươi hai nghĩa là thiếu trường, amount vượt một tỷ hoặc virtualAccountPrefix dài hơn mười ký tự; đọc detail[]. Khách quét được nhưng không có webhook thì VA có thể chưa hoàn tất bước đăng ký thông báo và OTP lần hai. QR hết hạn trên ứng dụng ngân hàng cần được hủy và tạo lại.
Mở docs và tạo thử
Body mẫu, response và code cURL, PHP, Node nằm tại monapay.vn/docs/api/qr-thanh-toan. Bạn đăng ký tại my.monapay.vn, thử tạo một mã QR trong dashboard để kiểm tra đầy đủ thông tin ACB trước khi gọi API thật. Nếu còn lỗi mã đơn, đầu số hoặc dữ liệu QR, gọi tổng đài một chín không không, sáu ba sáu, sáu bốn tám để đội MONA hỗ trợ.
QR thanh toán của MONA Pay là mã VietQR động do ACB tạo: đã điền sẵn số tài khoản (hoặc VA), số tiền và mã đơn, khách mở app ngân hàng bất kỳ quét là chuyển đúng số tiền, đúng nội dung, không gõ tay. Gọi POST /api/v1/acb/qr-payment/generate với orderId, amount (VND, số nguyên, tối đa 1.000.000.000) và đầu số VA, MONA Pay trả về qr_data_url để bạn hiển thị ngay trên trang thanh toán. Khi khách trả xong, ACB báo về và MONA Pay bắn webhook y như tiền vào VA. QR tạo nhầm thì hủy bằng endpoint cancellation trước khi khách quét.
Không muốn gọi API thì dashboard có mục Tạo QR: chọn VA, nhập số tiền, tải ảnh QR về in hoặc gửi khách.
POST /api/v1/acb/qr-payment/generate
Cần Bearer + X-Client-Secret. Điều kiện: tài khoản ACB đã nối và có VA (xem Tài khoản ảo).
| Trường | Kiểu | Bắt buộc | Ghi chú |
|---|---|---|---|
ownerNumber |
string | có | Số tài khoản ACB nhận tiền |
ownerType |
PER / ORG |
có | PER cá nhân, ORG doanh nghiệp |
merchantId |
string | có | Mã merchant do ACB cấp khi mở dịch vụ QR. Giá trị đúng hiển thị ở dashboard mục Tạo QR |
terminalId |
string | có | Mã điểm bán do ACB cấp, cùng chỗ với merchantId |
orderId |
string | có | Mã đơn của bạn, duy nhất cho mỗi lần thanh toán |
virtualAccountPrefix |
string (1-10) | có | Đầu số VA |
beneficiaryName |
string (1-100) | có | Tên người/đơn vị hưởng hiện trên app ngân hàng của khách |
amount |
integer | có | Số tiền VND, 0 đến 1.000.000.000. 0 = khách tự nhập số tiền |
description |
string (≤255) | không | Nội dung chuyển khoản hiện sẵn cho khách |
traceNumber |
string | không | Mã theo dõi riêng của bạn, nên đặt để tra soát |
userId |
string | không | Mã khách trong hệ thống của bạn |
voucherCode, loyaltyCode |
string | không | Mã giảm giá / tích điểm nếu bạn cần lưu kèm |
additionalInfo |
array [{key, value}] |
không | Thông tin phụ dạng khoá-giá trị |
Body mẫu:
Response 200: data là bản ghi QR, quan trọng nhất là qr_data_url và virtual_account_number.
qr_data_url là chuỗi dữ liệu QR chuẩn VietQR (EMVCo). Bạn đưa chuỗi này vào thư viện vẽ QR bất kỳ (ví dụ qrcode của Node, endroid/qr-code của PHP) để ra ảnh. Lưu id để hủy khi cần.
cURL
PHP
Node
DELETE /api/v1/acb/qr-payment/{qr_code_id}/cancellation
Hủy QR đã tạo nhưng khách chưa thanh toán (đơn bị hủy, đổi số tiền). Cần Bearer + X-Client-Secret. Body bắt buộc gửi lại thông tin khớp với lúc tạo:
| Trường | Kiểu | Bắt buộc |
|---|---|---|
ownerNumber |
string | có |
ownerType |
PER / ORG |
có |
orderId |
string | có |
amount |
integer | có |
traceNumber |
string | không |
Response: {"success": true, "message": "Success", "data": null}.
Khách quét xong thì sao
ACB ghi nhận tiền vào, báo cho MONA Pay, MONA Pay bắn webhook tới URL bạn cấu hình với payload y như giao dịch VA:
Khớp đơn bằng account_number (số VA gắn với QR) hoặc description chứa orderId. Nhớ so amount với số tiền đơn trước khi đổi trạng thái đã thanh toán.
Lỗi thường gặp
| Tình huống | Nguyên nhân | Cách xử lý |
|---|---|---|
| 400 khi tạo | Tài khoản chưa đăng ký VA với đầu số này, hoặc merchantId/terminalId sai |
Kiểm tra ở dashboard mục Tạo QR, tạo thử 1 mã trên web trước |
| 422 | Thiếu trường bắt buộc, amount vượt 1.000.000.000, virtualAccountPrefix dài quá 10 ký tự |
Sửa theo detail[] |
| Khách quét được nhưng không thấy webhook | VA chưa đăng ký nhận thông báo (bước 3, 4 khi tạo VA) | Xem Tài khoản ảo |
| QR hết hạn trên app ngân hàng | Mỗi QR động có thời hạn theo quy định ACB | Tạo QR mới với cùng orderId sau khi hủy mã cũ |