WordPress · chuyển khoản ACB

Plugin tự động xác nhận thanh toán chuyển khoản cho WordPress

Plugin tự động xác nhận thanh toán chuyển khoản cho WordPress nhận báo có qua webhook rồi khớp đúng người trả. Web có thể mở khoá học, xác nhận cọc hoặc gia hạn hội viên; bạn được thử webhook trước khi nối ngân hàng, trả 0% phí giao dịch và dùng miễn phí 500 giao dịch mỗi tháng.

Đơn trên WordPress tự xác nhận khi tiền vào, ảnh chụp cửa hàng thử (sandbox)
Đơn trên WordPress tự xác nhận khi tiền vào, ảnh chụp cửa hàng thử (sandbox)
  • 500 giao dịchmiễn phí mỗi tháng, đủ mọi tính năng
  • Không thu %trên số tiền khách chuyển
  • Tiền về thẳngtài khoản ngân hàng đứng tên bạn
  • Từ 2022chạy tiền thật cho khách MONA

Đủ kiểu web, chung một chỗ kẹt

Plugin thanh toán WordPress dùng cho website nào?

Trong 14.000+ dự án đội MONA làm từ 2016, WordPress chiếm phần lớn. Web nào có thu tiền là có người ngồi dò sao kê, bất kể bán gì.

Web bán khoá học, tài liệu, thành viên trả phí

Học viên chuyển khoản xong nhắn "em chuyển rồi", admin mở app ngân hàng dò, rồi vào WordPress mở quyền bằng tay. Khuya nhắn thì sáng mới có khoá. Học viên đóng tiền lúc đang hứng, chờ 8 tiếng là nguội.

Web đặt cọc: tour, phòng, sự kiện, dịch vụ

Cọc chưa xác nhận thì chỗ chưa giữ. Nhân viên phải nhìn app ngân hàng và bảng đặt chỗ cùng lúc, hai người cùng cọc một suất là rối. Cuối ngày kế toán ngồi khớp lại từng dòng sao kê với từng đơn cọc.

Form đăng ký thu phí, gia hạn dịch vụ

Khách điền form xong, chuyển tiền, rồi email chứng từ. Bộ phận thu tiền tìm email, tìm sao kê, đối chiếu tên người chuyển với tên trong form. Tên viết không dấu, chuyển từ tài khoản người thân, là mất dấu.

Nhiều khách chuyển cùng số tiền

Học phí cùng giá, cọc cùng giá. Ba giao dịch 1.990.000 đ trong 10 phút, nội dung thì "ck", "chuyen tien", "hoc phi". Khớp nhầm là mở nhầm khoá cho người chưa đóng và khoá nhầm người đã đóng.

Cách MONA Pay làm

Các bước tích hợp cổng thanh toán vào website WordPress

Chính website khanhhung.academy và mona.host của đội MONA đã thu học phí, thu tiền hosting bằng đúng luồng này nhiều năm trước khi mở public.

Trang thanh toán hiện mã QR hoặc số tài khoản ảo riêng

Web sinh mã VietQR đã điền sẵn số tiền và nội dung (mã học viên, mã đơn cọc, mã hội viên). Muốn khách khỏi gõ gì cả thì cấp mỗi khách 1 số tài khoản ảo riêng do ACB cấp từ đầu số của bạn. Cả hai cách đều làm bằng API hoặc trong dashboard.

Khách chuyển, tiền vào thẳng tài khoản ACB

Không ví trung gian, không giữ tiền, không chờ đối soát cuối ngày. ACB thấy tiền vào là báo cho MONA Pay biết giao dịch đó ngay.

MONA Pay gửi webhook có chữ ký về web

Gói tin JSON 7 trường kèm chữ ký HMAC-SHA256 và mốc thời gian. Web kiểm chữ ký, từ chối gói lệch giờ quá 5 phút, kiểm trùng bằng mã giao dịch. Web trả 200 trong 10 giây là MONA Pay ghi nhận đã giao.

Web tự làm phần việc của mình

Mở khoá học, đổi trạng thái cọc, gia hạn hội viên, gửi email, bật quyền xem nội dung. Cùng một gói tin, mỗi loại web bắt lấy làm việc khác nhau, nên đoạn code mẫu bên dưới phát ra 1 sự kiện WordPress để bạn nối vào bất cứ thứ gì.

Làm ngay hôm nay

QR code chuyển khoản tự xác nhận qua webhook WordPress

Đoạn code bên dưới tạo địa chỉ https://web-cua-anh-chi.vn/wp-json/monapay/v1/webhook, kiểm chữ ký HMAC, chặn gói lệch giờ quá 5 phút, chặn xử lý trùng, rồi phát sự kiện monapay_tien_vao. Cuối file có ví dụ bắt sự kiện để mở khoá học cho học viên; đặt cọc hay hội viên thì đổi vài dòng trong hàm đó. Web làm tại MONA thì đội MONA nối sẵn phần này lúc bàn giao, khỏi tự dán.

PHP
<?php
// mona-pay-webhook.php: bỏ vào wp-content/mu-plugins/
// Nhận webhook MONA Pay, kiểm chữ ký, rồi phát sự kiện 'monapay_tien_vao' cho phần còn lại của web dùng
add_action('rest_api_init', function () {
    register_rest_route('monapay/v1', '/webhook', [
        'methods'             => 'POST',
        'callback'            => 'monapay_nhan_webhook',
        'permission_callback' => '__return_true', // tự xác thực bằng HMAC bên dưới
    ]);
});

function monapay_nhan_webhook(WP_REST_Request $req) {
    $secret    = defined('MONA_WEBHOOK_SECRET') ? MONA_WEBHOOK_SECRET : ''; // khai báo trong wp-config.php
    $raw       = $req->get_body();
    $timestamp = $req->get_header('X-Mona-Timestamp') ?: '';
    $signature = $req->get_header('X-Mona-Signature') ?: '';

    // 1. Chặn replay: lệch quá 5 phút thì từ chối
    if (abs(time() - (int) $timestamp) > 300) {
        return new WP_REST_Response(['success' => false, 'message' => 'timestamp qua han'], 400);
    }
    // 2. Kiểm chữ ký HMAC-SHA256(secret, "<timestamp>.<raw_body>")
    $expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $raw, $secret);
    if (!hash_equals($expected, $signature)) {
        return new WP_REST_Response(['success' => false, 'message' => 'sai chu ky'], 401);
    }

    $data = json_decode($raw, true);

    // 3. Chống trùng bằng transaction_code (không đổi qua mọi lần gửi lại)
    $key = 'monapay_tx_' . sanitize_key($data['transaction_code']);
    if (get_option($key)) {
        return new WP_REST_Response(['success' => true, 'message' => 'da xu ly'], 200);
    }
    add_option($key, wp_json_encode($data), '', 'no');

    // 4. Phát sự kiện: phần nào của web cần biết "có tiền vào" thì bắt sự kiện này
    do_action('monapay_tien_vao', $data);

    return new WP_REST_Response(['success' => true], 200);
}

// Ví dụ: web bán khoá học, nội dung chuyển khoản "HV88" = học viên có ID 88 → mở khoá
add_action('monapay_tien_vao', function ($data) {
    if (preg_match('/HV\s?(\d+)/i', (string) $data['description'], $m) && (int) $data['amount'] >= 1990000) {
        update_user_meta((int) $m[1], 'da_thanh_toan', current_time('mysql'));
        wp_mail(get_userdata((int) $m[1])->user_email, 'Đã nhận học phí', 'Khoá học của bạn đã mở, vào học ngay.');
    }
});
Terminal
# Giả lập MONA Pay gọi vào web WordPress để test tại chỗ
SECRET='secret_hmac_dat_trong_dashboard'
URL='https://web-cua-anh-chi.vn/wp-json/monapay/v1/webhook'
TS=$(date +%s)
BODY='{"amount":1990000,"description":"HV88 hoc phi","transfer_date":"10:30:00 28/08/2026","transaction_code":"FT26240001234","account_number":"1234567890","bank_name":"ACB","type":"income"}'

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"
# Kỳ vọng: {"success":true}, gọi lần 2 cùng BODY → {"success":true,"message":"da xu ly"} (không xử lý trùng)
JavaScript
// monapay-wp.js: dịch vụ Node nhận webhook rồi gọi WordPress REST API cập nhật dữ liệu
const express = require('express');
const crypto  = require('crypto');

const app    = express();
const SECRET = process.env.MONA_WEBHOOK_SECRET; // secret HMAC trong dashboard MONA Pay
const WP_URL = 'https://web-cua-anh-chi.vn/wp-json/wp/v2';
const WP_AUTH = 'Basic ' + Buffer.from(process.env.WP_USER + ':' + process.env.WP_APP_PASSWORD).toString('base64'); // Application Password của WordPress

app.post('/webhook/monapay', express.raw({ type: 'application/json' }), async (req, res) => {
  const timestamp = req.header('X-Mona-Timestamp') || '';
  const signature = req.header('X-Mona-Signature') || '';
  const rawBody   = req.body.toString('utf8');

  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return res.status(400).send('timestamp qua han');
  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');

  res.status(200).json({ success: true }); // trả 200 trước, xử lý sau

  const data = JSON.parse(rawBody);
  const m = /HV\s?(\d+)/i.exec(data.description || '');
  if (!m) return;
  // Ghi meta cho user (cần plugin/đoạn code expose meta 'da_thanh_toan' qua REST)
  await fetch(WP_URL + '/users/' + m[1], {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: WP_AUTH },
    body: JSON.stringify({ meta: { da_thanh_toan: data.transfer_date } }),
  });
});

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

3 việc trong dashboard MONA Pay sau khi dán code: (1) mục Webhooks, thêm địa chỉ trên, chọn xác thực HMAC_SHA256 và đặt secret trùng với MONA_WEBHOOK_SECRET; (2) chọn webhook nghe mọi tài khoản hay chỉ 1 tài khoản ảo; (3) bấm gửi thử, xem kết quả trong Lịch sử: mã HTTP, thời gian phản hồi, nhãn lỗi nếu có. Chi tiết tại tài liệu tích hợp webhook.

Chữ ký trên từng gói tin

Header X-Mona-Signature là HMAC-SHA256 trên mốc thời gian và nguyên văn gói tin. Ai không có secret thì không giả được thông báo "đã nhận tiền" để lừa web mở khoá.

Kiểm trùng bằng mã giao dịch

transaction_code giữ nguyên qua mọi lần gửi lại. Web ghi lại mã đã xử lý, gặp lại là bỏ qua, nên gửi lại 3 lần cũng chỉ mở khoá 1 lần.

Lịch sử từng lần gửi

Mỗi lần MONA Pay gọi web đều có log: mã HTTP, mili giây phản hồi, nhãn lỗi (TIMEOUT, SSL, DNS, HTTP_5XX). Web lỗi thì thấy ngay, bấm gửi lại từ dashboard.

MONA Pay là API ngân hàng và dịch vụ xác nhận thanh toán tự động của The MONA Group, giúp doanh nghiệp Việt Nam nhận và xác nhận tiền chuyển khoản theo thời gian thực qua tài khoản ảo (VA), VietQR, webhook và Telegram, thiết kế để cả lập trình viên lẫn AI agent tích hợp trong vài phút.

Hệ thống MONA tự xây để thu tiền cho chính mình, rồi từ 2022 tới nay khách hàng của MONA đã thu tiền qua đây trong web, phần mềm MONA giao. Năm 2026 mở cho mọi doanh nghiệp, miễn phí 500 giao dịch mỗi tháng. The MONA Group thành lập 2016, 14.000+ dự án, 85% khách quay lại, tổng đài 1900 636 648 có người trực trong giờ làm việc. Đội làm web WordPress lâu năm nên phần nối vào web là việc đội MONA làm mỗi ngày.

Hỏi đáp

Chủ web WordPress hay hỏi đội MONA

Chưa thấy câu của bạn? Gọi đội MONA1900 636 648
Plugin thanh toán WordPress có mất phí không?

MONA Pay thu 0% trên giá trị chuyển khoản và miễn phí 500 giao dịch mỗi tháng. Chi phí chỉ phát sinh nếu web làm ngoài MONA cần thuê dev viết phần xử lý riêng.

Chưa nối ngân hàng có thử tích hợp WordPress được không?

Được. Bạn tạo tài khoản, cấu hình webhook và dùng chức năng gửi thử để kiểm tra địa chỉ nhận, chữ ký HMAC cùng logic xử lý trên WordPress. Khi luồng thử chạy đúng mới nối tài khoản ngân hàng để nhận giao dịch thật.

Web WordPress không dùng WooCommerce có dùng được không?

Được. MONA Pay chỉ cần 1 địa chỉ trên web để gửi webhook tới. Đoạn PHP mẫu trên trang này tạo địa chỉ đó và phát sự kiện monapay_tien_vao, phần còn lại bạn nối vào bất kỳ plugin hay code nào đang chạy: khoá học, thành viên, đặt lịch, form đăng ký thu phí. Bán hàng bằng WooCommerce thì xem trang riêng cho WooCommerce.

Tiền có nằm ở MONA Pay lúc nào không?

Không. Tiền đi thẳng từ ngân hàng khách vào tài khoản ACB của bạn. MONA Pay chỉ đọc thông báo giao dịch từ ngân hàng rồi báo về web. Vì vậy không có chuyện rút tiền về, không có phí giữ tiền, và sao kê ngân hàng của bạn vẫn là nguồn sự thật cuối cùng.

Web dùng cache, CDN, Cloudflare có chặn webhook không?

Địa chỉ /wp-json/monapay/v1/webhook là request POST nên cache trang thường không đụng tới. Nếu bạn bật tường lửa chặn POST lạ, cho phép địa chỉ máy chủ gửi webhook của MONA Pay là 103.168.55.14 (kiểm ngày 28/08/2026, có đổi đội MONA cập nhật ở trang địa chỉ IP trong tài liệu).

Tôi không có dev, ai làm phần code cho tôi?

Web làm tại MONA thì đội kỹ thuật MONA nối sẵn lúc bàn giao, không tính thêm. Web làm nơi khác thì bạn gửi đoạn code mẫu trên trang này cho người đang quản trị web, thường mất 30 phút; hoặc gọi 1900 636 648 để đội MONA báo giá phần nối.

Cần chuẩn bị gì trước khi bắt đầu?

Tài khoản ACB đứng tên bạn hoặc công ty, số điện thoại đăng ký với ACB để nhận 2 lần OTP khi nối, website có HTTPS. Đăng ký tại my.monapay.vn là dùng ngay, không cần ai duyệt.

Miễn phí tới mức nào?

MONA Pay miễn phí 500 giao dịch mỗi tháng, đủ các tính năng VA, VietQR, webhook, Telegram và dashboard. Khi số giao dịch vượt hạn mức, bạn chọn gói theo nhu cầu tại trang bảng giá.

Bắt đầu với MONA Pay

Nối ngân hàng hôm nay để đơn chuyển khoản tự xác nhận

Tạo tài khoản là dùng ngay, miễn phí 500 giao dịch mỗi tháng. Muốn thử trước thì sandbox tạo giao dịch tiền vào giả, không tốn tiền thật.