Webhooks
Webhooks
Section titled “Webhooks”Webhook จะส่งเหตุการณ์ไปยังเซิร์ฟเวอร์ของคุณทันทีที่เกิดขึ้น แทนที่จะให้คุณคอย polling ข้อมูล จัดการ endpoint ได้จาก ตั้งค่าองค์กร → Webhooks ในแดชบอร์ด หรือผ่าน /api/v1/webhooks ด้วยคีย์ที่มี scope write:webhooks
การลงทะเบียน endpoint
Section titled “การลงทะเบียน endpoint”POST /api/v1/webhooksContent-Type: application/jsonIdempotency-Key: <uuid>
{ "url": "https://example.com/hooks/clienta", "events": ["conversation.created", "message.received"]}{ "success": true, "data": { "id": "wh_endpoint_123", "url": "https://example.com/hooks/clienta", "events": ["conversation.created", "message.received"], "status": "active", "consecutiveFailures": 0, "createdAt": "2026-07-16T04:00:00.000Z", "secret": "3n9qYVs8h1kLp0..." }}การลงทะเบียนด้วย POST /api/v1/webhooks ต้องมี header Idempotency-Key — ดู ความเป็น Idempotent
ประเภทเหตุการณ์
Section titled “ประเภทเหตุการณ์”| เหตุการณ์ | เกิดขึ้นเมื่อ |
|---|---|
conversation.created | มีการเริ่มบทสนทนาใหม่ |
message.received | มีข้อความใหม่เข้ามาในบทสนทนา |
handoff.requested | บทสนทนาถูกยกระดับให้เจ้าหน้าที่มนุษย์ดูแล |
ticket.created | มีการสร้าง fallback ticket |
conversation.resolved | บทสนทนาถูกทำเครื่องหมายว่าแก้ไขแล้ว |
endpoint จะได้รับเฉพาะเหตุการณ์ที่สมัครรับผ่านรายการ events เท่านั้น — ไม่มีการสมัครรับแบบ wildcard ชื่อเหตุการณ์ที่พิมพ์ผิดจะถูกปฏิเสธตั้งแต่ตอนลงทะเบียน (400) ไม่ใช่รับไว้เฉยๆ แล้วไม่เคยส่งจริง
รูปแบบ Payload
Section titled “รูปแบบ Payload”เนื้อหาการส่งทุกครั้งจะอยู่ใน envelope ที่มีเวอร์ชันกำกับ:
{ "type": "conversation.created", "schemaVersion": 1, "orgId": "org_abc123", "createdAt": "2026-07-16T04:00:00.000Z", "data": { "conversationId": "conv_456", "channelId": "chan_789", "externalUserId": "ext_user_1" }}data เป็น allowlist เฉพาะแต่ละประเภทเหตุการณ์อย่างเข้มงวด — จะมีเฉพาะฟิลด์ที่ระบุไว้ด้านล่างเท่านั้น ไม่ว่าข้อมูลภายในจริงจะมีฟิลด์อื่นอีกเท่าใดก็ตาม
| เหตุการณ์ | ฟิลด์ใน data |
|---|---|
conversation.created | conversationId, channelId, externalUserId |
message.received | conversationId, messageId, role (user|assistant|agent|system) |
handoff.requested | conversationId, escalationLogId, reason? |
ticket.created | ticketId, conversationId?, reason? |
conversation.resolved | conversationId, resolvedBy |
ตรวจสอบ type กับประเภทเหตุการณ์ที่คุณจัดการจริงเสมอ และตรวจสอบ schemaVersion หากคุณดูแล handler สำหรับ payload หลายรูปแบบในอนาคต
การรับประกันการส่ง
Section titled “การรับประกันการส่ง”การส่งเป็นแบบ at-least-once (อย่างน้อยหนึ่งครั้ง) — ออกแบบระบบของคุณให้รองรับการจัดการแบบ idempotent (ยึดจากเหตุการณ์ ไม่ใช่ “ได้รับเรียกพอดีครั้งเดียวหรือไม่”)
- เหตุการณ์จะถูกบันทึกอย่างถาวรก่อน แยกออกจากการส่งจริง — การล่มระหว่าง “เหตุการณ์เกิดขึ้น” กับ “ส่ง webhook” จะไม่ทำให้เหตุการณ์หายไป
- เหตุการณ์จะถูกกระจายออกเป็นหนึ่งการส่งต่อ endpoint ที่ยังใช้งานอยู่และสมัครรับแต่ละราย
- การส่งแต่ละครั้งจะดำเนินการโดย worker ที่มีการเช่า (lease) — หาก worker ล่มระหว่างการส่ง lease จะหมดอายุและ worker อื่นจะเข้ามารับช่วงต่ออย่างปลอดภัย คุณจะไม่มีทางเห็นการส่งหายไปเงียบๆ เพราะ worker ล่ม แม้ในบางครั้งอาจเห็นการส่งเดียวกันถูกพยายามส่งซ้ำสองครั้งในช่วงเวลาที่ล่มพอดี — หากเรื่องนี้สำคัญกับคุณ ให้ใช้
id/eventIdของการส่งเป็นตัวช่วยกันข้อมูลซ้ำ
นโยบายการลองใหม่
Section titled “นโยบายการลองใหม่”| คุณสมบัติ | ค่า |
|---|---|
| จำนวนครั้งสูงสุดต่อการส่ง | 8 |
| Backoff | Exponential — เริ่มที่ 30 วินาที เพิ่มเป็นสองเท่าทุกครั้ง สูงสุด 1 ชั่วโมง |
| สถานะสุดท้าย | succeeded, exhausted (ครบจำนวนครั้งสูงสุด), skipped (endpoint ถูกปิดใช้งาน) |
endpoint ที่ล้มเหลวติดต่อกัน 10 ครั้ง จะถูกปิดใช้งานอัตโนมัติ (status: "auto_disabled") — เหตุการณ์ถัดไปจะถูกทำเครื่องหมาย skipped สำหรับ endpoint นั้น แทนที่จะพยายามส่งซ้ำไปยังปลายทางที่ตายแล้วตลอดไป เปิดใช้งานใหม่ได้โดยลงทะเบียน endpoint ใหม่ (หรือติดต่อฝ่ายสนับสนุนหากต้องการให้ endpoint เดิมกลับมาทำงาน)
ประวัติการส่ง
Section titled “ประวัติการส่ง”GET /api/v1/webhooks/{id}/deliveries?limit=20{ "success": true, "data": [ { "id": "whd_1", "eventId": "evt_1", "status": "succeeded", "nextRetryAt": null, "terminalAt": "2026-07-16T04:00:02.000Z", "terminalReason": null, "lastError": null, "createdAt": "2026-07-16T04:00:00.000Z" } ], "nextCursor": null}แบ่งหน้าแบบ cursor — ดู การกำหนดเวอร์ชัน → การแบ่งหน้า
การส่งเหตุการณ์ทดสอบ
Section titled “การส่งเหตุการณ์ทดสอบ”POST /api/v1/webhooks/{id}/testIdempotency-Key: <uuid>ส่งเหตุการณ์ webhook.test จริงผ่านเส้นทางการเซ็นลายเซ็นและส่งข้อมูลจริงไปยัง endpoint นั้นเพียงตัวเดียว — มีประโยชน์สำหรับตรวจสอบการตรวจสอบลายเซ็น ที่ปลายทางของคุณก่อนสมัครรับเหตุการณ์จริง
การลบ endpoint
Section titled “การลบ endpoint”DELETE /api/v1/webhooks/{id}การลบ endpoint ที่ถูกลบไปแล้วจะได้ 204 — ถือเป็นการไม่ทำอะไรเลย ไม่ใช่ข้อผิดพลาด ดังนั้นการลองซ้ำจึงปลอดภัยเสมอ
การหมุนเวียน Secret ของ Webhook
Section titled “การหมุนเวียน Secret ของ Webhook”ไม่มีการ “หมุนเวียน secret” แบบแก้ไขในที่เดิม — secret ผูกกับ endpoint ที่ออกให้ วิธีหมุนเวียน:
- ลงทะเบียน endpoint ใหม่ ด้วย
urlและeventsเดียวกัน - ตรวจสอบว่า endpoint ใหม่รับและตรวจสอบเหตุการณ์ทดสอบได้ถูกต้อง
- ลบ endpoint เก่า