Tổng quan
Nhận các sự kiện TicketWave dưới dạng yêu cầu HTTP đã ký trong ứng dụng của riêng bạn.
Webhooks
Webhook là một yêu cầu HTTP mà TicketWave gửi đến bạn. Bất cứ khi nào có điều gì đó xảy ra trên máy chủ của bạn — một ticket được mở, một thành viên bị đưa vào danh sách đen — TicketWave sẽ POST một body JSON đến một URL do bạn sở hữu.
Đó là điểm khác biệt so với Log Channels: log channels ghi một embed vào Discord để con người đọc, còn webhook chuyển sự kiện thô trực tiếp cho mã của bạn.
Webhooks là một tính năng premium. Nếu không có premium, không thể tạo endpoint và cũng sẽ không có sự kiện nào được gửi đến.
Tạo Endpoint
Mở trang endpoints
Server dashboard → Webhooks → Endpoints.
Thêm endpoint
Nhấp Add Endpoint và điền hai trường:
| Field | Description |
|---|---|
| Endpoint URL | URL https:// nhận các yêu cầu |
| Event Types | Những loại sự kiện mà endpoint này sẽ nhận |
Một endpoint chỉ nhận những loại bạn chọn. Không được để trống — hãy chọn ít nhất một loại.
Sao chép signing secret
TicketWave sẽ tạo một signing secret (whsec_…) ngay khi endpoint được tạo. Mở danh sách endpoints, hiện nó bằng biểu tượng con mắt rồi sao chép vào cấu hình ứng dụng của bạn.
Hãy coi secret này như mật khẩu. Bất kỳ ai có nó đều có thể giả mạo các yêu cầu và vượt qua bước kiểm tra chữ ký của bạn. Hãy lưu nó trong biến môi trường, không bao giờ đưa vào repository.
Gửi sự kiện thử
Dùng nút Send test event (biểu tượng máy bay giấy) trên dòng endpoint. Nó sẽ gửi một yêu cầu thật, đã được ký đầy đủ, với "test": true trong payload, để bạn có thể xác nhận bộ nhận của mình hoạt động trước khi một ticket thật phụ thuộc vào nó.
Kết quả sẽ xuất hiện trong lịch sử Webhooks như bất kỳ lần gửi nào khác.
Yêu cầu đối với Endpoint
| Requirement | Detail |
|---|---|
| Scheme | Chỉ https:// — http:// sẽ bị từ chối |
| Host | Phải có thể phân giải công khai. Các địa chỉ private, loopback, link-local và CGNAT đều bị từ chối |
| Response | Bất kỳ trạng thái 2xx nào đều được tính là thành công |
| Timeout | Bạn có 10 giây để phản hồi |
| Redirects | Không theo chuyển hướng. 3xx được tính là thất bại |
| Limit | Tối đa 5 endpoint cho mỗi server |
Việc kiểm tra host diễn ra cả khi bạn lưu endpoint và trước mỗi lần gửi, vì vậy nếu một domain sau này trỏ về địa chỉ nội bộ thì sẽ không còn được gửi đến nữa.
Yêu cầu HTTP
Mỗi lần gửi là một POST với body JSON.
Headers
| Header | Example | Meaning |
|---|---|---|
Content-Type | application/json | Luôn là JSON |
User-Agent | TicketWave-Webhooks/1.0.5 | Phiên bản bot đã gửi yêu cầu |
X-TicketWave-Event | ticket.created | Loại sự kiện |
X-TicketWave-Delivery | wh_3f2a… | ID duy nhất cho lần gửi này |
X-TicketWave-Timestamp | 1786224191 | Số giây Unix, là một phần của chữ ký |
X-TicketWave-Signature | sha256=9f86d0… | HMAC của yêu cầu |
Body
Mọi payload đều dùng cùng một khung bao. Chỉ data là khác nhau theo từng loại sự kiện:
{
"event": "ticket.created",
"timestamp": "2026-08-26T08:23:11.000Z",
"guild_id": "123456789012345678",
"data": {
"ticket_id": "ticket-1042",
"ticket_num_id": 1042,
"channel_id": "998877665544332211",
"category": "🤖 Support",
"user": { "id": "987654321098765432", "username": "Luna" },
"created_at": "2026-08-26T08:23:11.000Z"
}
}Xem Event Reference để biết đối tượng data của từng loại.
Xác minh chữ ký
Bất kỳ ai phát hiện ra URL endpoint của bạn đều có thể gửi một yêu cầu POST đến đó. Chữ ký là cách bạn phân biệt một lần gửi thật từ TicketWave với một yêu cầu giả mạo.
Luôn luôn xác minh. Một endpoint không được xác minh mà lại tạo hoặc đóng thứ gì đó trong hệ thống của bạn thì chẳng khác nào mở toang cánh cửa.
Chữ ký được tạo như thế nào
TicketWave ghép timestamp và body yêu cầu thô bằng dấu chấm, rồi chạy HMAC-SHA256 trên kết quả bằng secret của endpoint:
signed_payload = X-TicketWave-Timestamp + "." + raw_request_body
signature = HMAC_SHA256(signed_payload, your_endpoint_secret)Header sẽ mang digest đó dưới dạng hex và có tiền tố: sha256=<digest>.
Bộ nhận của bạn phải làm gì
Đọc raw body. Hãy xác minh dựa trên đúng các byte bạn nhận được. Nếu framework của bạn parse JSON trước rồi bạn serialize lại, thứ tự key hoặc khoảng trắng có thể thay đổi và digest sẽ không khớp.
Tính lại HMAC trên timestamp + "." + rawBody bằng secret của bạn.
So sánh theo thời gian hằng định (crypto.timingSafeEqual trong Node). Dùng === thông thường sẽ làm lộ thông tin về thời gian.
Kiểm tra timestamp còn mới — mặc định tốt là cho phép lệch năm phút. Timestamp nằm trong payload đã ký, nên kẻ tấn công không thể phát lại một yêu cầu cũ với timestamp mới.
Một triển khai hoàn chỉnh có ở trang Example Server.
Thử lại
Một lần gửi thất bại sẽ được tự động thử lại.
| Attempts | 3 (lần đầu cộng 2 lần thử lại) |
| Backoff | 1 giây, rồi 5 giây |
| Retried on | Lỗi mạng, timeout, 408, 429 và mọi 5xx |
| Not retried on | Mọi 4xx khác — nghĩa là endpoint của bạn đã cố ý từ chối yêu cầu |
Do có cơ chế thử lại, endpoint của bạn có thể nhận cùng một sự kiện hai lần. Hãy dùng X-TicketWave-Delivery làm idempotency key: ghi nhớ các ID bạn đã xử lý và bỏ qua các lần lặp lại.
Các lần gửi không được sắp xếp theo thứ tự. Nếu hai ticket được tạo cùng lúc, các yêu cầu có thể đến theo bất kỳ thứ tự nào — hãy dùng trường timestamp trong body nếu thứ tự quan trọng với bạn.
Lịch sử gửi
Trang Webhooks trong dashboard liệt kê mọi lần gửi cùng trạng thái, mã phản hồi, thời lượng và số lần thử. Mở một dòng để xem chính xác payload đã được gửi và phản hồi mà server của bạn trả về.
Các lần gửi thất bại có thể được gửi lại từ trang chi tiết bằng Retry Webhook. Nó sẽ gửi lại payload gốc đến cùng endpoint và ghi nhận một lần gửi mới.
Lịch sử được lưu trong 30 ngày, sau đó sẽ tự động được dọn dẹp.
Khắc phục sự cố
| Problem | Fix |
|---|---|
| Không thể lưu endpoint | URL phải là https:// và phân giải đến một địa chỉ công khai |
| Mọi thứ đều hiển thị là thất bại mà không có mã phản hồi | Yêu cầu chưa bao giờ đến được máy chủ của bạn — timeout, lỗi DNS hoặc kết nối bị từ chối |
| Chữ ký không bao giờ khớp | Bạn đang băm body đã parse thay vì các byte thô, hoặc quên tiền tố timestamp + "." |
| Các lần gửi dừng lại sau một lúc | Kiểm tra xem host của bạn có bắt đầu trả về 4xx không — các mã này sẽ không được thử lại |
| Một sự kiện không bao giờ đến | Endpoint chưa đăng ký loại đó, hoặc server đã mất premium |
| Sự kiện trùng lặp | Đây là điều bình thường khi thử lại — hãy khử trùng lặp dựa trên X-TicketWave-Delivery |
Bước tiếp theo
- Event Reference (Mọi sự kiện và payload của nó)
- Example Server (Một bộ nhận Express có thể chạy được)
- Log Channels (Các sự kiện giống nhau, nhưng được đăng vào Discord)
How is this guide?
