API giao dịch: tra cứu tiền vào theo tài khoản ảo
Mọi giao dịch ACB báo về đều được MONA Pay lưu lại, kể cả khi webhook tới server anh chị thất bại. Truy vấn bằng GET /api/v1/acb/virtual-account/transactions?virtual_account_number=<số VA>&page=1&limit=100 (Bearer token, limit tối đa 100). Mỗi bản ghi có transaction_code là mã tham chiếu ổn định của ngân hàng, dùng làm khoá chống trùng khi đối soát. Giao dịch nào lỡ không tới được server thì gọi endpoint retry để MONA Pay gửi lại webhook hoặc tin Telegram cho đúng giao dịch đó.
GET /api/v1/acb/virtual-account/transactions
Cần Bearer. Hệ thống tìm VA theo số, kiểm tra VA thuộc tài khoản của anh chị rồi mới trả giao dịch.
| Tham số (query) | Kiểu | Bắt buộc | Ghi chú |
|---|---|---|---|
virtual_account_number |
string | có | Số VA, ví dụ MONA0000010234 |
page |
integer ≥1 | không | Mặc định 1 |
limit |
integer 1-100 | không | Mặc định 10 |
curl "https://api.monapay.vn/api/v1/acb/virtual-account/transactions?virtual_account_number=MONA0000010234&page=1&limit=100" \
-H "Authorization: Bearer $MONA_TOKEN"
Response 200:
{
"success": true,
"message": "Success",
"data": {
"data": [
{
"id": "0190d0e1-...",
"acb_callback_request_id": "0190d0e0-...",
"transaction_status": "SUCCESS",
"transaction_channel": "IBFT",
"transaction_date": "2026-08-28T10:45:12",
"effective_date": "2026-08-28T10:45:12",
"debit_or_credit": "credit",
"amount": 2500000,
"transaction_content": "Thanh toan DH10234",
"transaction_code": "FT26240001234",
"account_number": "123456789",
"va_prefix_cd": "MONA",
"va_nbr": "MONA0000010234",
"attributes": {
"remitter_name": "NGUYEN VAN A",
"remitter_account_number": "9876543210",
"issuer_bank_name": "Vietcombank",
"reference_number": "FT26240001234"
}
}
],
"current_page": 1,
"per_page": 100,
"total": 1,
"last_page": 1,
"start": 1,
"end": 1,
"has_next": false,
"has_prev": false
}
}
Ý nghĩa từng trường
| Trường | Ý nghĩa |
|---|---|
id |
ID giao dịch trong MONA Pay, dùng cho endpoint retry |
transaction_status |
Trạng thái ACB trả về (SUCCESS là tiền đã vào) |
transaction_channel |
Kênh giao dịch theo ACB (chuyển khoản nhanh, QR…) |
transaction_date |
Thời điểm giao dịch, giờ Việt Nam |
effective_date |
Ngày hiệu lực ghi sổ |
debit_or_credit |
credit = tiền vào, debit = tiền ra. Webhook hiện chỉ bắn cho tiền vào |
amount |
Số tiền VND, số nguyên |
transaction_content |
Nội dung chuyển khoản khách gõ (hoặc QR điền sẵn) |
transaction_code |
Mã tham chiếu ngân hàng, ổn định qua mọi lần gửi lại, khoá chống trùng |
account_number |
Số tài khoản ACB thật nhận tiền |
va_prefix_cd, va_nbr |
Đầu số và số VA khớp giao dịch, null nếu tiền vào thẳng tài khoản chính |
attributes |
Thông tin phụ ACB gửi kèm: tên và số tài khoản người chuyển, ngân hàng chuyển, số tham chiếu, các trường custom1..custom10 nếu có |
Ngoài ra, cùng bản ghi này là thứ webhook gửi sang anh chị dưới dạng rút gọn (xem Định dạng payload).
Đối soát bằng API
Hiện chưa có tham số since_id; đối soát theo cách sau (cron mỗi 15-30 phút hoặc cuối ngày):
- Với mỗi VA đang dùng, gọi trang 1 với
limit=100, đọc tiếp khihas_nextlàtrue. - Với mỗi bản ghi, tra
transaction_codetrong bảng giao dịch của anh chị. Có rồi thì bỏ qua, chưa có thì ghi thêm và xử lý đơn như khi nhận webhook. - Dừng khi gặp
transaction_codeđã có vàtransaction_datecũ hơn mốc đối soát lần trước (danh sách sắp xếp mới trước).
Chi tiết và code mẫu ở Đối soát giao dịch.
PHP: đọc hết các trang
<?php
function monaGet(string $url): array {
$ctx = stream_context_create(['http' => ['header' => 'Authorization: Bearer ' . getenv('MONA_TOKEN') . "\r\n", 'ignore_errors' => true]]);
return json_decode(file_get_contents($url, false, $ctx), true) ?? [];
}
$va = 'MONA0000010234'; $page = 1;
do {
$res = monaGet("https://api.monapay.vn/api/v1/acb/virtual-account/transactions?virtual_account_number=$va&page=$page&limit=100");
if (empty($res['success'])) throw new RuntimeException($res['message'] ?? 'Lỗi truy vấn');
foreach ($res['data']['data'] as $tx) {
if ($tx['debit_or_credit'] !== 'credit') continue;
// INSERT ... ON DUPLICATE KEY (UNIQUE transaction_code) → chỉ ghi bản chưa có
ghiNhanGiaoDich($tx['transaction_code'], $tx['amount'], $tx['transaction_content'], $tx['transaction_date']);
}
$page++;
} while (!empty($res['data']['has_next']));
Node
async function* monaTransactions(va) {
for (let page = 1; ; page++) {
const r = await fetch(`https://api.monapay.vn/api/v1/acb/virtual-account/transactions?virtual_account_number=${va}&page=${page}&limit=100`, {
headers: { Authorization: `Bearer ${process.env.MONA_TOKEN}` },
});
const j = await r.json();
if (!j.success) throw new Error(j.message);
yield* j.data.data;
if (!j.data.has_next) break;
}
}
for await (const tx of monaTransactions('MONA0000010234')) {
if (tx.debit_or_credit !== 'credit') continue;
await db.upsertByTransactionCode(tx.transaction_code, tx); // UNIQUE(transaction_code)
}
POST /api/v1/acb/virtual-account/transactions/{transaction_id}/retry
Gửi lại thông báo cho một giao dịch cụ thể (server anh chị lúc đó bị lỗi, hoặc cấu hình webhook sai rồi sửa lại). Cần Bearer + X-Client-Secret. Gửi lại tự động theo lịch đang triển khai, hiện là thao tác chủ động này hoặc nút “Gửi lại” trong dashboard.
| Trường | Kiểu | Bắt buộc | Ghi chú |
|---|---|---|---|
target_type |
WEBHOOK / TELEGRAM |
có | Kênh cần gửi lại |
target_id |
uuid | không | ID cấu hình webhook hoặc Telegram cụ thể. Bỏ trống = gửi lại theo mọi cấu hình đang bật khớp giao dịch |
curl -X POST https://api.monapay.vn/api/v1/acb/virtual-account/transactions/0190d0e1-.../retry \
-H "Authorization: Bearer $MONA_TOKEN" -H "X-Client-Secret: $MONA_SECRET" \
-H 'Content-Type: application/json' -d '{"target_type":"WEBHOOK"}'
Payload gửi lại y hệt lần đầu, cùng transaction_code, nên server anh chị phải chống trùng (xem Gửi lại và xử lý lỗi).
Lỗi thường gặp
| HTTP | Nguyên nhân | Cách xử lý |
|---|---|---|
| 400 | Số VA không tồn tại hoặc không thuộc tài khoản | Lấy đúng số VA từ GET /api/v1/acb/{bank_account_id}/virtual-account/retrieve |
| 401 | Token hết hạn | Login lại |
| 422 | limit > 100 hoặc thiếu virtual_account_number |
Sửa tham số |
| 404 (retry) | transaction_id không tồn tại |
Lấy id từ danh sách giao dịch |