Cấu hình webhook qua API

Mọi thứ làm được ở dashboard mục Webhooks đều có API tương ứng: POST /api/v1/client-webhooks tạo cấu hình (URL nhận, kiểu xác thực HMAC_SHA256 / API_KEY / NONE, định dạng payload, gắn theo 1 VA hoặc mọi tài khoản), PUTDELETE /api/v1/client-webhooks/{config_id} để sửa, xoá, POST /api/v1/client-webhooks/test bắn 1 payload giả lập 500.000đ để thử endpoint trước khi có tiền thật. Lịch sử từng lần gửi (mã HTTP, thời gian phản hồi duration_ms, nhãn lỗi) đọc ở GET /api/v1/webhook-logs, thống kê 7-30 ngày ở GET /api/v1/webhook-logs/stats.

Cách MONA Pay ký và gửi payload xem ở Tích hợp webhookBảo mật; trang này là tham chiếu API.

Đối tượng cấu hình webhook

Trường Kiểu Bắt buộc khi tạo Ghi chú
name string Tên gợi nhớ (“Web bán hàng”, “Phần mềm kế toán”)
webhook_url string URL HTTPS nhận POST của anh chị
auth_type NONE / API_KEY / HMAC_SHA256 không, mặc định NONE Nên dùng HMAC_SHA256
secret_key string cần khi auth_type khác NONE Secret để ký HMAC hoặc gửi trong header API key
api_key_name string không, mặc định X-Webhook-Secret Tên header mang secret khi auth_type = API_KEY
payload_format application/json / application/x-www-form-urlencoded / multipart/form-data không, mặc định application/json Kiểu body MONA Pay gửi
virtual_account_id uuid không Gắn cấu hình với 1 VA. Bỏ trống = mọi tài khoản, mọi VA
is_active boolean chỉ khi PUT Tắt tạm không cần xoá

Mỗi giao dịch tiền vào sẽ bắn tới mọi cấu hình đang bật khớp điều kiện: cấu hình “mọi tài khoản” luôn nhận, cấu hình gắn VA chỉ nhận giao dịch của VA đó. Giữ số cấu hình gọn (dưới 20) để dễ theo dõi log.

GET /api/v1/client-webhooks

Danh sách cấu hình của tài khoản. Cần Bearer.

curl https://api.monapay.vn/api/v1/client-webhooks -H "Authorization: Bearer $MONA_TOKEN"
{
  "success": true,
  "message": "Success",
  "data": [
    { "id": "0190e0f1-...", "name": "Web ban hang", "webhook_url": "https://shop.vn/webhook/monapay", "auth_type": "HMAC_SHA256", "api_key_name": "X-Webhook-Secret", "payload_format": "application/json", "virtual_account_id": null, "is_active": true, "max_retries": 7, "created_at": "2026-08-28T11:00:00" }
  ]
}

secret_key không trả về trong danh sách. max_retries là số lần gửi lại tối đa dành cho cơ chế gửi lại tự động đang triển khai; hiện chưa có tác dụng.

POST /api/v1/client-webhooks

Cần Bearer + X-Client-Secret.

cURL

curl -X POST https://api.monapay.vn/api/v1/client-webhooks \
  -H "Authorization: Bearer $MONA_TOKEN" -H "X-Client-Secret: $MONA_SECRET" \
  -H 'Content-Type: application/json' \
  -d '{"name":"Web ban hang","webhook_url":"https://shop.vn/webhook/monapay","auth_type":"HMAC_SHA256","secret_key":"hmac-secret-dai-va-ngau-nhien","payload_format":"application/json"}'

PHP

<?php
$ch = curl_init('https://api.monapay.vn/api/v1/client-webhooks');
curl_setopt_array($ch, [
    CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . getenv('MONA_TOKEN'), 'X-Client-Secret: ' . getenv('MONA_SECRET')],
    CURLOPT_POSTFIELDS => json_encode([
        'name' => 'Web ban hang',
        'webhook_url' => 'https://shop.vn/webhook/monapay',
        'auth_type' => 'HMAC_SHA256',
        'secret_key' => getenv('MONA_WEBHOOK_SECRET'), // cùng secret server nhận webhook dùng để verify
    ]),
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($res['success'])) throw new RuntimeException($res['message'] ?? 'Tạo webhook thất bại');
$configId = $res['data']['id'];

Node

const r = await fetch('https://api.monapay.vn/api/v1/client-webhooks', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${process.env.MONA_TOKEN}`, 'X-Client-Secret': process.env.MONA_SECRET },
  body: JSON.stringify({
    name: 'Web ban hang',
    webhook_url: 'https://shop.vn/webhook/monapay',
    auth_type: 'HMAC_SHA256',
    secret_key: process.env.MONA_WEBHOOK_SECRET, // cùng secret server nhận webhook dùng để verify
  }),
});
const { success, data, message } = await r.json();
if (!success) throw new Error(message);
console.log('config id', data.id);

PUT /api/v1/client-webhooks/{config_id}

Sửa một phần, chỉ gửi trường cần đổi. Cần Bearer + X-Client-Secret.

curl -X PUT https://api.monapay.vn/api/v1/client-webhooks/0190e0f1-... \
  -H "Authorization: Bearer $MONA_TOKEN" -H "X-Client-Secret: $MONA_SECRET" \
  -H 'Content-Type: application/json' -d '{"is_active":false}'

DELETE /api/v1/client-webhooks/{config_id}

Xoá cấu hình. Log cũ vẫn giữ để tra cứu.

curl -X DELETE https://api.monapay.vn/api/v1/client-webhooks/0190e0f1-... \
  -H "Authorization: Bearer $MONA_TOKEN" -H "X-Client-Secret: $MONA_SECRET"

POST /api/v1/client-webhooks/test

Bắn 1 payload giả lập tới URL bất kỳ, không cần tạo cấu hình trước. Dùng để thử endpoint và code verify HMAC. Cần Bearer + X-Client-Secret.

Trường Kiểu Bắt buộc Ghi chú
webhook_url string URL cần thử
auth_type string không, mặc định NONE Thử đúng kiểu anh chị sẽ dùng
secret_key string khi auth khác NONE
api_key_name string không
payload_format string không
is_dummy boolean không Gửi payload giao dịch giả lập (nên đặt true)

Payload giả lập MONA Pay gửi:

{"amount":500000,"description":"DUMMY TRANSACTION MONAPAY","transfer_date":"11:05:00 28/08/2026","transaction_code":"DUMMY123","account_number":"1900636648","bank_name":"ACB","type":"income"}

Server anh chị nên nhận ra transaction_code = DUMMY123 để không tạo đơn thật.

curl -X POST https://api.monapay.vn/api/v1/client-webhooks/test \
  -H "Authorization: Bearer $MONA_TOKEN" -H "X-Client-Secret: $MONA_SECRET" \
  -H 'Content-Type: application/json' \
  -d '{"webhook_url":"https://shop.vn/webhook/monapay","auth_type":"HMAC_SHA256","secret_key":"hmac-secret-dai-va-ngau-nhien","is_dummy":true}'

Response: successtrue khi server anh chị trả 200/201/202 trong 10 giây; false kèm message mô tả lỗi (timeout, SSL, 4xx/5xx).

GET /api/v1/webhook-logs

Lịch sử từng lần gửi, mới nhất trước. Cần Bearer.

Tham số (query) Kiểu Ghi chú
page integer ≥1 mặc định 1
limit integer 1-100 mặc định 20
status success / failed success = mã 2xx
from_date, to_date YYYY-MM-DD Lọc theo ngày tạo (UTC)
curl "https://api.monapay.vn/api/v1/webhook-logs?status=failed&from_date=2026-08-01&limit=50" \
  -H "Authorization: Bearer $MONA_TOKEN"
{
  "success": true,
  "message": "Webhook logs retrieved successfully",
  "data": {
    "items": [
      {
        "id": "0190f0a1-...",
        "client_id": "0190a0f0-...",
        "event_type": "webhook",
        "endpoint_url": "https://shop.vn/webhook/monapay",
        "request_payload": "{\"amount\":2500000,...}",
        "request_headers": "{\"X-Mona-Timestamp\":\"1756350312\",\"X-Mona-Signature\":\"sha256=...\"}",
        "status_code": 500,
        "response_text": "Internal Server Error",
        "duration_ms": 842,
        "error_label": "HTTP_5XX",
        "created_at": "2026-08-28T10:45:13+00:00"
      }
    ],
    "total": 3,
    "page": 1,
    "limit": 50
  }
}

error_label nhận một trong: OK, HTTP_3XX, HTTP_4XX, HTTP_5XX, TIMEOUT, SSL, DNS, CONNECTION, ERROR. event_typewebhook cho giao dịch thật, test cho lần gửi thử. Ý nghĩa từng nhãn và cách sửa ở Gửi lại và xử lý lỗi.

GET /api/v1/webhook-logs/stats

Thống kê theo số ngày gần nhất (tham số days, ví dụ 7 hoặc 30). Cần Bearer.

curl "https://api.monapay.vn/api/v1/webhook-logs/stats?days=7" -H "Authorization: Bearer $MONA_TOKEN"
{
  "success": true,
  "message": "Success",
  "data": {
    "days": 7,
    "total": 412,
    "success": 409,
    "failed": 3,
    "success_rate": 99.27,
    "p95_duration_ms": 610,
    "daily": [ { "date": "2026-08-22", "total": 58, "failed": 0 } ],
    "errors": [ { "label": "HTTP_5XX", "count": 2 }, { "label": "TIMEOUT", "count": 1 } ]
  }
}

p95_duration_ms là thời gian server anh chị phản hồi ở phân vị 95; con số này vượt 5.000 là nên xem lại endpoint, vì MONA Pay cắt ở 10.000 ms.

Lỗi thường gặp

HTTP Nguyên nhân Cách xử lý
401 Token hết hạn hoặc thiếu X-Client-Secret ở POST/PUT/DELETE Login lại, thêm header
422 auth_type Giá trị ngoài NONE / API_KEY / HMAC_SHA256 Viết hoa đúng
422 payload_format Ngoài 3 giá trị cho phép Dùng application/json
test trả success: false Server anh chị không phản hồi 2xx trong 10 giây, hoặc SSL/DNS lỗi Đọc message, thử curl chính URL đó từ máy khác