ภาพรวม
รับอีเวนต์ TicketWave เป็นคำขอ HTTP ที่ลงลายเซ็นแล้วในแอปพลิเคชันของคุณเอง
Webhooks
Webhook คือคำขอ HTTP ที่ TicketWave ส่งถึงคุณ ทุกครั้งที่มีบางอย่างเกิดขึ้นในเซิร์ฟเวอร์ของคุณ — เช่น มีการเปิดทิกเก็ต หรือมีสมาชิกถูกแบล็กลิสต์ — TicketWave จะ POST เนื้อหา JSON ไปยัง URL ที่คุณเป็นเจ้าของ
นี่คือความแตกต่างจาก Log Channels: log channels จะเขียน embed ลงใน Discord ให้มนุษย์อ่าน ส่วน webhooks จะส่งอีเวนต์ดิบให้โค้ดของคุณโดยตรง
Webhooks เป็นฟีเจอร์ พรีเมียม หากไม่มีพรีเมียม จะไม่สามารถสร้าง endpoint ได้ และจะไม่มีการส่งอีเวนต์ใด ๆ
สร้าง Endpoint
เปิดหน้ารายการ endpoints
แดชบอร์ดเซิร์ฟเวอร์ → Webhooks → Endpoints
เพิ่ม endpoint
คลิก Add Endpoint แล้วกรอกสองช่องนี้:
| Field | Description |
|---|---|
| Endpoint URL | URL https:// ที่รับคำขอ |
| Event Types | ประเภทอีเวนต์ที่ endpoint นี้ควรรับ |
endpoint จะรับเฉพาะประเภทที่คุณเลือกไว้เท่านั้น ไม่อนุญาตให้ไม่เลือกอะไรเลย — ต้องเลือกอย่างน้อยหนึ่งรายการ
คัดลอก signing secret
TicketWave จะสร้าง signing secret (whsec_…) ทันทีที่สร้าง endpoint เสร็จ เปิดรายการ endpoints แล้วกดไอคอนรูปตาเพื่อแสดงค่า จากนั้นคัดลอกไปใส่ในการตั้งค่าของแอปพลิเคชันคุณ
ให้ปฏิบัติกับ secret เหมือนรหัสผ่าน ใครก็ตามที่มีค่านี้สามารถปลอมคำขอให้ผ่านการตรวจลายเซ็นของคุณได้ เก็บไว้ใน environment variable เท่านั้น ห้ามเก็บใน repository
ส่งอีเวนต์ทดสอบ
ใช้ปุ่ม Send test event (ไอคอนเครื่องบินกระดาษ) ที่แถวของ endpoint มันจะส่งคำขอจริงที่ลงลายเซ็นครบถ้วน พร้อม "test": true ใน payload เพื่อให้คุณยืนยันได้ว่า receiver ของคุณทำงานก่อนที่ทิกเก็ตจริงจะพึ่งพามัน
ผลลัพธ์จะปรากฏในประวัติ Webhooks เหมือนกับการส่งปกติทุกประการ
ข้อกำหนดของ Endpoint
| Requirement | Detail |
|---|---|
| Scheme | เฉพาะ https:// เท่านั้น — http:// จะถูกปฏิเสธ |
| Host | ต้อง resolve ได้แบบสาธารณะ ที่อยู่แบบ private, loopback, link-local และ CGNAT จะถูกปฏิเสธ |
| Response | สถานะ 2xx ใด ๆ นับว่าสำเร็จ |
| Timeout | คุณมีเวลา 10 วินาที ในการตอบกลับ |
| Redirects | จะไม่ตามต่อ 3xx นับว่าเป็นความล้มเหลว |
| Limit | สูงสุด 5 endpoints ต่อเซิร์ฟเวอร์ |
การตรวจ host จะเกิดขึ้นทั้งตอนที่คุณบันทึก endpoint และ ก่อนการส่งทุกครั้ง ดังนั้นโดเมนที่ภายหลังเริ่ม resolve ไปยังที่อยู่ภายในจะหยุดได้รับการส่งไปหา
คำขอ
การส่งทุกครั้งเป็น POST พร้อม body แบบ JSON
Headers
| Header | Example | Meaning |
|---|---|---|
Content-Type | application/json | เป็น JSON เสมอ |
User-Agent | TicketWave-Webhooks/1.0.5 | เวอร์ชันของบอทที่ส่งคำขอ |
X-TicketWave-Event | ticket.created | ประเภทอีเวนต์ |
X-TicketWave-Delivery | wh_3f2a… | id เฉพาะของการส่งครั้งนี้ |
X-TicketWave-Timestamp | 1786224191 | Unix seconds ซึ่งเป็นส่วนหนึ่งของลายเซ็น |
X-TicketWave-Signature | sha256=9f86d0… | HMAC ของคำขอ |
Body
payload ทุกอันใช้ envelope เดียวกัน ต่างกันแค่ data ตามประเภทอีเวนต์:
{
"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"
}
}ดู Event Reference สำหรับอ็อบเจ็กต์ data ของแต่ละประเภท
การตรวจสอบลายเซ็น
ใครก็ตามที่รู้ URL ของ endpoint คุณสามารถส่งคำขอ POST มาหาได้ ลายเซ็นคือวิธีที่คุณใช้แยกแยะว่าการส่งนั้นมาจาก TicketWave จริงหรือเป็นของปลอม
ต้องตรวจสอบเสมอ endpoint ที่ไม่ได้ตรวจสอบแล้วไปสร้างหรือปิดอะไรบางอย่างในระบบของคุณ เท่ากับเปิดประตูทิ้งไว้
ลายเซ็นถูกสร้างอย่างไร
TicketWave จะนำ timestamp กับ body ของคำขอแบบ raw มาต่อกันด้วยจุด แล้วทำ HMAC-SHA256 กับผลลัพธ์โดยใช้ secret ของ endpoint ของคุณ:
signed_payload = X-TicketWave-Timestamp + "." + raw_request_body
signature = HMAC_SHA256(signed_payload, your_endpoint_secret)header จะส่งค่า digest นั้นในรูปแบบ hex และมี prefix: sha256=<digest>
receiver ของคุณต้องทำอะไร
อ่าน raw body แล้วตรวจสอบกับไบต์จริงที่คุณได้รับ หาก framework ของคุณ parse JSON ก่อนแล้วคุณ serialize ใหม่ ลำดับคีย์หรือช่องว่างอาจเปลี่ยน และ digest จะไม่ตรงกัน
คำนวณ HMAC ใหม่ จาก timestamp + "." + rawBody ด้วย secret ของคุณ
เปรียบเทียบแบบ constant time (crypto.timingSafeEqual ใน Node) การใช้ === แบบธรรมดาจะทำให้รั่วไหลข้อมูลด้านเวลา
ตรวจสอบว่า timestamp ยังใหม่อยู่ — โดยทั่วไปให้เผื่อไว้ห้านาทีเป็นค่าเริ่มต้นที่ดี timestamp อยู่ใน signed payload ดังนั้นผู้โจมตีจะไม่สามารถ replay คำขอเก่าด้วย timestamp ใหม่ได้
มีตัวอย่างการใช้งานแบบครบถ้วนอยู่ที่หน้า Example Server
การลองส่งใหม่
การส่งที่ล้มเหลวจะถูกลองส่งใหม่โดยอัตโนมัติ
| Attempts | 3 (ครั้งแรกบวกกับ retry อีก 2 ครั้ง) |
| Backoff | 1 วินาที แล้ว 5 วินาที |
| Retried on | ข้อผิดพลาดของเครือข่าย, timeout, 408, 429 และ 5xx ทุกแบบ |
| Not retried on | 4xx อื่น ๆ ทั้งหมด — หมายความว่า endpoint ของคุณปฏิเสธคำขอนั้นโดยตั้งใจ |
เพราะมีการ retry endpoint ของคุณจึงอาจได้รับ อีเวนต์เดียวกันสองครั้ง ใช้ X-TicketWave-Delivery เป็น idempotency key: จดจำ id ที่คุณประมวลผลแล้วและละเว้นรายการที่ซ้ำ
การส่ง ไม่ได้ เรียงลำดับเสมอไป หากมีการสร้างทิกเก็ตสองใบในเวลาเดียวกัน คำขออาจมาถึงสลับลำดับกันได้ — ใช้ฟิลด์ timestamp ใน body หากลำดับมีความสำคัญกับคุณ
ประวัติการส่ง
หน้า Webhooks ในแดชบอร์ดจะแสดงการส่งทุกครั้งพร้อมสถานะ รหัสตอบกลับ ระยะเวลา และจำนวนครั้งที่พยายามส่ง เปิดแถวเพื่อดู payload ของคำขอที่ส่งจริงและ response ที่เซิร์ฟเวอร์ของคุณส่งกลับมา
การส่งที่ล้มเหลวสามารถส่งใหม่ได้จากหน้ารายละเอียดด้วย Retry Webhook มันจะส่ง payload เดิมไปยัง endpoint เดิมอีกครั้ง และบันทึกเป็นการส่งใหม่
ประวัติจะถูกเก็บไว้ 30 วัน จากนั้นจะถูกลบออกโดยอัตโนมัติ
การแก้ปัญหา
| Problem | Fix |
|---|---|
| ไม่สามารถบันทึก endpoint ได้ | URL ต้องเป็น https:// และ resolve ไปยังที่อยู่สาธารณะ |
| ทุกอย่างแสดงว่า failed โดยไม่มี response code | คำขอไม่เคยมาถึงคุณ — timeout, DNS ล้มเหลว หรือ connection refused |
| ลายเซ็นไม่ตรงเลย | คุณกำลัง hash body ที่ parse แล้วแทนไบต์ดิบ หรือไม่ได้ใส่ prefix timestamp + "." |
| การส่งหยุดไปหลังจากสักพัก | ตรวจดูว่า host ของคุณเริ่มส่งกลับ 4xx หรือไม่ — แบบนั้นจะไม่ถูก retry |
| อีเวนต์ไม่เคยเข้ามา | endpoint ไม่ได้ subscribe กับประเภทนั้น หรือเซิร์ฟเวอร์สูญเสียพรีเมียม |
| อีเวนต์ซ้ำ | เป็นเรื่องปกติเมื่อมี retry — ให้ deduplicate ด้วย X-TicketWave-Delivery |
ขั้นตอนถัดไป
- Event Reference (ทุกอีเวนต์และ payload ของมัน)
- Example Server (receiver แบบ Express ที่รันได้จริง)
- Log Channels (อีเวนต์เดียวกัน แต่โพสต์เข้า Discord)
How is this guide?
