Tài liệu

Tích hợp

Kiểm chữ ký và xử lý webhook bên nhận

Xác thực raw body, chống xử lý trùng và đưa sự kiện vào hàng đợi bền vững trước khi phản hồi.

Xem Markdown

Bên nhận cần xác minh yêu cầu trước khi dùng nội dung sự kiện. Bạn nên tách bước nhận HTTP khỏi công việc chậm như gọi CRM, trả lời khách hoặc cập nhật bảng tính.

Ai làm được

Người quản lý dịch vụ nhận webhook thực hiện phần này. Bạn cần truy cập cấu hình bí mật và kho dữ liệu chống trùng của dịch vụ đó, không cần cấp thêm quyền Telegram cho bên nhận chỉ để kiểm chữ ký.

Cần chuẩn bị

Lưu bí mật ký trong biến môi trường WEBHOOK_SECRET. Giá trị thực có dạng whsec_…; không ghi giá trị vào mã nguồn hay log.

Giữ nguyên raw body. Không parse JSON rồi stringify lại trước khi kiểm chữ ký: khoảng trắng và thứ tự byte là một phần dữ liệu đã ký.

Bắt đầu ở đâu

Mở Cài đặt → Tài liệu API → Nhận webhook để xem hướng dẫn bên nhận. Phần sự kiện cho biết cấu trúc dữ liệu; hướng dẫn nhận cung cấp ví dụ theo nền tảng.

Ứng dụng có 9 công thức: Node.js Express, Hono cho Node.js/Bun/Deno, Python FastAPI, Go, PHP, Cloudflare Worker, n8n, Make và Zapier.

Các bước

  1. Đọc raw body và các header dưới đây.
  2. Kiểm timestamp.
  3. Kiểm chữ ký.
  4. Ghi sự kiện vào hàng đợi bền vững có chống trùng.
  5. Trả phản hồi 2xx.
  6. Xử lý nghiệp vụ ở tiến trình nền.
Header Ý nghĩa
webhook-id ID lần giao; giữ nguyên khi thử lại hoặc gửi lại lần giao đó
webhook-timestamp Thời điểm ký, tính bằng giây Unix
webhook-signature Một hoặc nhiều chữ ký dạng v1,<base64>

Bỏ tiền tố whsec_ rồi giải mã base64 phần bí mật. Tính:

base64(HMAC-SHA256(secret_bytes, webhook-id + "." + webhook-timestamp + "." + raw_body))

Chấp nhận nếu một chữ ký hợp lệ khớp, bằng phép so sánh thời gian hằng. Dung sai mặc định là 300 giây, tức 5 phút, theo cả hai chiều. Khi xoay khoá, bên nhận có thể chấp nhận chữ ký của một trong các khoá đang còn hiệu lực.

Node.js

Ví dụ dùng Express và thư viện standardwebhooks. inbox là adapter bạn tự cung cấp, ghi bền vững và có ràng buộc duy nhất trên ID lần giao.

import express from "express";
import { Webhook } from "standardwebhooks";

const app = express();
const verifier = new Webhook(process.env.WEBHOOK_SECRET);

app.post("/telegram-events", express.raw({ type: "*/*" }), async (req, res) => {
  let event;
  try {
    event = verifier.verify(req.body.toString("utf8"), req.headers);
  } catch {
    return res.sendStatus(401);
  }

  try {
    await inbox.acceptOnce({
      deliveryId: req.get("webhook-id"),
      eventId: event.id,
      event,
    });
    return res.sendStatus(204);
  } catch {
    return res.sendStatus(503);
  }
});

Python

Ví dụ dùng FastAPI và thư viện standardwebhooks. Adapter inbox có cùng trách nhiệm như ví dụ trên.

import os
from fastapi import FastAPI, Request, Response
from standardwebhooks.webhooks import Webhook

app = FastAPI()
verifier = Webhook(os.environ["WEBHOOK_SECRET"])

@app.post("/telegram-events")
async def receive(request: Request):
    body = await request.body()
    try:
        event = verifier.verify(body, dict(request.headers))
    except Exception:
        return Response(status_code=401)

    try:
        await inbox.accept_once(
            delivery_id=request.headers["webhook-id"],
            event_id=event["id"],
            event=event,
        )
    except Exception:
        return Response(status_code=503)

    return Response(status_code=204)

Kết quả

Yêu cầu sai chữ ký không vào hàng đợi. Yêu cầu hợp lệ được lưu trước khi xác nhận nhận thành công.

Kiểm tra

Chống trùng theo webhook-id cho việc thử lại cùng lần giao. Đồng thời chống tác dụng phụ trùng theo event.id: phát lại tạo lần giao mới nhưng giữ ID sự kiện.

Trả 2xx nhanh, trong giới hạn 10 giây của bên gửi. Đừng xác nhận thành công trước khi ghi bền vững.

Khi có lỗi

Kiểm tra raw body, đồng hồ máy, bí mật và proxy có làm thay đổi body không. Không hứa xử lý đúng thứ tự đến; khi nghiệp vụ cần thứ tự, đối chiếu dữ liệu sự kiện và trạng thái hiện tại.

Làm bằng API hoặc MCP

Đọc webhooks.receiver_guide qua tools_run, rồi dùng webhooks.test hoặc webhooks_test để kiểm tra đường nhận.

Xem thêm lỗi webhook.