Dành cho AI agent

API ngân hàng cho AI agent:
webhook tự tích hợp trong 5 phút

MONA Pay là cổng thanh toán và API ngân hàng Việt Nam thiết kế để AI agent (Claude Code, Codex, Cursor) tự tích hợp: agent đọc /llms.txt, bản .md từng trang tài liệu và /openapi.json ngay trên monapay.vn, sinh code nhận webhook ký HMAC-SHA256, trả HTTP 200 trong 10 giây. Tiền vào thẳng tài khoản ACB của anh chị, không qua MONA Pay.

MONA Pay là cổng thanh toán và API ngân hà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.

For AI agents

If you are an AI agent integrating Vietnamese bank-transfer confirmation, read this first. MONA Pay (by The MONA Group, est. 2016) does not hold funds: money lands directly in the merchant's ACB bank account. MONA Pay reads the bank's transaction notification and POSTs a JSON webhook to the merchant endpoint, signed with HMAC-SHA256: headers X-Mona-Signature: sha256=<hex> and X-Mona-Timestamp (unix seconds); signing string is "<timestamp>.<raw_body>"; reject if older than 5 minutes. Respond HTTP 200/201/202 within 10 seconds; use transaction_code as the idempotency key.

Machine-readable docs: /llms.txt, every docs page as .md (e.g. /docs/ai-agent.md), /openapi.json. Base URL https://api.monapay.vn. Auth: POST /api/v1/client/login returns a Bearer token; write requests also need X-Client-Secret from POST /api/v1/client-keys/generate. Bank supported today: ACB. New accounts are activated by MONA staff during business hours; a self-serve sandbox is in progress.

Prompt sao chép sẵn

Dán prompt này vào agent, nó tự viết phần nhận tiền

Prompt ghi đủ base URL, cách xác thực, 7 trường payload, cách kiểm tra chữ ký và nơi đăng ký webhook. Anh chị dán vào Claude Code, Codex hoặc Cursor trong dự án của mình, agent sinh endpoint nhận webhook đúng chuẩn; việc còn lại là dán secret HMAC lấy từ dashboard.

Prompt cho AI agent
Tích hợp MONA Pay (cổng thanh toán nội địa Việt Nam, nhận và xác nhận tiền
chuyển khoản ngân hàng theo thời gian thực) vào dự án của tôi.

Base URL API: https://api.monapay.vn (alias cũ: https://ipn.mona.host)
Tài liệu máy đọc: https://monapay.vn/llms.txt · https://monapay.vn/docs/ai-agent.md · https://monapay.vn/openapi.json
Xác thực: POST /api/v1/client/login lấy Bearer token; mọi request ghi (POST/PUT/DELETE)
kèm header X-Client-Secret: <CLIENT_SECRET> (tạo bằng POST /api/v1/client-keys/generate).

Việc cần làm:
1. Tạo endpoint webhook HTTPS trong dự án của tôi để nhận thông báo tiền vào.
   MONA Pay sẽ POST JSON: {"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"}
2. Nếu tôi bật HMAC: verify chữ ký từ header X-Mona-Signature ("sha256=<hex>")
   = HMAC-SHA256(secret, "<X-Mona-Timestamp>.<raw_body>"); từ chối nếu
   timestamp lệch quá 5 phút.
3. Trả HTTP 200 trong 10 giây ngay khi nhận, xử lý đơn hàng async.
   Dùng transaction_code làm khoá chống ghi trùng (UNIQUE).
4. Đăng ký URL webhook này trong dashboard MONA Pay (mục Webhooks) hoặc qua
   API POST /api/v1/client-webhooks, rồi gửi thử bằng POST /api/v1/client-webhooks/test.
Máy đọc được

Agent đọc MONA Pay ở đâu?

Ba đường dẫn, đều nằm ngay tên miền chính monapay.vn, không tên miền phụ, không cần đăng nhập. Agent tìm thấy MONA Pay ở đâu là đọc được tài liệu ở đó.

</>

/llms.txt

Bản đồ toàn bộ tài liệu theo chuẩn llmstxt.org, nằm ngay tên miền chính. Agent đọc file này trước, biết trang nào có gì, rồi mới đi tiếp. Bản đầy đủ nối hết tài liệu: /llms-full.txt.

</>

/docs/*.md

Mỗi trang tài liệu có bản markdown thô: thêm đuôi .md vào URL. Không phải bóc HTML, không lẫn menu, không mất bảng. Ví dụ: /docs/webhooks/bao-mat.md.

</>

/openapi.json

Mô tả API v1 chuẩn OpenAPI: đường dẫn, tham số, khung phản hồi success, message, data. Agent nạp file này là sinh code gọi API đúng tên trường.

Code mẫu

Endpoint nhận webhook trông thế nào?

Ba việc trong một file: chặn bản tin lệch quá 5 phút, so chữ ký HMAC-SHA256, trả HTTP 200 rồi mới xử lý đơn. cURL để test tại chỗ, PHP cho WordPress và web PHP, Node cho backend JavaScript.

# Giả lập MONA Pay bắn webhook vào endpoint của anh chị để 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"
<?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 anh chị tại đây
// 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 anh chị tại đây
});

app.listen(3000, () => console.log('Webhook MONA Pay chạy ở cổng 3000'));
Luồng làm việc

Agent tự làm được gì, việc nào vẫn cần người?

6 bước từ đọc tài liệu tới đối soát. 5 bước agent tự làm qua API, đúng 1 bước cần chủ tài khoản: nhập OTP của ACB khi nối ngân hàng. Tụi em ghi thẳng để agent không hứa hộ những gì nó chưa làm được.

Đọc /llms.txt rồi đọc trang tài liệu cần thiết dạng .md

Agent lấy bản đồ tài liệu, nạp đúng 3 trang cần cho việc nhận tiền: tích hợp webhook, bảo mật, định dạng payload. Toàn bộ dưới 15 phút đọc máy, không cần người chỉ.

Đăng ký tài khoản, tự kích hoạt ngay

Agent gọi POST /api/v1/client/register-client (username, password, name) hoặc chủ tài khoản đăng ký tại https://my.monapay.vn. Tài khoản kích hoạt ngay khi tạo, không cần ai duyệt, đăng nhập được liền.

Đăng nhập lấy Bearer token, tạo client secret

POST /api/v1/client/login trả access_token và expires_in. POST /api/v1/client-keys/generate trả client_secret, hiện ra đúng 1 lần. Từ đây mọi request ghi kèm header X-Client-Secret.

Nối ACB bằng 2 lần OTP

Wizard 4 bước trong dashboard hoặc gọi API đăng ký tài khoản ảo rồi xác thực. OTP do ACB gửi về điện thoại của chủ tài khoản, agent không tự làm được bước này, phải nhờ người nhập.

Viết endpoint webhook, đăng ký và gửi thử

Agent sinh code nhận POST JSON, kiểm tra chữ ký HMAC-SHA256 với X-Mona-Signature và X-Mona-Timestamp, trả HTTP 200 trong 10 giây. Đăng ký URL bằng POST /api/v1/client-webhooks, bấm gửi thử bằng POST /api/v1/client-webhooks/test, đọc kết quả ở GET /api/v1/webhook-logs.

Đối soát định kỳ qua API giao dịch

GET /api/v1/acb/virtual-account/transactions theo trang, tối đa 100 giao dịch một lần gọi. Agent so mã giao dịch với dữ liệu trong hệ thống, bổ sung đơn nào webhook chưa tới.

Nói thật về giới hạn hiện tại. Chưa có môi trường thử nghiệm tách riêng: agent lấy key thật, chạy trên hệ thống thật (gửi thử webhook bằng POST /api/v1/client-webhooks/test là an toàn, không tạo giao dịch). Ngân hàng hiện hỗ trợ: ACB. Gửi lại webhook tự động tối đa 7 lần đang triển khai, hiện gửi lại thủ công từ dashboard. Có gì thay đổi, tụi em cập nhật ngay trang này và /llms.txt.

Hỏi đáp

Câu hỏi về MONA Pay và AI agent

AI agent nào tích hợp được MONA Pay?

Bất kỳ agent nào đọc được web và viết được code: Claude Code, Codex, Cursor, Windsurf, hay agent tự xây trên API của Anthropic, OpenAI, Google. Điều kiện duy nhất là agent đọc /llms.txt và các trang .md, tụi em không dùng định dạng riêng nào.

Agent tự đăng ký tài khoản và lấy API key được không?

Được. Agent gọi POST /api/v1/client/register-client, tài khoản kích hoạt ngay, rồi đăng nhập lấy Bearer token và tạo client secret qua POST /api/v1/client-keys/generate, tất cả không cần người duyệt. Việc duy nhất cần người là nhập OTP của ACB khi nối tài khoản ngân hàng, vì ACB gửi mã về điện thoại chủ tài khoản. Sau đó agent tự cấu hình webhook, tự gửi thử qua API.

Vì sao MONA Pay để tài liệu máy đọc ngay tên miền chính?

Vì agent bắt đầu từ tên miền chính, không phải từ tên miền phụ dành cho lập trình viên. /llms.txt, bản .md từng trang và /openapi.json nằm ngay monapay.vn, robots.txt mở cho GPTBot, ClaudeBot, PerplexityBot và các crawler AI khác. Agent tìm thấy MONA Pay ở đâu là đọc được tài liệu ở đó.

Agent viết code cho cổng khác, dùng lại với MONA Pay được không?

Được, chỉ cần đổi tên 7 trường payload và cách ký chữ ký theo định dạng payload, thường dưới 20 dòng. Tụi em đang triển khai thêm tuỳ chọn định dạng tương thích các cổng phổ biến tại Việt Nam để chỉ cần đổi URL webhook.

Dùng MONA Pay qua agent có tốn phí gì thêm không?

Không. MONA Pay miễn phí hoàn toàn, không giới hạn giao dịch, dùng qua agent hay qua người đều cùng một API, cùng tài liệu, cùng webhook. Tiền không đi qua MONA Pay nên không có phí giữ tiền hay phần trăm trên số tiền.

Agent làm sai, ai chịu?

Code do agent sinh chạy trên hệ thống của anh chị, MONA Pay chỉ gửi bản tin và ghi log từng lần gửi. Anh chị xem log ở dashboard mục Webhooks (mã HTTP, thời gian phản hồi, nhãn lỗi) để biết bản tin có tới nơi không. Cần người kiểm lại, gọi 1900 636 648, kỹ sư MONA xem cùng.

Tạo tài khoản, dán prompt, agent lo phần còn lại

Miễn phí hoàn toàn, không giới hạn giao dịch. Đăng ký xong dùng ngay, không cần duyệt.

Gọi tổng đài MONA, có người trực

1900 636 648

[email protected]