Bỏ qua tới nội dung
QH2Pay Tài liệu Lấy API Token
Trong trang này

Webhooks · Payload & Xác thực

Khi có giao dịch khớp điều kiện, QHTech gửi một request POST tới URL webhook của bạn với body là JSON.

#HTTP headers

QHTech đính kèm token của webhook vào hai header (cả hai đều mang cùng một giá trị token bạn đã cấu hình):

POST /your-webhook-endpoint HTTP/1.1
Content-Type: application/json
QHTECH-TOKEN: {token}
Authorization: Apikey {token}
Header Giá trị Dùng để
Content-Type application/json Định dạng body
QHTECH-TOKEN {token} Token bí mật của webhook — dùng để xác thực
Authorization Apikey {token} Cùng token, ở dạng header Authorization

Bạn có thể kiểm tra một trong hai header trên là đủ.

#Cấu trúc payload

{
  "transaction_id": "20250812083338000006",
  "gateway": "BIDV",
  "transactionDate": "2026-06-10 08:33:38",
  "accountNumber": "96247100868",
  "code": "DH12345",
  "content": "DH12345 chuyen tien mua hang",
  "transferType": "in",
  "transferAmount": 150000,
  "referenceCode": "0551dTCO-82LiomOss"
}

#Mô tả field

Field Kiểu Mô tả
transaction_id string | null Mã giao dịch tại QHTech
gateway string Mã ngân hàng nguồn (ví dụ BIDV)
transactionDate string (Y-m-d H:i:s) Thời điểm giao dịch
accountNumber string Số tài khoản ngân hàng nhận/phát sinh giao dịch
code string | null Mã thanh toán trích được từ nội dung chuyển khoản (theo cấu trúc mã của bạn). null nếu không trích được
content string Nội dung / diễn giải giao dịch (nguyên văn từ ngân hàng)
transferType string in = tiền vào · out = tiền ra
transferAmount int Số tiền (VND)
referenceCode string | null Mã tham chiếu của ngân hàng (core reference)

code dùng để làm gì? Nếu bạn đặt nội dung chuyển khoản là mã đơn hàng (ví dụ khi sinh QR với memo=DH12345), QHTech sẽ tự trích mã đó vào field code — giúp bạn khớp giao dịch với đúng đơn hàng. Cấu trúc mã được cấu hình ở Cài đặt → Cấu trúc mã thanh toán.

#Xác thực request đến từ QHTech

Webhook công khai trên Internet, nên bạn phải kiểm tra mỗi request có đúng là do QHTech gửi không, bằng cách so sánh token trong header với token bạn đã cấu hình cho webhook.

QHTech dùng cơ chế shared token (không ký HMAC). Vì token được gửi trong header dạng plaintext, hãy luôn dùng HTTPS cho URL webhook để tránh lộ token trên đường truyền.

PHP (Laravel controller)

public function handle(Request $request)
{
    $expected = config('services.qhtech.webhook_token'); // token bạn đã cấu hình

    // Chấp nhận 1 trong 2 header
    $token = $request->header('QHTECH-TOKEN')
        ?? str_replace('Apikey ', '', (string) $request->header('Authorization'));

    if (! hash_equals($expected, (string) $token)) {
        return response()->json(['success' => false], 401);
    }

    $data = $request->all();
    // Chỉ xử lý tiền vào, ví dụ:
    if ($data['transferType'] === 'in') {
        // TODO: khớp đơn hàng theo $data['code'] và cộng tiền
    }

    return response()->json(['success' => true]); // HTTP 200
}

Node.js (Express)

app.post("/qhtech/webhook", express.json(), (req, res) => {
  const expected = process.env.QHTECH_WEBHOOK_TOKEN;

  const auth = req.get("authorization") || "";
  const token = req.get("qhtech-token") || auth.replace("Apikey ", "");

  if (token !== expected) {
    return res.status(401).json({ success: false });
  }

  const data = req.body;
  if (data.transferType === "in") {
    // TODO: khớp đơn hàng theo data.code và cộng tiền
  }

  return res.json({ success: true }); // HTTP 200
});

Tiếp theo: quy tắc phản hồi, cơ chế retry và xem log.