Skip to content

Webhooks

Webhook จะส่งเหตุการณ์ไปยังเซิร์ฟเวอร์ของคุณทันทีที่เกิดขึ้น แทนที่จะให้คุณคอย polling ข้อมูล จัดการ endpoint ได้จาก ตั้งค่าองค์กร → Webhooks ในแดชบอร์ด หรือผ่าน /api/v1/webhooks ด้วยคีย์ที่มี scope write:webhooks

การลงทะเบียน endpoint

Section titled “การลงทะเบียน endpoint”
POST /api/v1/webhooks
Content-Type: application/json
Idempotency-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) ไม่ใช่รับไว้เฉยๆ แล้วไม่เคยส่งจริง

เนื้อหาการส่งทุกครั้งจะอยู่ใน 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.createdconversationId, channelId, externalUserId
message.receivedconversationId, messageId, role (user|assistant|agent|system)
handoff.requestedconversationId, escalationLogId, reason?
ticket.createdticketId, conversationId?, reason?
conversation.resolvedconversationId, resolvedBy

ตรวจสอบ type กับประเภทเหตุการณ์ที่คุณจัดการจริงเสมอ และตรวจสอบ schemaVersion หากคุณดูแล handler สำหรับ payload หลายรูปแบบในอนาคต

การรับประกันการส่ง

Section titled “การรับประกันการส่ง”

การส่งเป็นแบบ at-least-once (อย่างน้อยหนึ่งครั้ง) — ออกแบบระบบของคุณให้รองรับการจัดการแบบ idempotent (ยึดจากเหตุการณ์ ไม่ใช่ “ได้รับเรียกพอดีครั้งเดียวหรือไม่”)

  1. เหตุการณ์จะถูกบันทึกอย่างถาวรก่อน แยกออกจากการส่งจริง — การล่มระหว่าง “เหตุการณ์เกิดขึ้น” กับ “ส่ง webhook” จะไม่ทำให้เหตุการณ์หายไป
  2. เหตุการณ์จะถูกกระจายออกเป็นหนึ่งการส่งต่อ endpoint ที่ยังใช้งานอยู่และสมัครรับแต่ละราย
  3. การส่งแต่ละครั้งจะดำเนินการโดย worker ที่มีการเช่า (lease) — หาก worker ล่มระหว่างการส่ง lease จะหมดอายุและ worker อื่นจะเข้ามารับช่วงต่ออย่างปลอดภัย คุณจะไม่มีทางเห็นการส่งหายไปเงียบๆ เพราะ worker ล่ม แม้ในบางครั้งอาจเห็นการส่งเดียวกันถูกพยายามส่งซ้ำสองครั้งในช่วงเวลาที่ล่มพอดี — หากเรื่องนี้สำคัญกับคุณ ให้ใช้ id/eventId ของการส่งเป็นตัวช่วยกันข้อมูลซ้ำ

นโยบายการลองใหม่

Section titled “นโยบายการลองใหม่”
คุณสมบัติค่า
จำนวนครั้งสูงสุดต่อการส่ง8
BackoffExponential — เริ่มที่ 30 วินาที เพิ่มเป็นสองเท่าทุกครั้ง สูงสุด 1 ชั่วโมง
สถานะสุดท้ายsucceeded, exhausted (ครบจำนวนครั้งสูงสุด), skipped (endpoint ถูกปิดใช้งาน)

endpoint ที่ล้มเหลวติดต่อกัน 10 ครั้ง จะถูกปิดใช้งานอัตโนมัติ (status: "auto_disabled") — เหตุการณ์ถัดไปจะถูกทำเครื่องหมาย skipped สำหรับ endpoint นั้น แทนที่จะพยายามส่งซ้ำไปยังปลายทางที่ตายแล้วตลอดไป เปิดใช้งานใหม่ได้โดยลงทะเบียน endpoint ใหม่ (หรือติดต่อฝ่ายสนับสนุนหากต้องการให้ endpoint เดิมกลับมาทำงาน)

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}/test
Idempotency-Key: <uuid>

ส่งเหตุการณ์ webhook.test จริงผ่านเส้นทางการเซ็นลายเซ็นและส่งข้อมูลจริงไปยัง endpoint นั้นเพียงตัวเดียว — มีประโยชน์สำหรับตรวจสอบการตรวจสอบลายเซ็น ที่ปลายทางของคุณก่อนสมัครรับเหตุการณ์จริง

DELETE /api/v1/webhooks/{id}

การลบ endpoint ที่ถูกลบไปแล้วจะได้ 204 — ถือเป็นการไม่ทำอะไรเลย ไม่ใช่ข้อผิดพลาด ดังนั้นการลองซ้ำจึงปลอดภัยเสมอ

การหมุนเวียน Secret ของ Webhook

Section titled “การหมุนเวียน Secret ของ Webhook”

ไม่มีการ “หมุนเวียน secret” แบบแก้ไขในที่เดิม — secret ผูกกับ endpoint ที่ออกให้ วิธีหมุนเวียน:

  1. ลงทะเบียน endpoint ใหม่ ด้วย url และ events เดียวกัน
  2. ตรวจสอบว่า endpoint ใหม่รับและตรวจสอบเหตุการณ์ทดสอบได้ถูกต้อง
  3. ลบ endpoint เก่า