MONA Pay sandbox: test transactions and checkout without moving money

Video guide

Sandbox MONA Pay: thử giao dịch và checkout không tốn tiền · Xem trên YouTube
Xem transcript video (9 phần)

Thử trọn luồng an toàn

Đưa code thanh toán lên thật rồi mới thử ca thiếu tiền hoặc webhook gửi lại là quá rủi ro. Sandbox cho anh chị chạy trọn luồng mà không chuyển tiền thật. Trong video này, mình tạo giao dịch giả, nhận thông báo, thử checkout đủ tiền, thiếu tiền và gửi trùng mã. Chưa nối ngân hàng, anh chị vẫn làm được với tài khoản ảo bắt đầu bằng SBX.

Tạo giao dịch sandbox

Endpoint là POST /api/v1/sandbox/transactions, cần Bearer và X-Client-Secret. Body tối thiểu có amount, số nguyên lớn hơn không, tối đa một tỷ đồng, cùng description dài từ một đến hai trăm năm mươi lăm ký tự. Nếu không truyền tài khoản, hệ thống tự tạo hoặc dùng lại VA sandbox SBX. Response còn trả mã giao dịch, số VA, số tài khoản và số tiền; is_sandbox bằng true.

Chọn VA và mã thử

Muốn thử trên một VA đã có, truyền virtual_account_number. Muốn chỉ định tài khoản thật đã nối, dùng account_number; chỉ cần một trong hai. transaction_code là tùy chọn, dài tối đa một trăm ký tự. Tự đặt mã như SANDBOX-DH10234-01 rất hữu ích để kiểm chống trùng. Nếu bỏ trống, hệ thống sinh mã bắt đầu bằng SANDBOX.

Đi qua kênh thật

Giao dịch sandbox đi qua cùng bộ xử lý như giao dịch thật, nên webhook, Telegram, email và logic khớp checkout đều nhận được. Trong bảng nội bộ, vẫn dùng transaction_code làm khóa chống trùng và dùng is_sandbox để phân biệt môi trường thử. Không viết một nhánh xử lý hoàn toàn khác, vì mục tiêu của sandbox là kiểm đúng code mà anh chị sẽ chạy khi có tiền thật.

Đưa localhost ra HTTPS

Nếu endpoint webhook đang ở máy cá nhân, MONA Pay không gọi trực tiếp được localhost. Tạo URL HTTPS công khai bằng lệnh cloudflared tunnel --url http://localhost:4400, rồi dán URL được cấp vào webhook_url. Nếu chưa có URL công khai, trong lúc thử checkout anh chị có thể gọi GET /api/v1/checkouts/{checkout_id} mỗi vài giây để đọc trạng thái.

Tạo checkout sandbox

Để thử trang thanh toán, thêm sandbox bằng true vào body POST /api/v1/checkouts, đồng thời gửi Idempotency-Key. Response trả checkout_url, dữ liệu QR và VA SBX; trang thanh toán có dải “PHIÊN THỬ, không chuyển tiền thật”. Lấy data.bank.account_number hoặc VA trong response rồi tạo giao dịch sandbox vào đúng số đó. Khi tổng tiền đủ, phiên thành paid và phát CHECKOUT_PAID.

Chạy ba ca kiểm thử

Ca đầu là đủ tiền: checkout hai trăm năm mươi nghìn, giao dịch sandbox đúng hai trăm năm mươi nghìn, chờ CHECKOUT_PAID và bảo đảm đơn chỉ xử lý một lần. Ca hai là thiếu tiền: bắn hai trăm nghìn, status phải giữ pending và có partial_amount. Ca ba gửi lại cùng transaction_code; tổng tiền không được cộng thêm và trạng thái không được xử lý lần nữa.

Biết giới hạn sandbox

Sandbox không gửi hay nhận tiền thật và giao dịch thử không tính vào hạn mức gói. VA SBX, QR và checkout thử không đưa cho khách thanh toán. Kết quả sandbox kiểm luồng dịch vụ cùng code của anh chị, nhưng không thay lần thử cuối bằng một khoản chuyển thật sau khi nối ngân hàng. Nếu trùng mã mà số tiền cộng dồn, hãy kiểm khóa UNIQUE và cách xử lý transaction_code.

Mở docs và thử ngay

Lệnh tạo giao dịch, checkout thử và ba kịch bản kiểm tra nằm tại monapay.vn/docs/api/sandbox. Anh chị đăng ký tại my.monapay.vn, lấy khóa API rồi chạy đầy đủ cả ba ca sandbox trước khi nối ngân hàng thật. Nếu webhook, email hoặc trạng thái checkout chưa đổi như mong đợi, 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 chiếu luồng.

The sandbox exercises the complete payment-confirmation flow without a real bank transfer. Call POST /api/v1/sandbox/transactions; MONA Pay records a fake incoming transaction and sends it through webhooks, Telegram, email and the hosted-checkout matcher just like a real one.

You can test before linking a bank. MONA Pay creates a dedicated sandbox VA for your account, with a number beginning SBX…. If you already have a real VA, you can pass that number instead; the transaction still has is_sandbox: true and never moves bank funds.

POST /api/v1/sandbox/transactions

The request needs a Bearer token and X-Client-Secret:

curl -X POST https://api.monapay.vn/api/v1/sandbox/transactions \
  -H "Authorization: Bearer $MONA_TOKEN" \
  -H "X-Client-Secret: $MONA_SECRET" \
  -H 'Content-Type: application/json' \
  -d '{"amount":250000,"description":"Payment for ORDER10234"}'

When no account number is passed, MONA Pay creates or reuses your SBX… sandbox VA. To test against a linked real VA, add virtual_account_number:

{
  "virtual_account_number": "LOCHOA000123456",
  "amount": 250000,
  "description": "Payment for ORDER10234",
  "transaction_code": "SANDBOX-ORDER10234-01"
}
Field Type Required Notes
virtual_account_number string, up to 50 characters no A real VA or an SBX… VA; omit it to let MONA Pay provide a sandbox VA
account_number string, up to 50 characters no A linked real account; only one account reference is needed when you want to select a receiver
amount integer yes Fake amount, greater than 0 and no more than 1,000,000,000 VND
description string, 1–255 characters yes Fake transfer note; include an order code to test matching
transaction_code string, 1–100 characters no Set one to test deduplication; otherwise MONA Pay generates a SANDBOX-… code

Response 200:

{
  "success": true,
  "message": "Sandbox transaction accepted",
  "data": {
    "transaction_code": "SANDBOX-ORDER10234-01",
    "virtual_account_number": "SBX000123456",
    "account_number": "SBX000123456",
    "amount": 250000,
    "is_sandbox": true
  }
}

The event goes through the same processing and notification channels as a real transfer. Use transaction_code as the deduplication key and is_sandbox to identify test data during reconciliation.

Running webhooks from localhost

Webhooks need a public HTTPS URL; MONA Pay cannot call localhost directly.

cloudflared tunnel --url http://localhost:4400

Paste the HTTPS URL issued by the tunnel into webhook_url; ngrok works too. If no public URL is available yet, poll GET /api/v1/checkouts/{checkout_id} every few seconds while testing. The IP addresses page applies when the system goes to production.

Test hosted checkout

Add "sandbox": true when creating a checkout. The test session uses an SBX… VA and returns a checkout_url, displayable QR data and sandbox: true; the hosted page shows a TEST SESSION — do not transfer real money banner.

curl -X POST https://api.monapay.vn/api/v1/checkouts \
  -H "Authorization: Bearer $MONA_TOKEN" \
  -H "X-Client-Secret: $MONA_SECRET" \
  -H "Idempotency-Key: sandbox-ORDER10234" \
  -H 'Content-Type: application/json' \
  -d '{"amount":250000,"order_code":"ORDER10234","return_url":"https://shop.example/payment/return","sandbox":true}'

Take data.bank.account_number, or the VA number in the checkout response, and pass it as virtual_account_number to /sandbox/transactions. Once the sandbox total reaches amount, the checkout becomes paid and emits CHECKOUT_PAID. See Hosted checkout for the remaining fields.

Three tests to run before going live

  1. Exact amount: create a 250,000 VND checkout and send one 250,000 VND sandbox transaction. Wait for CHECKOUT_PAID, verify the signature, confirm paid, and ensure fulfilment runs once.
  2. Underpayment: create a 250,000 VND checkout and send 200,000 VND. It must stay pending with partial_amount; do not fulfil it.
  3. Repeat the same transaction code: send the exact same transaction_code again. MONA Pay returns the same 200 response as the first request and does not add the amount again, so paid_amount stays unchanged. To automate this check, call GET /api/v1/checkouts/{checkout_id} before and after, then compare paid_amount and partial_amount.

Sandbox limits

  • No real money is sent or received; never scan a sandbox QR to make a transfer.
  • Sandbox transactions do not count against the plan transaction quota.
  • SBX… VAs, QR codes and sandbox checkouts are test-only and must not be given to real payers.
  • The sandbox tests MONA Pay and your integration; it does not replace a final small real transfer after the bank is linked.

See Webhook payload format, Webhook security and Transaction reconciliation.