Bắt đầu nhanh với MONA Pay trong 5 phút

Cập nhật 04/09/2026Bản Markdownllms.txtopenapi.json

Video hướng dẫn

Bắt đầu nhanh với MONA Pay trong 5 phút: đăng ký, nối ACB, nhận tiền đầu tiên · Xem trên YouTube
Xem transcript video (8 phần)

Chuẩn bị trước khi làm

Bạn muốn tiền vừa vào tài khoản ACB là website biết ngay, nhưng đang mắc giữa tài khoản, khóa API, hai lần OTP và webhook. Video này mình đi trọn sáu việc trong khoảng năm phút: chuẩn bị, đăng ký, lấy quyền gọi API, nối ngân hàng, khai báo webhook rồi chuyển một khoản nhỏ để kiểm tra. Bạn cần tài khoản ACB, điện thoại nhận OTP và một URL HTTPS công khai. Chưa có máy chủ vẫn có thể dùng thông báo Telegram.

Đăng ký và lấy token

Vào my.monapay.vn/auth, chọn tab Đăng ký, rồi điền tên đăng nhập, mật khẩu, tên và email. Tài khoản tạo xong dùng ngay, không có bước chờ duyệt. Nếu làm qua API, gửi POST tới /api/v1/client/register-client với ba trường username, password, name. Sau đó đăng nhập tại /api/v1/client/login. Kết quả có access_token và expires_in; mọi lệnh gọi tiếp theo gửi Authorization: Bearer kèm token này.

Tạo khóa API

Mở mục API Keys và tạo một khóa tên may-chu-production. Hệ thống trả client_secret, tức mã bí mật, đúng một lần nên phải lưu ngay vào biến môi trường. Nếu mất, tạo khóa mới rồi thu hồi khóa cũ. Với token lấy từ client/login, các lệnh POST, PUT, PATCH và DELETE còn phải gửi X-Client-Secret. Token đổi qua /api/v1/oauth/token không bắt buộc header này, nhưng tài liệu vẫn khuyến nghị luôn gửi.

Nối ACB bằng hai OTP

Tiếp theo vào Ngân hàng & VA, bấm Thêm tài khoản. Nhập số tài khoản ACB, số điện thoại đã đăng ký với ACB, loại khách hàng cá nhân hoặc doanh nghiệp, rồi tự đặt đầu số VA bằng chữ in hoa hoặc số, ví dụ HOA hay SHOP. Nhập OTP thứ nhất để xác thực và tạo tài khoản ảo đầu tiên. Đăng ký nhận thông báo, nhập OTP thứ hai. Phải hoàn tất đủ hai lượt thì giao dịch mới báo sang hệ thống.

Khai báo webhook

ACB sẽ ghép mã đối tác phía trước đầu số bạn chọn. Ví dụ đầu số HOA có thể thành VA LOCHOA000123456; hãy dùng nguyên số hệ thống trả về, không tự ghép. Bây giờ vào Webhooks, bấm Thêm webhook. Điền URL HTTPS, chọn HMAC_SHA256, đặt secret_key, tức mã bí mật dùng ký webhook, và để định dạng application/json. Bỏ trống virtual_account_id để nhận mọi tài khoản, hoặc chọn một VA để lọc riêng.

Kiểm chữ ký và localhost

Endpoint phía bạn làm ba việc theo đúng thứ tự: đọc raw body, kiểm X-Mona-Timestamp và X-Mona-Signature, trả HTTP 200 ngay, rồi mới xử lý đơn. Chữ ký là HMAC-SHA256 của chuỗi timestamp, dấu chấm và raw body. Timestamp lệch quá năm phút thì từ chối. Nếu đang thử trên máy cá nhân, localhost không nhận được cuộc gọi từ MONA Pay; hãy dùng URL HTTPS công khai do tunnel cấp rồi dán vào webhook_url.

Gửi thử và chuyển tiền

Trong mục Webhooks, bấm Gửi thử. Mở Lịch sử gửi để xem mã HTTP và thời gian phản hồi. Sau đó chuyển một khoản nhỏ, ví dụ mười nghìn đồng, vào VA vừa tạo. Trong vài giây, giao dịch sẽ hiện trên dashboard và webhook tới máy chủ. Nếu báo TIMEOUT, server chưa trả lời trong mười giây. Nếu chữ ký sai, đừng parse JSON rồi ký lại. Nếu tiền chưa hiện, kiểm tra đã nhập OTP thứ hai hay chưa.

Việc nên làm tiếp

Vậy là bạn đã đi từ tài khoản mới tới giao dịch thật: có token, khóa API, VA, thông báo ngân hàng và webhook đã kiểm chữ ký. Bước tiếp theo nên đọc Định dạng payload để hiểu từng trường, dùng transaction_code chống trùng, rồi xem Gửi lại và xử lý lỗi. Toàn bộ hướng dẫn nằm tại monapay.vn/docs/bat-dau-nhanh. Đăng ký tại my.monapay.vn. Cần hỗ trợ, bạn gọi tổng đài một chín không không, sáu ba sáu, sáu bốn tám.

Để nhận thông báo tiền vào tài khoản ACB theo thời gian thực, bạn cần 6 bước: đăng ký tài khoản (dùng ngay, không cần duyệt), đăng nhập lấy token, tạo API key, nối tài khoản ACB bằng OTP, khai báo URL webhook, rồi chuyển một khoản nhỏ để kiểm tra. Nếu đã có tài khoản ACB và một máy chủ nhận webhook, phần thao tác mất khoảng 5 phút.

Dashboard MONA Pay tổng quan tài chính với API key, kích hoạt tài khoản và tạo tài khoản ảo
Màn hình Tổng quan gom các việc cần hoàn tất trước khi nhận giao dịch đầu tiên, ảnh chụp từ dashboard my.monapay.vn.

Chuẩn bị

  • Tài khoản ngân hàng ACB đứng tên bạn hoặc doanh nghiệp, kèm số điện thoại đã đăng ký với ACB (để nhận OTP).
  • Một URL HTTPS trên máy chủ của bạn để nhận webhook, ví dụ https://ten-mien-cua-anh-chi.vn/webhook/monapay. Chưa có máy chủ thì vẫn dùng được thông báo Telegram, xem trang Telegram.
  • Công cụ gọi API: cURL, Postman, hoặc để AI agent gọi giùm theo prompt có sẵn.
Dashboard MONA Pay hướng dẫn tích hợp cho WooCommerce, Shopify, webhook và AI agent
Mục Hướng dẫn tích hợp giúp chọn đúng luồng cho nền tảng, website riêng hoặc AI agent, ảnh chụp từ dashboard my.monapay.vn.

Dùng WooCommerce: cài plugin

Tải plugin MONA Pay for WooCommerce mới nhất, cài file zip tại Plugins → Thêm mới → Tải plugin lên, rồi vào WooCommerce → Cài đặt → Thanh toán → MONA Pay VietQR để nhập Client ID và Client Secret.

Chưa nối ngân hàng vẫn thử được: bật Chế độ thử (sandbox) trong cài đặt plugin. Sau khi lưu, tạo một đơn và chọn MONA Pay tại checkout để chạy hết luồng thử.

Ảnh cài đặt plugin WooCommerce MONA Pay với Client ID, Client Secret và chế độ thử sandbox
Màn hình nhập key và bật sandbox; chụp trên cửa hàng demo WooCommerce 11.1, chế độ thử.
Ảnh plugin WooCommerce MONA Pay được chọn tại trang checkout của đơn hàng 900.000 đồng
Khách chọn MONA Pay tại checkout; chụp trên cửa hàng demo WooCommerce 11.1, chế độ thử.

Dùng OpenCart: cài module

Tải module MONA Pay cho OpenCart, vào Extensions → Installer để upload, rồi mở Extensions → Extensions → Payments → MONA Pay. Nhập Client ID và Client Secret lấy từ my.monapay.vn → API Keys, bật Sandbox để chạy đơn thử. Khi checkout, trang thanh toán, trang success và đơn trong admin đều đúng thì tắt Sandbox trước khi bán thật. Xem luồng 5 bước có ảnh chụp trên OpenCart 4.1.

Dùng PrestaShop: cài module

Tải module MONA Pay cho PrestaShop, vào Modules → Module Manager → Upload a module, rồi bấm Configure để nhập Client ID, Client Secret và các secret xác thực. Bật Chế độ sandbox để chạy đơn thử, sau đó tắt trước khi bán thật. Module chỉ hiện khi giỏ hàng dùng tiền tệ VND. Xem luồng 4 bước có ảnh chụp trên PrestaShop 8.2.

Bước 1. Đăng ký tài khoản

Vào https://my.monapay.vn/auth, chọn tab Đăng ký, điền tên đăng nhập, mật khẩu, tên và email. Bạn cũng gọi được API:

Terminal
curl -X POST https://api.monapay.vn/api/v1/client/register-client \
  -H 'Content-Type: application/json' \
  -d '{"username":"shop-cua-toi","password":"mat-khau-manh","name":"Shop của tôi"}'

Tài khoản tạo xong dùng được ngay: đăng nhập liền ở bước 2, không cần ai duyệt. MONA Pay miễn phí 500 giao dịch mỗi tháng, gói trả phí tính theo số giao dịch (xem bảng giá).

Bước 2. Đăng nhập lấy token

Nếu bạn giao cho AI agent hoặc máy chủ làm, bỏ qua bước đăng nhập bằng mật khẩu: tạo API key ở dashboard rồi đổi client_id + client_secret ra token qua POST /api/v1/oauth/token, xem Xác thực.

Terminal
curl -X POST https://api.monapay.vn/api/v1/client/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"shop-cua-toi","password":"mat-khau-manh"}'

Kết quả trả về theo khung chung của mọi API:

JSON
{
  "success": true,
  "message": "Đăng nhập thành công",
  "data": { "access_token": "eyJhbGciOi...", "expires_in": 86400 }
}

Từ đây mọi lệnh gọi API đều gửi kèm Authorization: Bearer <access_token>. Chi tiết ở trang Xác thực.

Bước 3. Tạo API key

Với Bearer token đăng nhập bằng mật khẩu ở bước 2, các request POST, PUT, PATCH và DELETE bắt buộc thêm X-Client-Secret. Token từ oauth/token không bắt buộc gửi lại header này, nhưng SDK, MCP chính thức vẫn gửi và MONA Pay khuyến nghị luôn gửi. Tạo khoá trong dashboard mục API Keys, hoặc:

Terminal
curl -X POST https://api.monapay.vn/api/v1/client-keys/generate \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"may-chu-production"}'

client_secret chỉ hiện đúng 1 lần trong response. Lưu vào biến môi trường ngay, mất thì tạo khoá mới và thu hồi khoá cũ. Xem API keys.

Bước 4. Nối tài khoản ACB (có OTP)

Làm trong dashboard, mục Ngân hàng & VA, nút Thêm tài khoản:

  1. Nhập số tài khoản ACB, số điện thoại đăng ký với ACB, loại khách hàng (cá nhân hoặc doanh nghiệp) và tự đặt đầu số VA ngắn bằng chữ in hoa/số, ví dụ HOA hoặc SHOP. Không cần ra quầy hay đăng ký đầu số trước; nếu MONA Pay báo lỗi đầu số thì đổi đầu số khác.
  2. ACB gửi OTP về điện thoại. Nhập OTP để xác thực và tạo tài khoản ảo (VA) đầu tiên.
  3. Đăng ký nhận thông báo giao dịch. ACB gửi OTP lần 2, nhập tiếp.
  4. Xong. Từ lúc này tiền vào VA hoặc tài khoản là MONA Pay nhận được thông báo.

Nếu muốn làm bằng API thay vì dashboard, xem Tài khoản ảo (VA), luồng cũng đúng 4 lệnh gọi này.

ACB sẽ ghép mã đối tác phía trước đầu số bạn chọn. Chẳng hạn đầu số HOA có thể cho số VA hoàn chỉnh LOCHOA000123456; hãy dùng nguyên số MONA Pay trả về, không tự ghép.

Bước 5. Khai báo URL webhook

Vào dashboard mục Webhooks, bấm Thêm webhook, điền URL, chọn kiểu xác thực HMAC_SHA256 và đặt secret. Hoặc gọi API:

Terminal
curl -X POST https://api.monapay.vn/api/v1/client-webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Client-Secret: $CLIENT_SECRET" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Web bán hàng",
    "webhook_url": "https://ten-mien-cua-anh-chi.vn/webhook/monapay",
    "auth_type": "HMAC_SHA256",
    "secret_key": "secret_hmac_cua_anh_chi",
    "payload_format": "application/json"
  }'

Không truyền virtual_account_id thì webhook nhận mọi giao dịch của mọi tài khoản. Truyền id của một VA thì chỉ nhận giao dịch của VA đó.

Chạy webhook trên localhost

Webhook cần một URL HTTPS công khai, MONA Pay không thể gọi trực tiếp vào localhost.

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

Dán URL HTTPS do tunnel cấp vào webhook_url; bạn cũng có thể dùng ngrok. Nếu chưa có URL công khai, hãy hỏi lại GET /api/v1/checkouts/{checkout_id} mỗi vài giây trong lúc thử. Trang Địa chỉ IP chỉ áp dụng khi đưa hệ thống lên production.

Phía máy chủ của bạn, endpoint chỉ cần làm 3 việc: kiểm chữ ký, trả HTTP 200 ngay, rồi xử lý đơn sau. Code mẫu dán vào dùng được:

PHP
<?php
// webhook-monapay.php: endpoint nhận thông báo tiền vào từ MONA Pay
$secret = getenv('MONA_WEBHOOK_SECRET'); // secret HMAC đặt khi bật HMAC

$raw       = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_MONA_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_MONA_SIGNATURE'] ?? ''; // dạng "sha256=<hex>"

// 1. Chặn replay: timestamp lệch quá 5 phút thì từ chối
if (abs(time() - (int) $timestamp) > 300) {
    http_response_code(400);
    exit('timestamp qua han');
}

// 2. Verify chữ ký: HMAC-SHA256(secret, "<timestamp>.<raw_body>")
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $raw, $secret);
if (!hash_equals($expected, $signature)) { // hash_equals chống timing attack
    http_response_code(401);
    exit('sai chu ky');
}

// 3. Trả 200 ngay, việc nặng đẩy sang xử lý sau (queue/cron)
http_response_code(200);
echo 'OK';
if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();

$data = json_decode($raw, true);
// $data['amount'], $data['description'], $data['transaction_code'], ...
// TODO: ghi nhận giao dịch + xử lý đơn hàng của bạn tại đây
JavaScript
// webhook-monapay.js: nhận webhook MONA Pay bằng Express
const express = require('express');
const crypto  = require('crypto');

const app    = express();
const SECRET = process.env.MONA_WEBHOOK_SECRET; // secret HMAC đặt khi bật HMAC

// Phải đọc raw body thì chữ ký mới khớp (đừng dùng express.json() ở route này)
app.post('/webhook/monapay', express.raw({ type: 'application/json' }), (req, res) => {
  const timestamp = req.header('X-Mona-Timestamp') || '';
  const signature = req.header('X-Mona-Signature') || ''; // "sha256=<hex>"
  const rawBody   = req.body.toString('utf8');

  // 1. Chặn replay: timestamp lệch quá 5 phút thì từ chối
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
    return res.status(400).send('timestamp qua han');
  }

  // 2. Verify chữ ký: HMAC-SHA256(secret, "<timestamp>.<raw_body>")
  const expected = 'sha256=' + crypto
    .createHmac('sha256', SECRET)
    .update(timestamp + '.' + rawBody)
    .digest('hex');
  const hopLe =
    signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  if (!hopLe) return res.status(401).send('sai chu ky');

  // 3. Trả 200 ngay, xử lý đơn hàng async sau đó
  res.status(200).send('OK');

  const data = JSON.parse(rawBody);
  // data.amount, data.description, data.transaction_code, ...
  // TODO: ghi nhận giao dịch + xử lý đơn hàng của bạn tại đây
});

app.listen(3000, () => console.log('Webhook MONA Pay chạy ở cổng 3000'));

Bước 6. Gửi thử rồi chuyển tiền thật

Trước hết bấm Gửi thử trong dashboard (mục Webhooks) hoặc gọi POST /api/v1/client-webhooks/test. MONA Pay bắn một gói mẫu tới URL của bạn, kết quả hiện ngay trong Lịch sử gửi kèm mã HTTP và thời gian phản hồi.

Muốn kiểm tra tại chỗ không cần chờ MONA Pay, bạn giả lập chính xác gói MONA Pay gửi bằng cURL:

Terminal
# Giả lập MONA Pay bắn webhook vào endpoint của bạn để test tại chỗ
SECRET='secret_hmac_cua_anh_chi'   # secret HMAC đặt khi bật HMAC trong dashboard
URL='https://ten-mien-cua-anh-chi.vn/webhook/monapay'
TS=$(date +%s)
BODY='{"amount":2500000,"description":"noi dung ck","transfer_date":"10:30:00 28/08/2026","transaction_code":"FT26240001234","account_number":"1234567890","bank_name":"ACB","type":"income"}'

# Chữ ký = HMAC-SHA256(secret, "<timestamp>.<raw_body>"), dùng printf để không dính ký tự xuống dòng
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

curl -X POST "$URL" \
  -H 'Content-Type: application/json' \
  -H "X-Mona-Timestamp: $TS" \
  -H "X-Mona-Signature: sha256=$SIG" \
  --data "$BODY"

Cuối cùng chuyển một khoản nhỏ vào số VA vừa tạo, ví dụ 10.000đ, từ app ngân hàng bất kỳ. Trong vài giây bạn sẽ thấy giao dịch trong dashboard và webhook về máy chủ.

Sau khi chạy được

  • Đọc Định dạng payload để biết từng trường dữ liệu và dùng transaction_code làm khoá chống trùng.
  • Đọc Gửi lại và xử lý lỗi để hiểu log, nhãn lỗi và cách gửi lại.
  • Mở tường lửa cho IP 103.168.55.14 nếu máy chủ của bạn chặn kết nối lạ, xem Địa chỉ IP.
  • Muốn tạo mã QR có sẵn số tiền cho từng đơn: QR thanh toán.

Lỗi thường gặp

Đăng nhập báo sai tài khoản dù mật khẩu đúng. Kiểm tra lại username (phân biệt hoa thường) và mật khẩu. Tài khoản mới đăng ký là đăng nhập được ngay, không có bước chờ kích hoạt; vẫn kẹt thì gọi 1900 636 648.

Gọi POST bị từ chối dù đã có Bearer token. Nếu token lấy từ client/login, request đang thiếu X-Client-Secret; mọi POST, PUT, PATCH và DELETE bắt buộc gửi header này. Token từ oauth/token không bị bắt buộc, nhưng MONA Pay vẫn khuyến nghị gửi kèm.

Gửi thử báo TIMEOUT. Máy chủ của bạn không trả lời trong 10 giây. Trả HTTP 200 trước, xử lý đơn sau như code mẫu ở trên.

Chữ ký không khớp. Thường do framework đã parse JSON rồi mới ký lại. Phải ký trên raw body đúng từng byte MONA Pay gửi, xem Bảo mật webhook.

Chuyển tiền rồi mà không thấy giao dịch. Kiểm tra bước 4 đã hoàn tất cả 2 lần OTP chưa. Thiếu OTP lần 2 (đăng ký nhận thông báo) thì ACB không báo giao dịch sang MONA Pay.