Đối soát giao dịch bằng API MONA Pay
Video hướng dẫn
Xem transcript video (9 phần)
Lưới đỡ cho webhook
Webhook chạy thời gian thực nhưng chỉ một lần bảo trì, mất mạng hoặc khóa cơ sở dữ liệu cũng có thể làm hệ thống của bạn bỏ lỡ giao dịch. Trong video này, mình dựng một vòng đối soát theo tài khoản ảo, phân trang đúng cách, bổ sung khoản thiếu và đặt lịch chạy. Mục tiêu là webhook có trục trặc thì cuối ca vẫn không sót tiền.
Gọi API giao dịch
Endpoint cần gọi là GET /api/v1/acb/virtual-account/transactions. Query bắt buộc có virtual_account_number, là số tài khoản ảo cần lấy giao dịch. page bắt đầu từ một và limit tối đa một trăm. Vì đây là lệnh GET, request chỉ cần Authorization: Bearer và không cần X-Client-Secret. Bạn nên gọi riêng cho từng tài khoản ảo đang dùng.
Đọc response phân trang
Response dùng khung success, message, data. Bên trong, data.data là mảng giao dịch. Các trường current_page, per_page, total và last_page mô tả phân trang. Mỗi giao dịch có mã, số tiền, thời gian, nội dung và tài khoản nhận giống dữ liệu webhook. Dừng vòng lặp khi current_page lớn hơn hoặc bằng last_page. Danh sách mới nhất nằm trước.
Thuật toán đối soát
Thuật toán bắt đầu bằng trang đầu với limit bằng một trăm. Với mỗi bản ghi, tìm transaction_code trong bảng giao dịch nội bộ. Mã chưa có thì chèn và gọi đúng hàm xử lý mà webhook đang dùng. Mã đã có thì bỏ qua. Nếu cả trang không có mã mới, dừng; nếu vẫn có giao dịch mới, đọc trang kế tiếp. Cuối lần chạy, lưu thời điểm và số khoản được bổ sung.
Dừng khi hết mã mới
Hiện API chưa có since_id hay bộ lọc khoảng ngày. Vì thế, đừng kéo toàn bộ lịch sử ở mọi lần chạy. Bắt đầu từ dữ liệu mới nhất và dừng ngay khi cả trang đều đã tồn tại. Cả webhook và tác vụ đối soát phải ghi vào cùng một bảng có UNIQUE trên transaction_code. Nếu hai luồng dùng hai bảng khác nhau, bạn vẫn tạo trùng dù thuật toán đọc đúng.
Làm mới token hết hạn
Token truy cập có hạn dùng. Nếu tác vụ định kỳ nhận HTTP bốn trăm lẻ một, hãy đăng nhập lại hoặc xin token mới rồi thử lại trang đang đọc. Đừng bỏ qua lỗi và ghi mốc đối soát thành công. Lệnh mẫu trong tài liệu còn in transaction_code, amount và ngày giao dịch của trang đầu để bạn so nhanh trước khi đưa logic chèn dữ liệu vào chạy tự động.
Chọn lịch chạy phù hợp
Tần suất phụ thuộc việc khách chờ bao lâu. Web bán hàng giao ngay, vé hoặc khóa học mở tức thì có thể chạy mỗi mười lăm phút. Phần mềm quản lý, học phí hay phí dịch vụ có thể chạy mỗi giờ. Kế toán chốt sổ chạy lúc hai mươi ba giờ ba mươi mỗi ngày. Cách chắc hơn là đối soát nhanh trang đầu mỗi giờ và đọc đủ các trang vào cuối ngày.
Đối soát trên dashboard
Nếu không viết code, vào dashboard mục Giao dịch, lọc theo tài khoản ảo và khoảng ngày rồi xuất CSV để so trong Excel bằng transaction_code. API trả trống dù có tiền thì kiểm tra virtual_account_number; khoản đó có thể vào tài khoản chính hoặc một tài khoản ảo khác. Tác vụ chạy quá lâu nghĩa là chưa dừng khi hết mã mới. Chèn trùng thì kiểm tra ràng buộc UNIQUE và hàm xử lý dùng chung.
Mở docs và chạy thử
Code PHP, Node và thuật toán đầy đủ nằm tại monapay.vn/docs/webhooks/doi-soat. Bạn có thể đăng ký tại my.monapay.vn, mở mục Giao dịch để đối chiếu kết quả API với dữ liệu dashboard trước khi đặt lịch tự động. Nếu còn kẹt ở phân trang hoặc giao dịch thiếu, 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ợ.
Đối soát là bước so danh sách giao dịch MONA Pay ghi nhận với bảng giao dịch trong hệ thống của bạn, để bổ sung khoản nào webhook chưa tới (máy chủ bảo trì, mất mạng, lỗi code). Bạn gọi GET /api/v1/acb/virtual-account/transactions theo trang, mỗi trang tối đa 100 giao dịch, và so bằng transaction_code. Nên chạy mỗi giờ hoặc ít nhất mỗi ngày.
Vì sao cần đối soát dù đã có webhook
Webhook là kênh thời gian thực nhưng phụ thuộc máy chủ của bạn đang sống lúc tiền vào. Một lần deploy 2 phút, một lần hết hạn chứng chỉ SSL, một lần database khoá là có khoản bị lỡ. Hiện MONA Pay gửi lại thủ công (gửi lại tự động đang triển khai, xem Gửi lại và xử lý lỗi), nên đối soát định kỳ là lưới đỡ cần có ngay từ ngày đầu.
API danh sách giao dịch
| Tham số query | Bắt buộc | Ý nghĩa |
|---|---|---|
virtual_account_number |
có | Số VA cần lấy giao dịch |
page |
không | Trang, bắt đầu từ 1 |
limit |
không | Số giao dịch mỗi trang, tối đa 100 |
Request là GET nên chỉ cần Authorization: Bearer <access_token>, không cần X-Client-Secret.
Response theo khung chung {"success": true, "message": "...", "data": {...}}, trong đó data là khối phân trang (kiểm code BE 28/08/2026): data.data là mảng giao dịch, kèm current_page, per_page, total, last_page. Mỗi giao dịch trong data.data mang cùng thông tin với payload webhook: mã giao dịch, số tiền, thời gian, nội dung, số tài khoản nhận. Dừng vòng lặp khi current_page >= last_page. Chi tiết trường xem https://monapay.vn/openapi.json (mục /api/v1/acb/virtual-account/transactions).
Hiện API chưa có tham số since_id hay lọc theo khoảng ngày. Cách làm việc là kéo theo trang từ trang 1, giao dịch mới nhất ở đầu, dừng khi gặp transaction_code đã có trong bảng của bạn và trang đó không còn mã nào mới.
Thuật toán đối soát
- Với mỗi VA đang dùng, gọi trang 1 với
limit=100. - Với mỗi giao dịch, kiểm
transaction_codeđã có trong bảng của bạn chưa. - Chưa có: chèn vào bảng và chạy đúng logic xử lý như khi nhận webhook (đổi trạng thái đơn, gửi email…). Nhớ đây là cùng một hàm xử lý, để đơn được cập nhật y hệt dù tới bằng đường nào.
- Nếu cả trang đều đã có, dừng. Nếu còn mã mới, gọi trang tiếp theo.
- Ghi lại thời điểm chạy và số giao dịch bổ sung, để bạn biết webhook có đang hụt không.
Lưu ý access_token có hạn dùng (expires_in khi đăng nhập). Script cron nên đăng nhập lại khi nhận 401, xem Xác thực.
Lịch chạy gợi ý
| Loại hệ thống | Tần suất | Lý do |
|---|---|---|
| Web bán hàng giao ngay, ví bán vé, khoá học mở tức thì | Mỗi 15 phút | Khách chờ ngay sau khi chuyển |
| Phần mềm quản lý, thu học phí, thu phí dịch vụ | Mỗi giờ | Đủ nhanh, ít tốn tài nguyên |
| Kế toán cuối ngày | 23:30 mỗi ngày | Chốt sổ, in báo cáo |
Kết hợp cả hai: mỗi giờ chạy đối soát nhanh trang 1, cuối ngày chạy đủ mọi trang.
Đối soát bằng dashboard
Không cần code, bạn vào dashboard mục Giao dịch, lọc theo VA và khoảng ngày, xuất CSV rồi so với sổ bằng Excel: cột transaction_code là khoá, dùng VLOOKUP hoặc đối chiếu bằng Power Query. Cách này hợp với kế toán chốt sổ tuần hoặc tháng.
Lỗi thường gặp
Gọi API trả 401. Token hết hạn. Đăng nhập lại lấy token mới.
Trang 1 trống dù có giao dịch. Sai virtual_account_number, hoặc giao dịch vào tài khoản chính chứ không vào VA đó. Kiểm số VA trong dashboard mục Ngân hàng & VA.
Đối soát chèn trùng giao dịch. Bảng chưa có UNIQUE trên transaction_code, hoặc hàm xử lý webhook và hàm đối soát ghi vào hai bảng khác nhau. Dùng chung một hàm và một bảng.
Script chạy quá lâu. Đang kéo hết mọi trang mỗi lần. Dừng ngay khi gặp trang không còn mã mới, như thuật toán trên.