Tài khoản ngân hàng ảo (virtual account) ACB: tạo VA qua API
Video hướng dẫn
Xem transcript video (9 phần)
Đủ bốn bước mới nhận báo
Tạo xong tài khoản ảo nhưng tiền vào không phát webhook thường không phải lỗi webhook, mà do quy trình ACB còn thiếu bước đăng ký thông báo. Trong video này, mình đi đủ bốn bước tạo tài khoản ảo, gọi tắt là VA: đăng ký, nhập OTP, bật báo giao dịch và nhập OTP lần hai. Bạn cũng biết trường nào phải lưu cho bước kế tiếp.
VA dùng để làm gì
VA là số tài khoản phụ do ACB cấp dưới tài khoản thật. Tiền vẫn nằm trong tài khoản ACB của bạn, nhưng mỗi VA có thể gắn một đơn hoặc một khách để khớp tự động. Điều kiện là tài khoản ACB đứng tên bạn và số điện thoại đang đăng ký với ACB. Không muốn gọi API, dashboard mục Ngân hàng và VA có wizard bốn bước tương tự.
Gửi yêu cầu đăng ký
Ở bước đầu, gọi POST /api/v1/acb/virtual-account/registration với Bearer và X-Client-Secret. Lần đầu chưa có bank_account_id, truyền customer_type như PERS, account_number, phone_number, khối virtual_account_info và user_agreement bằng true. Nếu tài khoản ACB đã nối, có thể truyền bank_account_id rồi bỏ số tài khoản và số điện thoại. Trong khối con, virtual_account_prefix_code là bắt buộc; virtual_account_content có thể chứa mã đơn, còn virtual_account_explain là diễn giải.
Đặt đầu số VA
Đầu số VA do bạn tự đặt bằng chữ in hoa và số, nên ngắn như HOA hoặc SHOP; không cần đăng ký trước. ACB có thể ghép thêm mã đối tác và phần định danh. Vì vậy, đừng tự nối chuỗi. Sau bước đầu, lưu acb_request.id. Nếu đầu số không được chấp nhận, đổi sang đầu số ngắn khác và gửi lại yêu cầu, không cần ra quầy.
Xác thực OTP lần đầu
ACB gửi OTP về số điện thoại. Dùng acb_request_id vừa lưu để gọi POST /api/v1/acb/{acb_request_id}/virtual-account/verification, body chỉ có code. Response trả VA vừa tạo. Lưu id cho bước tiếp theo và virtual_account_number để tạo QR, khớp giao dịch hoặc đưa cho khách. Đây phải là nguyên số ACB trả về, không phải đầu số bạn đã nhập.
Bật thông báo, nhập OTP
Bước ba gọi POST /api/v1/acb/{virtual_account_id}/notification/registration. Body có receive_noti_realtime bằng true để nhận từng giao dịch ngay; false nghĩa là ACB gộp báo cuối ngày. Response trả một acb_request.id mới và ACB gửi OTP lần hai. Bước bốn gọi /notification/verification với ID mới cùng code. Hoàn tất bước này thì tiền vào mới phát webhook hoặc Telegram.
Truy vấn và quản lý VA
Sau khi tạo, dùng GET /api/v1/client/bank-accounts để lấy danh sách tài khoản và bank_account_id. Endpoint virtual-account/retrieve liệt kê VA theo tài khoản. Bạn còn có thể xem chi tiết đăng ký thông báo, sửa kiểu nhận, hủy nhận hoặc hủy VA bằng các endpoint quản lý. Những lệnh ghi đều cần Bearer và X-Client-Secret; một số thay đổi có thể yêu cầu OTP xác thực lại.
Sửa lỗi tạo VA
Lỗi bốn trăm sau bước đầu thường do sai tài khoản ACB, sai số điện thoại hoặc đầu số không được chấp nhận. code sai ở bước hai hay bốn nghĩa là OTP sai hoặc hết hạn; làm lại bước trước để nhận mã mới. Bốn trăm hai mươi hai cho biết thiếu virtual_account_info.virtual_account_prefix_code. VA tồn tại nhưng không thấy giao dịch thì kiểm tra ngay bước ba và bước bốn.
Mở docs hoặc dùng wizard
Sơ đồ bốn bước, body mẫu và code PHP, Node nằm tại monapay.vn/docs/api/tai-khoan-ao-va. Bạn đăng ký tại my.monapay.vn, có thể vào mục Ngân hàng và VA để làm đủ bốn bước bằng wizard trước khi tự động hóa qua API. Nếu toàn bộ quy trình OTP hoặc đăng ký thông báo chưa hoàn tất, 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ợ.
Tài khoản ảo (VA) là số tài khoản phụ do ACB cấp dưới tài khoản thật của bạn. Tiền chuyển vào VA vẫn nằm trong tài khoản ACB thật, nhưng mỗi VA gắn được với 1 đơn hàng hoặc 1 khách nên MONA Pay khớp tiền tự động, không cần đọc nội dung chuyển khoản. Tạo VA qua API gồm 4 bước: gửi yêu cầu đăng ký, nhập OTP ACB gửi về số điện thoại, đăng ký nhận thông báo giao dịch, nhập OTP lần 2. Điều kiện: tài khoản ACB đứng tên bạn và số điện thoại đang đăng ký với ACB.
Bạn không muốn gọi API thì dashboard my.monapay.vn có sẵn wizard 4 bước y hệt, tại mục Ngân hàng & VA.
Đầu số VA do bạn tự đặt
virtual_account_prefix_code không phải mã cần xin ACB hoặc MONA Pay cấp trước. Bạn tự đặt ngay khi tạo VA: dùng chữ in hoa và số, chọn ngắn, dễ nhận ra, ví dụ HOA hoặc SHOP. Không cần ra quầy và không cần đăng ký đầu số trước.
ACB ghép mã đối tác ở phía trước đầu số bạn chọn, rồi thêm phần số định danh. Ví dụ bạn chọn HOA, số VA hoàn chỉnh ACB trả về có thể là LOCHOA000123456. Luôn dùng nguyên virtual_account_number trong response khi tạo QR, khớp giao dịch hoặc đưa cho khách; đừng tự ghép chuỗi. Nếu MONA Pay trả lỗi đầu số, đổi sang một đầu số ngắn khác rồi gửi lại yêu cầu.
Luồng đăng ký tài khoản ảo
| Bước | Endpoint | Ai làm gì |
|---|---|---|
| 1 | POST /api/v1/acb/virtual-account/registration |
Gửi số tài khoản, số điện thoại, đầu số VA. ACB nhận yêu cầu, gửi OTP về điện thoại |
| 2 | POST /api/v1/acb/{acb_request_id}/virtual-account/verification |
Nhập OTP. ACB tạo VA, trả số VA |
| 3 | POST /api/v1/acb/{virtual_account_id}/notification/registration |
Đăng ký nhận thông báo giao dịch tức thì. ACB gửi OTP lần 2 |
| 4 | POST /api/v1/acb/{acb_request_id}/notification/verification |
Nhập OTP lần 2. Từ đây tiền vào là có thông báo về MONA Pay |
Bỏ bước 3 và 4 thì VA có tồn tại nhưng ACB không báo giao dịch về, webhook và Telegram sẽ im lặng. Đây là lỗi đội MONA gặp nhiều nhất khi khách tự làm.
Mọi request dưới đây cần Authorization: Bearer và X-Client-Secret (xem Xác thực).
Bước 1: POST /api/v1/acb/virtual-account/registration
| Trường | Kiểu | Bắt buộc | Ghi chú |
|---|---|---|---|
bank_account_id |
uuid | không | Dùng khi tài khoản ACB đã nối trước đó (lấy từ GET /api/v1/client/bank-accounts). Có trường này thì bỏ account_number, phone_number |
customer_type |
string | không | Loại khách hàng theo mã ACB, ví dụ PERS cho cá nhân |
account_number |
integer | không | Số tài khoản thanh toán ACB (số thật) |
phone_number |
string | không | Số điện thoại đăng ký với ACB, nhận OTP |
virtual_account_info.virtual_account_prefix_code |
string | có | Bạn tự đặt khi tạo VA; dùng chữ in hoa/số, nên ngắn, ví dụ HOA, SHOP; không cần đăng ký trước |
virtual_account_info.virtual_account_content |
string | không | Nội dung định danh gắn với VA (mã đơn, mã khách) |
virtual_account_info.virtual_account_explain |
string | không | Diễn giải khi đăng ký |
virtual_account_info.beneficiary_name_rule |
integer | không | Cách hiển thị tên đơn vị hưởng theo quy ước ACB |
user_agreement |
boolean | không | Khách đồng ý điều khoản dịch vụ, nên gửi true |
Body mẫu (lần đầu, chưa có bank_account_id):
Response 200: data là tài khoản ngân hàng vừa ghi nhận, kèm acb_request chứa id cần cho bước 2.
cURL
Bước 2: POST /api/v1/acb/{acb_request_id}/virtual-account/verification
| Trường | Kiểu | Bắt buộc |
|---|---|---|
code |
string | có, là OTP ACB gửi về điện thoại |
Response 200: data là VA vừa tạo.
virtual_account_number là số bạn đưa cho khách chuyển tiền (hoặc đưa vào QR). id dùng cho bước 3.
Bước 3: POST /api/v1/acb/{virtual_account_id}/notification/registration
| Trường | Kiểu | Bắt buộc | Ghi chú |
|---|---|---|---|
receive_noti_realtime |
boolean | có | true = báo ngay từng giao dịch (cần cho webhook). false = ACB gộp báo cuối ngày |
username |
string (≤50) | không | Thông tin đăng nhập theo yêu cầu ACB, để trống nếu không được ACB yêu cầu |
Response 200/201: data chứa acb_request.id cho bước 4.
Bước 4: POST /api/v1/acb/{acb_request_id}/notification/verification
Body {"code": "<OTP lần 2>"}, giống bước 2. Thành công là xong: từ giao dịch kế tiếp, ACB báo về MONA Pay, MONA Pay bắn webhook hoặc Telegram theo cấu hình của bạn.
Ví dụ PHP: chạy trọn bước 1 và 2
Ví dụ Node: bước 3 và 4
Truy vấn và quản lý
| Endpoint | Việc |
|---|---|
GET /api/v1/client/bank-accounts?page=1&limit=10 |
Danh sách tài khoản ACB đã nối (lấy bank_account_id) |
GET /api/v1/acb/{bank_account_id}/virtual-account/retrieve?virtual_account_number=&page=1&limit=10 |
Danh sách VA của một tài khoản, lọc theo số VA, limit tối đa 100 |
GET /api/v1/acb/{virtual_account_id}/notification/details |
Xem đăng ký thông báo của VA |
POST /api/v1/acb/{acb_notification_id}/notification/modification |
Đổi kiểu nhận thông báo (body như bước 3), cần OTP xác thực lại qua bước 4 |
POST /api/v1/acb/{acb_notification_id}/notification/delete |
Hủy nhận thông báo |
POST /api/v1/acb/{virtual_account_id}/virtual-account/delete |
Hủy VA, không có body. ACB có thể yêu cầu OTP xác thực qua endpoint verification |
Lỗi thường gặp
| Tình huống | Nguyên nhân | Cách xử lý |
|---|---|---|
| 400 sau bước 1 | Số tài khoản không phải ACB, sai số điện thoại đăng ký với ACB, hoặc đầu số VA không được chấp nhận | Kiểm tra lại tài khoản và số điện thoại; nếu lỗi nằm ở đầu số thì đổi đầu số ngắn khác rồi gửi lại, không cần ra quầy đăng ký |
400 code sai ở bước 2/4 |
OTP nhập sai hoặc hết hạn | Làm lại bước trước để ACB gửi OTP mới |
| VA tạo xong nhưng không thấy giao dịch | Chưa làm bước 3 và 4 | Gọi notification/registration rồi xác thực OTP lần 2 |
| 401 | Token hết hạn hoặc thiếu X-Client-Secret | Login lại, kiểm tra header |
| 422 | Thiếu virtual_account_info.virtual_account_prefix_code |
Trường này bắt buộc |