Hướng dẫn các bước test kết nối API VietQR Banknet - Hub
1.1. Tài liệu này dùng để làm gì
Đây là hướng dẫn thực hành, mô tả trình tự các bước cần làm để đưa dịch vụ thanh toán VietQR vào hệ thống của Đối tác.
Tài liệu này không thay thế bản đặc tả kỹ thuật. Đặc tả mô tả từng API có những trường nào; hướng dẫn này mô tả thứ tự làm, cách làm, và những chỗ dễ sai.
Khi cần tra cứu chi tiết trường dữ liệu, giới hạn độ dài hay mẫu phản hồi đầy đủ, hãy dùng tài liệu BLC-API-SPEC-PROD-VIETQR v1.0.
1.2. Những gì cần nhận trước khi bắt đầu
Hạng mục | Mô tả | Nguồn cấp |
|---|---|---|
username / password | Thông tin xác thực tài khoản API. Có hai bộ riêng biệt cho Sandbox và Production. | VietQR |
merchantName | Tên thương nhân trên hệ thống VietQR. Đối tác không được tự đặt giá trị này. | VietQR |
secretKey | Khóa bí mật riêng cho tính năng hoàn tiền. Khác với password tài khoản API. | VietQR — kênh an toàn riêng |
bankAccount / bankCode | Tài khoản thụ hưởng đã đăng ký. Mã ngân hàng hiện áp dụng: MB. | VietQR |
Endpoint callback | Hai endpoint do Đối tác xây dựng, phải đăng ký với VietQR trước khi kiểm thử. | Đối tác cung cấp |
Để cấu hình kết nối API với VietQR, đối tác vui lòng cung cấp và đối chiếu các thông tin dưới đây trước khi bắt đầu.
Thông tin đối tác cần cung cấp | Thông tin VietQR cung cấp |
|---|---|
Tên merchant (tên cửa hàng/doanh nghiệp muốn hiển thị) | Username: VietQR cấp username cho đối tác |
URL kết nối (địa chỉ API để kết nối) | Password: VietQR cấp mật khẩu cho đối tác |
URL Path / Suffix (đường dẫn mở rộng nếu có) | Hoặc: mở tài khoản VietQR, ký tài khoản và tự khai báo trong link liên kết |
Khóa Key kết nối truyền dữ liệu — Username: tự đặt theo nhu cầu của khách hàng | |
Khóa Key kết nối truyền dữ liệu — Password: tự đặt theo nhu cầu của khách hàng |
Quy tắc bảo mật quan trọng nhất
Mật khẩu của VietQR được sinh ra từ chính tên đăng nhập theo quy tắc base64. Vì vậy, lộ username đồng nghĩa với lộ password.
Phải đối xử với cặp username và password như một bí mật duy nhất: không đưa vào mã nguồn, không lưu trong kho mã, không ghi vào nhật ký, không đưa vào tài liệu hay thư điện tử.
Liên kết tham khảo
Nhóm Zalo hỗ trợ test: https://zalo.me/g/wbclso803
Biểu mẫu thông tin ký hợp đồng
1.3. Ba điều cần biết trước khi thiết kế
1. Callback không phải kênh duy nhất. Có tình huống ngân hàng không báo giao dịch sang VietQR; khi đó VietQR không có gì để gửi cho Đối tác. Hệ thống bắt buộc phải có tác vụ đối soát chủ động, xem Bước 4.
2. Callback sẽ đến trùng. VietQR thử lại 10 lần trong 5 phút khi gặp lỗi. Cơ chế chống trùng ở tầng cơ sở dữ liệu là bắt buộc, không phải tùy chọn.
3. Sandbox và Production không giống nhau. Hai môi trường dùng mô hình đối soát khác nhau, và một số API chỉ tồn tại ở một môi trường. Xem Mục 9.
2. Lộ trình tích hợp
Trình tự dưới đây được thiết kế để mỗi giai đoạn đều có kết quả kiểm chứng được trước khi sang giai đoạn kế tiếp. Không nên làm song song các giai đoạn 1 đến 3.
GĐ | Nội dung | Môi trường | Tiêu chí hoàn thành |
|---|---|---|---|
1 | Xác thực, lấy access\_token | Sandbox | Nhận được token; cơ chế cache và tự làm mới hoạt động đúng |
2 | Sinh mã QR và hiển thị | Sandbox | Ứng dụng ngân hàng quét được mã, hiển thị đúng số tiền và tài khoản thụ hưởng |
3 | Tiếp nhận callback | Sandbox | Nhận được dữ liệu giao dịch; gọi trùng hai lần chỉ trả dịch vụ một lần |
4 | Đối soát chủ động | Production | Tác vụ nền phát hiện được giao dịch đã thanh toán mà chưa nhận callback |
5 | Hoàn tiền | Production | Hoàn toàn phần và hoàn từng phần đều thành công, đối soát khớp |
Vì sao giai đoạn 4 và 5 phải làm trên Production
API Check Transaction và API Refund không tồn tại trên Sandbox. Đây là hạn chế của dịch vụ, không phải lựa chọn thiết kế của Đối tác.
Khuyến nghị dự trù một khoản ngân sách nhỏ để chạy kiểm thử bằng giao dịch tiền thật giá trị thấp trong giai đoạn nghiệm thu, trước khi mở dịch vụ cho người dùng cuối.
2.1. Ghi chú về khối lượng công việc
Bảng dưới là nhận định của Bluecom dựa trên kinh nghiệm tích hợp cổng thanh toán nói chung, dùng để tham khảo khi lập kế hoạch. Đây không phải cam kết tiến độ.
Giai đoạn | Ghi chú |
|---|---|
Giai đoạn 1 và 2 | Khối lượng nhỏ. Chủ yếu là gọi API và dựng ảnh QR từ chuỗi qrCode. |
Giai đoạn 3 | Khối lượng trung bình. Phần khó nằm ở cơ chế chống trùng và xử lý bất đồng bộ, không nằm ở việc nhận request. |
Giai đoạn 4 | Khối lượng trung bình. Cần dùng chung luồng xử lý với callback, không viết nhánh riêng. |
Giai đoạn 5 | Phụ thuộc vào quy trình nghiệp vụ hoàn tiền phía Đối tác nhiều hơn là vào bản thân API. |
3. Bước 1 — Xác thực
3.1. Quy tắc sinh chuỗi Basic Auth
Đây là điểm sai nhiều nhất khi bắt đầu. Mật khẩu không phải một chuỗi ngẫu nhiên do VietQR cấp phát riêng, mà chính là tên đăng nhập được mã hóa base64.
password = base64(username)
Authorization = "Basic " + base64(username + ":" + password)
Quy tắc đã được Bluecom kiểm chứng bằng cách giải mã đối chiếu với payload của token trả về.* |
Ví dụ mã nguồn
// Java
String password = Base64.getEncoder()
.encodeToString(username.getBytes(StandardCharsets.UTF\_8));
String basic = Base64.getEncoder()
.encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF\_8));
headers.set("Authorization", "Basic " + basic);
# Python
password = base64.b64encode(username.encode()).decode()
basic = base64.b64encode(f"{username}:{password}".encode()).decode()
headers = {"Authorization": f"Basic {basic}"}
3.2. Quản lý vòng đời token
Token có hiệu lực 300 giây. Không gọi Get Token trước mỗi request nghiệp vụ, vì cách làm đó nhân đôi số lượng request và làm tăng độ trễ không cần thiết.
Yêu cầu triển khai
· Cache token trong bộ nhớ tiến trình và tái sử dụng.
· Chủ động làm mới khi token còn 30 đến 60 giây hiệu lực, thay vì đợi đến khi nhận lỗi.
· Dùng khóa đồng bộ quanh thao tác làm mới, tránh nhiều luồng cùng gọi Get Token.
· Khi gặp lỗi xác thực, làm mới token và thử lại đúng một lần. Thất bại tiếp thì ghi nhật ký và cảnh báo, không thử lại vô hạn.
· Không ghi token vào nhật ký ở bất kỳ mức nào.
Lưu ý về mã lỗi
VietQR chưa cung cấp bảng mã lỗi. Trong giai đoạn kiểm thử Sandbox, hãy ghi lại nguyên văn mọi phản hồi khác HTTP 200 kèm phần thân phản hồi.
Tập hợp các bản ghi này chính là bảng mã lỗi thực nghiệm, hiện là nguồn thông tin đáng tin cậy nhất mà Đối tác có.
4. Bước 2 — Sinh mã QR
4.1. Chọn đúng loại mã QR
Quyết định này ảnh hưởng trực tiếp đến khả năng đối soát tự động và phải được chốt trước khi viết mã.
Tiêu chí | QR động (0) | QR tĩnh (1) | QR bán động (3) |
|---|---|---|---|
Số tiền | Gắn sẵn | Người trả tự nhập | Gắn sẵn |
Gắn orderId | Có, bắt buộc | Không | Không |
Vòng đời | 15 phút, một lần | Dài hạn, nhiều lần | Dài hạn, nhiều lần |
Đối soát tự động theo đơn hàng | Có | Không | Không |
VietQR chống thanh toán lặp | Có | Không | Không |
Phù hợp với | Thương mại điện tử, đơn hàng có giá trị xác định | Quầy thu ngân, cửa hàng nhỏ | Trạm sạc, máy bán hàng tự động |
Khuyến nghị của Bluecom
Nếu nghiệp vụ cần đối soát chính xác đến từng đơn hàng, QR động là lựa chọn duy nhất phù hợp.
Với QR tĩnh và QR bán động, dữ liệu callback không mang orderId. Hệ thống sẽ phải suy luận đơn hàng từ tổ hợp số tiền, thời điểm và điểm bán. Cơ chế này không đảm bảo chính xác khi có hai giao dịch cùng số tiền phát sinh gần nhau.
4.2. Bốn ràng buộc dễ vi phạm nhất
Trường | Ràng buộc | Ví dụ |
|---|---|---|
amount | Số nguyên dương, đơn vị VND. Không dấu phân cách hàng nghìn, không dấu thập phân, không ký hiệu tiền tệ. | Đúng: 10000, 250000 Sai: 10.000 · 10,000 · 10000.00 |
content | Tối đa 23 ký tự, áp dụng cho cả ba loại QR. | Cắt chuỗi ở phía Đối tác trước khi gửi |
orderId | Tối đa 13 ký tự. Phải duy nhất toàn cục trong hệ thống Đối tác. | Đây là khóa đối soát tự động quan trọng nhất |
4.3. Dựng ảnh QR từ chuỗi qrCode
Trường qrCode trong phản hồi là một chuỗi dữ liệu theo chuẩn EMVCo. Đối tác tự dựng ảnh QR từ chuỗi này bằng thư viện mã QR bất kỳ.
Lưu ý khi dựng ảnh
· Mã hóa chuỗi ở chế độ văn bản, không thêm khoảng trắng hay ký tự xuống dòng.
· Mức sửa lỗi khuyến nghị là M hoặc Q. Mức H làm mã dày hơn, khó quét trên màn hình nhỏ.
· Chừa vùng trắng viền quanh mã. Thiếu vùng trắng là nguyên nhân phổ biến khiến ứng dụng ngân hàng không quét được.
· Kích thước hiển thị tối thiểu khuyến nghị là 200 x 200 điểm ảnh.
Kiểm chứng nhanh trước khi viết tiếp
Dựng ảnh QR, mở ứng dụng ngân hàng bất kỳ và quét thử. Nếu ứng dụng hiển thị đúng tài khoản thụ hưởng và đúng số tiền, bước 2 đã hoàn thành.
Không xác nhận thanh toán ở bước kiểm chứng này.
5. Bước 3 — Tiếp nhận callback
5.1. Đảo chiều vai trò
Ở các bước trước, hệ thống Đối tác là bên gọi. Trong luồng callback, VietQR là bên gọi và Đối tác là bên cung cấp dịch vụ.
Đối tác phải tự xây dựng và công bố hai endpoint: một endpoint để VietQR lấy token truy cập hệ thống Đối tác, và một endpoint để VietQR đẩy dữ liệu giao dịch.
Hạng mục cần VietQR cung cấp trước khi bắt đầu bước này
VietQR hiện chỉ cung cấp đường dẫn tham chiếu tới đặc tả của hai endpoint này, chưa cung cấp nội dung đặc tả bằng văn bản.
Bluecom không dựng payload mẫu giả định, vì một cấu trúc callback tự chế sẽ dẫn đến việc xây dựng sai endpoint và chỉ phát hiện ra khi đã tích hợp xong.
Khuyến nghị coi việc nhận được đặc tả này là điều kiện tiên quyết trước khi cam kết tiến độ. Xem Phụ lục B, mục A-01.
5.2. Sáu yêu cầu bắt buộc
Các yêu cầu dưới đây được đưa vào vì cơ chế thử lại 10 lần khiến việc bỏ qua chúng gần như chắc chắn gây sự cố vận hành.
1. Bất biến theo lần gọi. Hệ thống chắc chắn sẽ nhận trùng callback. Dùng referenceNumber làm khóa chống trùng, lưu vào bảng có ràng buộc duy nhất ở tầng cơ sở dữ liệu. Kiểm tra trùng chỉ ở tầng ứng dụng sẽ để lọt hai callback đến đồng thời.
2. Phản hồi nhanh, xử lý bất đồng bộ. Ghi nhận callback vào hàng đợi và trả HTTP 200 ngay, thay vì xử lý toàn bộ nghiệp vụ trong request. Trả lời chậm có thể bị coi là thất bại và kích hoạt thử lại.
3. Đối chiếu số tiền trước khi trả dịch vụ. Luôn so khớp amount trong callback với số tiền của đơn hàng trong cơ sở dữ liệu. Không trả dịch vụ chỉ dựa trên sự tồn tại của callback.
4. Ghi nhật ký toàn bộ payload thô. Lưu nguyên văn phần thân của mọi callback, kể cả callback bị từ chối hay xử lý lỗi. Đây là bằng chứng duy nhất khi cần đối chất với VietQR hoặc ngân hàng.
5. Giới hạn dải địa chỉ IP nguồn. Chỉ chấp nhận request từ dải IP mà VietQR sử dụng. Đây là lớp phòng vệ bổ sung bên cạnh cơ chế token.
6. Không tin cậy callback là kênh duy nhất. Bắt buộc xây dựng tác vụ đối soát chủ động ở Bước 4.
5.3. Mẫu xử lý callback khuyến nghị
@Transactional
public void handleCallback(CallbackPayload p) {
// 1. Chong trung /
// Bat exception vi pham rang buoc duy nhat, KHONG dung SELECT truoc INSERT
try {
txnLogRepo.insert(p.getReferenceNumber(), rawBody);
} catch (DuplicateKeyException e) {
[log.info**](https://vietqr.com/huong-dan-tich-hop-vietqr#)**("Callback trung, bo qua: {}", p.getReferenceNumber());
return; // van tra HTTP 200
}
// 2. Doi chieu don hang /
Order order = orderRepo.findByOrderId(p.getOrderId());
if (order == null) { alert("Khong tim thay don hang"); return; }
if (order.getAmount() != p.getAmount()) { alert("Lech so tien"); return; }
if (order.isPaid()) { return; } // da xu ly
// 3. Cap nhat va tra dich vu /
order.markPaid(p.getReferenceNumber());
serviceQueue.enqueue(order.getId()); // xu ly bat dong bo
}
Điểm mấu chốt: dựa vào ràng buộc duy nhất của cơ sở dữ liệu để chống trùng, không dùng mẫu kiểm tra rồi mới ghi.* |
Vì sao không dùng mẫu kiểm tra rồi mới ghi
Nếu hai callback cho cùng một giao dịch đến đồng thời, cả hai đều có thể vượt qua bước kiểm tra trước khi bất kỳ bản ghi nào được ghi xuống. Kết quả là dịch vụ được trả hai lần.
Ràng buộc duy nhất ở tầng cơ sở dữ liệu loại bỏ hoàn toàn khoảng trống này, vì việc kiểm tra và ghi diễn ra như một thao tác nguyên tử.
5.4. Kiểm thử callback trên Sandbox
Sandbox có API Test Callback để giả lập việc người dùng quét mã và xác nhận thanh toán, không cần giao dịch thật.
Lỗi thường gặp nhất
Trường content truyền vào API Test Callback phải là giá trị lấy từ phản hồi của API sinh QR, tức là giá trị đã có tiền tố đối soát, không phải giá trị mà Đối tác đã gửi lên.
Việc cần làm trong bước này
· Ghi lại nguyên văn payload callback nhận được vào tài liệu nội bộ. Vì VietQR chưa cung cấp đặc tả bằng văn bản, payload thực tế quan sát được chính là đặc tả đáng tin cậy nhất mà Đối tác có.
6. Bước 4 — Đối soát chủ động
6.1. Vì sao bước này bắt buộc
Cơ chế thử lại 10 lần của VietQR chỉ bù trừ cho trường hợp hệ thống Đối tác tạm thời không nhận được dữ liệu.
Nó không bù trừ cho trường hợp ngân hàng không báo giao dịch sang VietQR, vì khi đó VietQR không có gì để gửi đi.
Theo mô tả của VietQR, khi hệ thống ngân hàng nhận quá tải, ngân hàng chỉ lưu thông tin giao dịch mà không thực hiện đối soát, do đó không thông báo giao dịch sang VietQR. Đây là tình huống nằm hoàn toàn ngoài phạm vi của cơ chế thử lại.
Hệ quả nếu bỏ qua bước này: tiền đã vào tài khoản nhưng người dùng không nhận được dịch vụ, và hệ thống không tự phát hiện được.
6.2. Thiết kế tác vụ đối soát
1. Chạy mỗi 2 đến 5 phút, quét các đơn hàng ở trạng thái chờ thanh toán có tuổi đời từ 3 phút trở lên.
2. Với mỗi đơn hàng, gọi API Check Transaction với type = 0 và value = orderId.
3. Nếu tìm thấy giao dịch đã thanh toán, xử lý qua đúng luồng callback thông thường: cùng một hàm xử lý, cùng cơ chế chống trùng theo referenceNumber.
4. Dừng đối soát khi đơn hàng vượt quá thời hạn, khuyến nghị 20 phút; chuyển sang trạng thái quá hạn và ghi nhận để đối soát cuối ngày.
5. Thiết lập cảnh báo khi tỷ lệ đơn hàng được cứu bởi tác vụ này vượt ngưỡng. Đây là tín hiệu sớm cho thấy kênh callback đang gặp vấn đề.
Nguyên tắc quan trọng nhất của bước này
Không viết hai nhánh xử lý riêng cho callback và cho đối soát chủ động. Hai nhánh sẽ phân kỳ theo thời gian và tạo ra lỗ hổng rất khó phát hiện.
Đối soát chủ động chỉ nên là một nguồn dữ liệu đầu vào khác cho cùng một hàm xử lý đã dùng cho callback.
6.3. Hạn chế cần biết trước
API Check Transaction không khả dụng trên Sandbox. Do đó toàn bộ tác vụ đối soát chủ động không thể kiểm thử đầu-cuối trước khi golive.
Khuyến nghị thiết kế tầng truy cập API có thể thay thế bằng đối tượng giả lập, để ít nhất kiểm thử được phần logic nghiệp vụ trên Sandbox.
7. Bước 5 — Hoàn tiền
7.1. Hai ràng buộc an toàn của VietQR
1. Hoàn tiền luôn gắn với một giao dịch gốc. Không thể tạo lệnh hoàn tiền độc lập; mọi lệnh hoàn đều phải tham chiếu referenceNumber của giao dịch đã thanh toán.
2. Tổng số tiền hoàn không vượt quá số tiền gốc. Có thể hoàn nhiều lần, nhưng tổng giá trị các lần hoàn bị giới hạn bởi số tiền của giao dịch gốc. Cơ chế này cho phép hoàn từng phần một cách an toàn.
So tien con co the hoan = amount - amountRefunded
(lay tu API Check Transaction /
7.2. Luồng hoàn tiền khuyến nghị
1. Gọi API Check Transaction để lấy trạng thái thực tế của giao dịch gốc, đặc biệt là hai trường refundCount và amountRefunded.
2. Tính số tiền còn có thể hoàn. Nếu số tiền cần hoàn vượt quá giá trị này, dừng lại và báo lỗi nghiệp vụ, không gọi API Refund.
3. Sinh và lưu một mã định danh yêu cầu hoàn tiền phía Đối tác, để phân biệt yêu cầu hoàn tiền với lần gọi API. Một yêu cầu có thể phát sinh nhiều lần gọi.
4. Gọi API Refund. Lưu lại nguyên văn cả request và response.
5. Nếu thành công, trường message trong phản hồi chứa mã giao dịch hoàn do ngân hàng sinh ra. Lưu giá trị này để đối soát với ngân hàng.
6. Chờ callback với transType = "D" để xác nhận trạng thái cuối cùng. Đối soát lại bằng Check Transaction.
Hai điểm dễ hiểu nhầm
Thứ nhất: trong phản hồi thành công, trường message không chứa thông điệp mô tả mà chứa mã giao dịch hoàn. Nội dung trường này khi thất bại chưa được VietQR mô tả, nên phải kiểm tra status trước rồi mới diễn giải message.
Thứ hai: phản hồi HTTP 200 của API Refund không phải bằng chứng tiền đã về tài khoản người dùng. Nó chỉ xác nhận VietQR đã tiếp nhận và chuyển lệnh sang ngân hàng.
7.3. Xử lý khi hoàn tiền thất bại
VietQR không có cơ chế thử lại tự động cho API Refund. Cơ chế thử lại 10 lần trong 5 phút áp dụng cho callback, không áp dụng cho lệnh hoàn tiền.
Yêu cầu bắt buộc
· Không tự động thử lại lệnh hoàn tiền khi chưa xác định được nguyên nhân thất bại. Nếu lệnh hoàn thứ nhất thực tế đã thành công nhưng phản hồi bị mất, việc thử lại sẽ hoàn tiền hai lần.
· Trước mỗi lần thử lại, gọi Check Transaction và kiểm tra refundCount cùng amountRefunded để xác định trạng thái thực tế. Đây là nguồn dữ liệu đáng tin cậy hơn phản hồi của chính lệnh hoàn tiền.
· Đưa lệnh hoàn tiền thất bại vào hàng đợi xử lý thủ công có người phê duyệt, kèm đầy đủ nhật ký request và response.
8. Mười lỗi thường gặp
Bảng tổng hợp các lỗi mà đội tích hợp hay mắc phải, kèm cách xử lý.
# | # | Lỗi | Cách xử lý |
|---|---|---|---|
1 | Tự sinh password thay vì dùng base64(username) | Áp dụng đúng quy tắc tại Mục 3.1. Kiểm chứng bằng cách giải mã trường user trong token trả về. | 2 |
Gọi Get Token trước mỗi request nghiệp vụ | Cache token trong bộ nhớ, làm mới khi còn 30 đến 60 giây. | 3 | Gửi amount có dấu phân cách, ví dụ 10.000 |
Chuẩn hóa về số nguyên trước khi gửi. Thêm kiểm tra ở tầng gọi API. | 4 | content vượt 23 ký tự, orderId vượt 13 ký tự | Cắt chuỗi ở phía Đối tác. Không dựa vào việc VietQR tự cắt. |
5 | Gửi userBankName có dấu tiếng Việt | Chuyển về chữ HOA không dấu trước khi gửi. | 6 |
Gọi Test Callback với content chưa có tiền tố đối soát | Dùng đúng giá trị content lấy từ phản hồi của API sinh QR. | 7 | Chống trùng callback bằng mẫu kiểm tra rồi mới ghi |
Dùng ràng buộc duy nhất ở tầng cơ sở dữ liệu, bắt lỗi vi phạm ràng buộc. Xem Mục 5.3. | 8 | Bóc tách tiền tố VQR, SQR, SMQR từ trường content để đối soát | Cách này chỉ đúng trên Sandbox. Trên Production phải đối soát theo orderId hoặc referenceNumber. |
9 | Đặt thời hạn đơn hàng ngắn hơn hoặc bằng 15 phút | Đặt dài hơn vòng đời mã QR, khuyến nghị 20 phút, để tránh tình huống tiền đã vào nhưng đơn đã hủy. | 10 |
9. Chuyển từ Sandbox sang Production
9.1. Khác biệt về tập tính năng
API | Sandbox | Production | Hệ quả |
|---|---|---|---|
Get Token | Có | Có | — |
Generate QR Code | Có | Có | — |
Create terminalCode | Có | Có | Giá trị tid khác nhau giữa hai môi trường; không cứng hóa trong cấu hình |
Check Transaction | Không | Có | Tác vụ đối soát chủ động không kiểm thử được trên Sandbox |
Refund | Không | Có | Toàn bộ luồng hoàn tiền phải kiểm thử trên Production |
9.2. Khác biệt về mô hình đối soát
Đây là khác biệt quan trọng nhất và là nguyên nhân gây lỗi phổ biến nhất khi chuyển môi trường.
Hạng mục | Sandbox | Production |
|---|---|---|
Mã QR trỏ tới | Số tài khoản thụ hưởng | Tài khoản ảo riêng cho từng mã QR |
Cơ chế đối soát | Theo tiền tố trong nội dung chuyển khoản | Theo tài khoản ảo |
Trường content | Bị VietQR chèn tiền tố VQR, SQR hoặc SMQR | Giữ nguyên giá trị gửi lên |
Trường vaAccount | Rỗng | Có giá trị, 13 ký tự |
Trường userBankName | Viết HOA | Viết thường có hoa đầu từ |
Rà soát bắt buộc trước khi chuyển môi trường
Mọi đoạn mã phụ thuộc vào giá trị của ba trường content, vaAccount và userBankName phải được rà soát lại.
Đoạn mã bóc tách tiền tố từ trường content sẽ chạy đúng trên Sandbox nhưng sai trên Production. Ngược lại, logic đối soát theo vaAccount không thể kiểm thử được trên Sandbox vì trường này luôn rỗng.
Khuyến nghị đối soát theo orderId với QR động, hoặc theo referenceNumber, vì hai khóa này ổn định trên cả hai môi trường.
9.3. Danh mục kiểm tra khi chuyển môi trường
Hạng mục | Trạng thái |
|---|---|
Đã thay domain sang [api.vietqr.org](https://vietqr.com/huong-dan-tich-hop-vietqr#) ở toàn bộ điểm gọi | ☐ |
Đã dùng bộ username và password của Production, tách biệt hoàn toàn với Sandbox | ☐ |
Đã nhận secretKey dùng cho hoàn tiền qua kênh an toàn | ☐ |
Đã rà soát logic phụ thuộc vào content, vaAccount, userBankName | ☐ |
Đã đăng ký endpoint callback Production với VietQR | ☐ |
Đã đăng ký lại terminalCode trên Production và cập nhật giá trị tid mới | ☐ |
Đã thiết lập danh sách cho phép theo dải IP nguồn của callback | ☐ |
Đã kiểm thử luồng thanh toán bằng giao dịch tiền thật giá trị nhỏ | ☐ |
Đã kiểm thử luồng hoàn tiền bằng giao dịch tiền thật giá trị nhỏ | ☐ |
10. Kiểm thử và nghiệm thu
10.1. Bộ ca kiểm thử tối thiểu
Mã | Ca kiểm thử | Kết quả kỳ vọng | MT |
|---|---|---|---|
TC-01 | Lấy token với thông tin xác thực hợp lệ | Nhận access\_token, expires\_in = 300 | SB |
TC-02 | Lấy token với thông tin xác thực sai | Nhận lỗi. Ghi lại mã trạng thái và phần thân phản hồi | SB |
TC-03 | Gọi API với token đã hết hạn | Cơ chế tự làm mới token hoạt động đúng | SB |
TC-04 | Sinh QR động với tham số hợp lệ | Nhận qrCode, orderId trả lại đúng giá trị gửi lên | SB |
TC-05 | Sinh QR với amount có dấu phân cách | Bị từ chối, hoặc hệ thống Đối tác đã chặn từ trước | SB |
TC-06 | Sinh QR với content dài 24 ký tự | Ghi lại hành vi thực tế: lỗi hay bị cắt bớt | SB |
TC-07 | Dựng ảnh QR và quét bằng ứng dụng ngân hàng | Hiển thị đúng tài khoản thụ hưởng và đúng số tiền | SB |
TC-08 | Gọi Test Callback với content đúng | Endpoint nhận được dữ liệu. Lưu nguyên văn payload | SB |
TC-09 | Gọi Test Callback hai lần với cùng dữ liệu | Chỉ trả dịch vụ một lần | SB |
TC-10 | Endpoint callback trả lỗi ở lần gọi đầu | VietQR thử lại. Ghi lại số lần và khoảng cách thực tế | SB |
TC-11 | Tác vụ đối soát phát hiện giao dịch chưa nhận callback | Đơn hàng được cập nhật qua cùng luồng xử lý với callback | PR |
TC-12 | Quét lại mã QR động đã thanh toán | Ứng dụng ngân hàng từ chối. Ghi lại thông báo hiển thị | PR |
TC-13 | Quét mã QR động đã để quá 15 phút | Ứng dụng ngân hàng từ chối. Ghi lại thông báo hiển thị | PR |
TC-14 | Hoàn tiền toàn phần | status = SUCCESS, message chứa mã giao dịch hoàn | PR |
TC-15 | Hoàn tiền từng phần, chia hai lần | refundCount = 2, amountRefunded đúng tổng | PR |
TC-16 | Hoàn tiền vượt quá số tiền gốc | Bị từ chối. Ghi lại mã lỗi và thông báo | PR |
TC-17 | Nhận callback của giao dịch hoàn tiền | Nhận được transType = "D", hệ thống phân loại đúng | PR |
Hạng mục bàn giao bắt buộc của giai đoạn kiểm thử
Toàn bộ payload callback thực tế quan sát được trên Sandbox phải được ghi lại nguyên văn và bàn giao như một tài liệu chính thức.
Toàn bộ phản hồi khác HTTP 200 phải được ghi lại để lập bảng mã lỗi thực nghiệm.
Vì VietQR chưa cung cấp hai nội dung này bằng văn bản, kết quả thực nghiệm chính là tài liệu tham chiếu đáng tin cậy nhất.
11. Danh mục kiểm tra trước khi golive
11.1. Hạng mục phụ thuộc VietQR
Hạng mục | Trạng thái |
|---|---|
Đã nhận đặc tả callback đầy đủ bằng văn bản | ☐ |
Đã nhận bảng mã lỗi, hoặc đã lập bảng mã lỗi thực nghiệm từ Sandbox | ☐ |
Đã làm rõ ý nghĩa bốn tham số sign, urlLink, note, additionalData | ☐ |
Đã làm rõ bảng ánh xạ giá trị trường status | ☐ |
Đã kiểm chứng thực nghiệm cả ba công thức checkSum | ☐ |
Đã làm rõ cơ chế chống trùng lặp lời gọi phía VietQR | ☐ |
11.2. Hạng mục phía Đối tác
Hạng mục | Trạng thái |
|---|---|
Cơ chế chống trùng theo referenceNumber có ràng buộc duy nhất ở tầng cơ sở dữ liệu | ☐ |
Tác vụ đối soát chủ động đã hoàn thiện và được kiểm thử | ☐ |
Đối soát chủ động và callback dùng chung một hàm xử lý | ☐ |
Thời hạn đơn hàng đã đặt dài hơn 15 phút | ☐ |
Endpoint callback xử lý bất đồng bộ, trả HTTP 200 nhanh | ☐ |
Nhật ký lưu nguyên văn payload callback, có che dấu thông tin xác thực | ☐ |
Thông tin bí mật lưu trong kho bí mật, không nằm trong mã nguồn | ☐ |
Cấu hình Sandbox và Production tách biệt hoàn toàn | ☐ |
Đã thiết lập giám sát và cảnh báo cho các chỉ số vận hành | ☐ |
11.3. Chỉ số cần giám sát sau golive
Chỉ số | Ý nghĩa |
|---|---|
Tỷ lệ sinh QR thất bại | Phát hiện sớm sự cố ở tầng API hoặc lỗi cấu hình tham số. |
Độ trễ từ thanh toán đến callback | Tăng bất thường là dấu hiệu ngân hàng hoặc VietQR đang quá tải. |
Tỷ lệ đơn hàng được cứu bởi tác vụ đối soát chủ động | Chỉ số quan trọng nhất. Tăng đột biến nghĩa là kênh callback đang gặp vấn đề. |
Số callback trùng lặp bị chặn | Xác nhận cơ chế chống trùng đang hoạt động. Bằng 0 liên tục có thể là dấu hiệu cơ chế chưa được kích hoạt đúng. |
Tỷ lệ hoàn tiền thất bại | Trực tiếp ảnh hưởng tới trải nghiệm và uy tín với người dùng cuối. |
Phụ lục A. Bảng thuật ngữ đối chiếu
Tên trường / Thuật ngữ | Tiếng Việt |
|---|---|
QR động | qrType = 0. Mã QR gắn sẵn số tiền và mã đơn hàng, dùng một lần, vòng đời 15 phút. |
QR tĩnh | qrType = 1. Mã QR cố định cho một điểm bán, người trả tự nhập số tiền. |
QR bán động | qrType = 3. Mã QR gắn số tiền và thông tin điểm bán, dịch vụ; dùng lâu dài. |
orderId | Mã đơn hàng do Đối tác sinh, tối đa 13 ký tự. Khóa đối soát tự động chính. |
referenceNumber | Mã giao dịch do ngân hàng thụ hưởng sinh. Khóa đối soát với ngân hàng và khóa chống trùng. |
vaAccount | Tài khoản ảo, 13 ký tự, gắn riêng cho từng mã QR trên Production. |
terminalCode | Mã điểm bán, 10 ký tự, Đối tác tự đặt, phải đăng ký trước. |
serviceCode | Mã dịch vụ, Đối tác tự đặt, dùng phân tách doanh thu theo loại dịch vụ. |
transType | "C" là Credit, tiền vào. "D" là Debit, tiền ra, phát sinh khi hoàn tiền. |
checkSum | Chuỗi băm MD5 kiểm tra tính toàn vẹn của request. Mỗi API có công thức riêng. |
Callback / Transaction Sync | Cơ chế VietQR chủ động gọi vào hệ thống Đối tác để đẩy dữ liệu giao dịch. |
Bất biến theo lần gọi | Tính chất cho phép thực hiện nhiều lần mà kết quả không đổi. Bắt buộc với xử lý callback. |
Đối soát chủ động | Tác vụ nền định kỳ gọi Check Transaction để tự phát hiện giao dịch chưa nhận callback. |
EMVCo MPM | Chuẩn quốc tế định dạng dữ liệu trong mã QR mà cửa hàng hiển thị cho khách quét. |
Sandbox / Production | Môi trường kiểm thử và môi trường vận hành thật. Hai bộ khóa hoàn toàn tách biệt. |
Phụ lục B. Hạng mục chờ VietQR xác nhận
Các hạng mục dưới đây chưa được VietQR cung cấp hoặc chưa đủ rõ để hiện thực hóa. Đội phát triển không nên viết mã dựa trên suy đoán cho những phần này.
B.1. Ưu tiên cao
Mã | Nội dung cần làm rõ | Rủi ro |
|---|---|---|
A-01 | Đặc tả đầy đủ bằng văn bản của hai endpoint callback: cấu trúc payload, danh sách trường, phản hồi VietQR mong đợi, tiêu chí xác định thất bại, khoảng cách giữa các lần thử lại. | Xây dựng endpoint dựa trên suy đoán, chỉ phát hiện sai khi đã tích hợp xong |
A-02 | Bảng mã trạng thái HTTP và mã lỗi nghiệp vụ cho toàn bộ các API. | Không phân biệt được lỗi tạm thời với lỗi vĩnh viễn |
A-03 | Ý nghĩa của bốn tham số sign, urlLink, note, additionalData. Đặc biệt tham số sign, nếu là chữ ký chống giả mạo request. | Có thể bỏ sót một cơ chế bảo mật quan trọng |
A-04 | Bảng ánh xạ đầy đủ các giá trị của trường status trong phản hồi Check Transaction. | Không phân biệt được các trạng thái thất bại |
A-05 | Xác nhận các công thức checkSum: thứ tự nối chuỗi, có ký tự phân tách hay không, chữ hoa hay chữ thường, kiểu dữ liệu của amount. | Mọi lệnh hoàn tiền và đăng ký điểm bán bị từ chối |
A-06 | Cơ chế xử lý hoàn tiền thất bại: mã lỗi, cách phân biệt lỗi tạm thời và vĩnh viễn, điều kiện an toàn để thử lại. | Rủi ro hoàn tiền hai lần |
B.2. Ưu tiên trung bình
Mã | Nội dung cần làm rõ |
|---|---|
A-08 | Danh mục mã ngân hàng được hỗ trợ, ngoài MB. |
A-09 | Giới hạn tần suất gọi của từng API và cơ chế phản hồi khi vượt hạn mức. |
A-10 | Dải địa chỉ IP nguồn mà VietQR dùng để gọi callback. |
A-11 | Giới hạn độ dài của userBankName, terminalName, terminalAddress, serviceCode, và content của API Refund. |
A-12 | Ý nghĩa các trường phản hồi chưa được mô tả: existing, imgId, transactionId, subTerminalCode, type. |
A-13 | Hành vi hệ thống khi gửi trùng terminalCode ở API Generate QR. |
A-14 | Kiểu dữ liệu chuẩn của qrType và của amount ở API Refund. |
A-15 | Múi giờ tham chiếu của timeCreated và timePaid. |
A-16 | Nội dung trường message của API Refund trong trường hợp thất bại. |
12. Hỗ trợ kỹ thuật
12.1. Phạm vi hỗ trợ của Bluecom
· Giải đáp thắc mắc kỹ thuật về nội dung tài liệu này và tài liệu đặc tả.
· Làm việc với VietQR để giải quyết các hạng mục trong Phụ lục B.
· Rà soát thiết kế tích hợp và mã nguồn phía Đối tác trước khi golive.
· Đồng hành trong giai đoạn nghiệm thu và chuyển môi trường.
12.2. Thông tin liên hệ
Hạng mục | Thông tin |
|---|---|
Đơn vị | Công ty Bluecom — Khối Giải pháp Tích hợp |
Đầu mối kỹ thuật | [Họ tên — chức danh] |
Thư điện tử | [[email protected]](https://vietqr.com/huong-dan-tich-hop-vietqr#) |
Điện thoại | +84.939603636 |
Ngôn ngữ hỗ trợ | Tiếng Việt, tiếng Trung, tiếng Anh |
Thời gian hỗ trợ | [Khung giờ hỗ trợ] Các trường trong ngoặc vuông cần được điền trước khi bàn giao tài liệu cho Đối tác. | |
Ghi chú cuối
Tài liệu này được biên soạn dựa trên đặc tả do VietQR cung cấp, kết hợp với phân tích kỹ thuật độc lập của Bluecom.
Các đặc tả của VietQR có thể thay đổi theo thời gian. Khuyến nghị liên hệ Bluecom nếu phát hiệ
2. Cấu Trúc Triển Khai — 5 Phần
Quá trình triển khai và kiểm thử kết nối API VietQR gồm 5 phần chính, thực hiện tuần tự:
1. Implement Get Token API — triển khai API lấy token xác thực
2. Execute Transaction Sync API — đồng bộ giao dịch/biến động số dư
3. Call Get Token API — gọi thử API lấy token
4. Generate VietQR Code API — sinh mã VietQR
5. Test Callback — kiểm thử luồng callback
3. Hướng Dẫn Thực Hiện Từng Bước
Bước 1 — Cấu hình và kết nối API
Khách hàng thực hiện lần lượt theo đúng thứ tự sau, sau đó mới bắt đầu test kết nối:
✔ Bước 1: Triển khai API Get Token
✔ Bước 2: Triển khai API Transaction Sync
✔ Bước 3: Gọi thử API Get Token
✔ Bước 4: Triển khai API Generate VietQR Code
✔ Bước 5: Gọi thử API Test Callback
Bước 2 — Kiểm tra dữ liệu
• Kiểm tra lại dữ liệu đã cấu hình tại Bước 1 và Bước 2 để đảm bảo tính chính xác.
• Nếu phát hiện lỗi, cần chỉnh sửa trước khi tiếp tục các bước tiếp theo.
Lưu ý: Sau khi hoàn tất các bước trên, khách hàng có thể tiến hành kiểm thử toàn bộ quy trình để đảm bảo hệ thống hoạt động đúng yêu cầu.
4. Hướng Dẫn Sau Khi Hoàn Tất Test (Go-live)
Sau khi test thành công, khách hàng sẽ được nghiệm thu và triển khai trên môi trường dịch vụ thực của tài khoản ngân hàng.
Liên hệ bộ phận kinh doanh (Khối Khách hàng Doanh nghiệp số) để được hỗ trợ triển khai:
Cán bộ KD | Mobile | |
|---|---|---|
Lê Hương | 092233.3636 | |
Tuấn Bùi (Nguyễn) | 0923 006 234 | |
Tạ Quang Tuấn | 0966 266 049 | |
Hoàng Văn Hiển | 0565 606 789 | |
Thịnh Nguyễn | 0936 381 333 | |
Tuấn Phạm | 096838.3636 | |
Hiếu Hà | 0939 603 636 |
5. Mô Tả Chi Tiết Tài Liệu API
5.1. API Get Token
API xác thực, dùng để lấy token truy cập trước khi gọi các API khác (Transaction Sync, Generate VietQR Code, Test Callback).
5.2. API Transaction Sync
Áp dụng để đối tác đồng bộ biến động số dư do VietQR trả về, theo 5 bước sau:
Bước 1: Cấp quyền truy cập API
• Đối tác cần cấp quyền cho VietQR bằng cách thiết lập quyền truy cập vào API Transaction Sync.
• Cấu hình điểm nhận dữ liệu (webhook) để VietQR có thể gửi thông tin biến động số dư.
Bước 2: Cấu hình đầu hứng (webhook)
• Đối tác cung cấp URL endpoint để nhận dữ liệu.
• Đảm bảo endpoint hỗ trợ nhận dữ liệu từ VietQR qua phương thức POST.
• Kiểm tra bảo mật, xác thực request gửi đến từ VietQR.
Bước 3: VietQR gửi dữ liệu biến động số dư
Khi có giao dịch mới, VietQR gửi thông tin biến động số dư theo thời gian thực đến webhook của đối tác. Dữ liệu bao gồm:
Trường dữ liệu | Mô tả |
|---|---|
Số tiền thay đổi | Giá trị biến động của giao dịch |
Số dư mới | Số dư tài khoản sau giao dịch |
Thời gian giao dịch | Thời điểm giao dịch phát sinh |
Mã giao dịch | Mã định danh giao dịch do VietQR cấp |
Thông tin khác | Tùy theo cấu hình đã thống nhất với VietQR |
Bước 4: Xác nhận và xử lý dữ liệu từ VietQR
• Đối tác nhận request từ VietQR và xác thực dữ liệu.
• Lưu trữ hoặc xử lý thông tin theo nhu cầu (cập nhật hệ thống, hiển thị trên ứng dụng, v.v.).
• Trả về response 200 OK để xác nhận đã nhận dữ liệu thành công.
Bước 5: Kiểm tra và giám sát
• Định kỳ kiểm tra log để đảm bảo không có lỗi kết nối.
• Nếu có lỗi (mất kết nối, dữ liệu sai, v.v.), kiểm tra lại cấu hình webhook hoặc liên hệ bộ phận hỗ trợ của VietQR.
Lưu ý: VietQR có thể yêu cầu xác thực webhook bằng token hoặc chữ ký số để đảm bảo an toàn khi truyền dữ liệu.