Open in
ภาพรวม Webhook
วิธีที่ ThunderPhone ส่งมอบเหตุการณ์แบบเรียลไทม์ วิธีตรวจสอบลายเซ็น และการเปรียบเทียบโมเดลการส่งมอบแบบเดิมกับแบบอิงปลายทาง
ThunderPhone ส่งคำขอ HTTP POST ไปยังเซิร์ฟเวอร์ของคุณเมื่อมีเหตุการณ์
เกิดขึ้นระหว่างการโทร — สายเรียกเข้าเริ่มต้น สายสิ้นสุด การประเมิน
เสร็จสมบูรณ์ มีการแจ้งเตือน และอื่นๆ มีโมเดลการส่งข้อมูลสองแบบ:
หลาย URL ความลับแยกตามปลายทาง ตัวกรองเหตุการณ์แยกตามปลายทาง
และการลองส่งซ้ำอัตโนมัติ
จัดการผ่าน GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints
หนึ่ง URL ต่อองค์กร มีเหตุการณ์วงจรชีวิตการโทร รวมถึงการแลกเปลี่ยน
การกำหนดค่าที่ต้องรอผลลัพธ์ จัดการที่ GET/PUT /v1/webhook
ประเภทเหตุการณ์ทั้งหมดที่ระบุในแค็ตตาล็อกเหตุการณ์
จะถูกส่งผ่านปลายทาง webhook เหตุการณ์วงจรชีวิตการโทรทั้งหกรายการ
(telephony.incoming, telephony.complete, telephony.tool,
web.incoming, web.complete, web.tool) จะถูกส่งไปยัง webhook เดิมแบบ URL เดียว
ด้วย — หากคุณมีทั้ง URL เดิมและปลายทางที่ตรงกัน คุณจะได้รับเหตุการณ์ผ่าน
ทั้งสองเส้นทาง พฤติกรรมแบบต้องรอผลลัพธ์ (การแลกเปลี่ยนการกำหนดค่า
telephony.incoming / web.incoming และ
การเรียกใช้เครื่องมือในโหมด webhook)
มีอยู่เฉพาะบนเส้นทางเดิมเท่านั้น การส่งไปยังปลายทางทุกครั้งเป็น
การแจ้งเตือนแบบส่งแล้วไม่รอผลลัพธ์
รูปแบบเพย์โหลด
การส่งไปยังปลายทางเป็นออบเจ็กต์ JSON ที่มี data, event_id และ
type:
{
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
},
"event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
"type": "telephony.incoming"
}event_id ไม่ซ้ำกันสำหรับแต่ละเหตุการณ์ที่ส่งออก โดยจะเหมือนกันในการลองส่งซ้ำ
และในทุกปลายทางที่ได้รับเหตุการณ์ — ใช้ค่านี้เพื่อตัดรายการซ้ำ
webhook เดิมแบบ URL เดียวส่ง type และ data เดียวกัน แต่
ไม่มี event_id:
{
"type": "telephony.incoming",
"data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}ในการส่งจริง เนื้อหาทุกรายการจะถูกซีเรียลไลซ์แบบมาตรฐาน — คีย์เรียงตาม ตัวอักษร ไม่มีช่องว่าง ใช้ UTF-8 ตัวอย่างที่จัดรูปแบบให้อ่านง่ายใน เอกสารนี้มีไว้เพื่อให้อ่านง่ายเท่านั้น
ดูแค็ตตาล็อกเหตุการณ์สำหรับรายการประเภทเหตุการณ์ และฟิลด์เพย์โหลดทั้งหมด
การตรวจสอบลายเซ็น
ทุกคำขอมีลายเซ็นสองรายการ โดยทั้งสองรายการใช้ HMAC-SHA256 ที่คีย์ด้วย secret ของ
ปลายทาง (หรือ webhook secret ระดับองค์กรของคุณสำหรับการส่งแบบเดิม):
X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex>ลงลายเซ็นใน การประทับเวลา เมธอด พาธและคิวรี และเนื้อหาดิบ ตรวจสอบลายเซ็นนี้ และปฏิเสธคำขอที่มีtห่างจากเวลาของคุณเกิน 5 นาที เพื่อป้องกันไม่ให้นำคำขอที่ถูกดักจับไปเล่นซ้ำในภายหลัง ระบบจะลงลายเซ็นใหม่สำหรับการลองส่งซ้ำเมื่อมีการส่งX-ThunderPhone-Signatureลงลายเซ็นเฉพาะเนื้อหาดิบเท่านั้น ระบบยังคงส่งลายเซ็นนี้ โดยไม่มีการเปลี่ยนแปลง เพื่อให้ตัวตรวจสอบที่มีอยู่เดิมยังทำงานต่อไปได้
ขั้นตอน
- อ่านส่วนหัว เมธอด พาธและคิวรีแบบดิบ และเนื้อหาแบบดิบ ก่อน การแยกวิเคราะห์ใดๆ
- คำนวณ HMAC-SHA256 แบบฐานสิบหกของ
<t>\n<METHOD>\n<path and query>\n<body>โดยใช้ข้อมูลลับของคุณ - ปฏิเสธคำขอหาก
tคลาดเคลื่อนเกิน 300 วินาที หรือหากผลลัพธ์ ไม่ตรงกับv1ในการเปรียบเทียบแบบเวลาคงที่
เนื้อหาเป็นการซีเรียลไลซ์ JSON แบบมาตรฐาน (เรียงลำดับคีย์ ใช้ตัวคั่นแบบกระชับ) และเราลงนามไบต์ที่ส่งจริงทุกประการ คู่มือการตรวจสอบ มีสตริงที่ลงนามอย่างครบถ้วน ตัวอย่างการทำงาน โค้ดที่ไม่ใช้ SDK และส่วนหัวแบบเดิม
from flask import Flask, abort, request
from thunderphone import verify_signature
app = Flask(__name__)
@app.post("/thunderphone-webhook")
def handle():
query = request.query_string.decode()
if not verify_signature(
request.headers.get("X-ThunderPhone-Signature-V2"),
secret=WEBHOOK_SECRET,
method=request.method,
path=request.path + (f"?{query}" if query else ""),
body=request.get_data(), # raw bytes
):
abort(401)
event = request.get_json()
# dispatch on event["type"] …
return "", 204import express from "express";
import { verifySignature } from "@thunderphone/sdk";
const app = express();
app.post(
"/thunderphone-webhook",
express.raw({ type: "application/json" }),
(req, res) => {
const ok = verifySignature({
header: req.header("X-ThunderPhone-Signature-V2"),
secret: process.env.WEBHOOK_SECRET,
method: req.method,
path: req.originalUrl,
body: req.body,
});
if (!ok) return res.sendStatus(401);
const event = JSON.parse(req.body.toString("utf8"));
// dispatch on event.type …
res.sendStatus(204);
},
);ความหมายของการส่ง
ความหมายเหล่านี้ใช้กับการส่งไปยัง ปลายทาง เว็บฮุก URL เดียวแบบเดิมเป็นการพยายามแบบซิงโครนัสเพียงครั้งเดียวโดยไม่มีการลองใหม่ ยกเว้นการแลกเปลี่ยนการกำหนดค่าระหว่างการโทร telephony.incoming ซึ่งจะลองใหม่หนึ่งครั้ง
การลองใหม่
แต่ละอีเวนต์จะถูกพยายามส่งทันทีหนึ่งครั้ง การตอบกลับ 2xx ใดๆ จะยืนยันการส่ง สำหรับผลลัพธ์อื่นๆ ทั้งหมด (ไม่ใช่ 2xx ข้อผิดพลาดการเชื่อมต่อ หมดเวลา) เราจะลองใหม่ที่ 1 m, 5 m, 30 m, 2 h, 6 h, 12 h, and 24 h after the first attempt — รวม 8 ครั้งภายใน 24 ชั่วโมง หากทุกความพยายามล้มเหลว การส่งจะหยุดลงและปลายทางจะถูกทำเครื่องหมายเป็น status="failing" ในหน้า ปลายทางเว็บฮุก เราจะส่งอีเมลถึงเจ้าของและผู้ดูแลระบบขององค์กรคุณ และแสดงสถานะในแดชบอร์ด ส่งคืน 2xx ทันทีที่ยอมรับและจัดเก็บเพย์โหลดอย่างคงทน แล้วประมวลผลแบบอะซิงโครนัส
การส่งทดสอบจาก API ทดสอบปลายทางจะลองใหม่หนึ่งครั้งหลังจากความพยายามแรกประมาณหนึ่งนาที และจะไม่เปลี่ยนสถานะของปลายทาง
ลำดับ
ลำดับการส่งเป็นแบบพยายามอย่างดีที่สุด ในทางปฏิบัติ เราส่งตาม
ลำดับที่อีเวนต์ถูกปล่อยออกมา แต่การลองใหม่อาจทำให้ลำดับเปลี่ยนเมื่อเกิดความล้มเหลว
ให้ขจัดข้อมูลซ้ำและกระทบยอดโดยใช้ call_id / รหัสออบเจ็กต์เสมอ
รายการซ้ำ
การส่งเป็นแบบ อย่างน้อยหนึ่งครั้ง: การลองใหม่หลังจากการตอบกลับที่เราไม่เคย
เห็นอาจทำให้อีเวนต์ซ้ำได้ การลองใหม่ทุกครั้งมี
event_id เดียวกัน ดังนั้นให้จัดเก็บรหัสที่ประมวลผลแล้วและข้ามรายการซ้ำ event_id จะ
ใช้ร่วมกันระหว่างเอ็นด์พอยต์ด้วย — เอ็นด์พอยต์สองรายการที่สมัครรับ
อีเวนต์เดียวกันจะได้รับ event_id เดียวกัน
การหมดเวลา
การส่งไปยังปลายทางมีเวลาหมดเวลา 30 s ต่อความพยายามหนึ่งครั้ง ในเส้นทางแบบเดิม คำขอแบบบล็อกที่ขับเคลื่อนพฤติกรรมการโทรสด — การแลกเปลี่ยนการกำหนดค่า telephony.incoming / web.incoming — ถูกจำกัดไว้ที่ 10 s สำหรับความพยายามแรกของการโทร และ 13 s สำหรับการแลกเปลี่ยนทั้งหมดรวมการลองใหม่หนึ่งครั้ง และ 10 s สำหรับเซสชันวิดเจ็ต การตอบกลับที่ช้าจะทำให้การรับสายล่าช้า ดังนั้นควรตอบกลับภายในไม่กี่วินาที การเรียกใช้เครื่องมือในโหมดเว็บฮุกอนุญาตให้ใช้เวลา 20 s ตามค่าเริ่มต้น และการประกาศเครื่องมืออาจกำหนด timeout ระดับบนสุดได้
IP ต้นทาง
เว็บฮุกขาออกมาจากช่วง IP บนคลาวด์ของ ThunderPhone หากไฟร์วอลล์ของคุณต้องใช้รายการที่อนุญาต โปรดติดต่อฝ่ายสนับสนุน แล้วเราจะแชร์ ช่วงปัจจุบันให้
การเลือกระหว่างเว็บฮุกแบบเดิมและแบบอิงเอ็นด์พอยต์
| ฟีเจอร์ | แบบเดิม (/v1/webhook) | ปลายทาง (/v1/developer/webhook-endpoints) |
|---|---|---|
| จำนวน URL | 1 ต่อองค์กร | หลายรายการต่อองค์กร |
| ขอบเขตเหตุการณ์ | เฉพาะ telephony.* / web.* | เหตุการณ์ทั้ง 10 ประเภท |
| ตัวกรองเหตุการณ์ | — | แยกตามแต่ละปลายทาง |
| การลองใหม่ | ไม่มี ยกเว้น 1 ครั้งสำหรับการแลกเปลี่ยนการกำหนดค่าการโทร | 8 ครั้งภายใน 24 ชม. |
| เอนเวโลป | type + data | type + data + event_id |
| การหมุนเวียนซีเคร็ต | แทนที่ซีเคร็ตเดียว | ซีเคร็ตแยกตามปลายทาง |
| ปิดใช้งานโดยไม่ลบ | PUT /v1/webhook พร้อม {"url": ""} | status=disabled |
| การแสดงสถานะ | — | active / disabled / failing |
| การแลกเปลี่ยนการกำหนดค่าแบบบล็อก | มี (telephony.incoming / web.incoming) | ไม่มี — มีเฉพาะการแจ้งเตือน |
| เหมาะสำหรับ | การกำหนดค่าการโทรแบบไดนามิก | การรับเหตุการณ์ในระบบใช้งานจริง |
การเชื่อมต่อใหม่ควรรับอีเวนต์ผ่าน เว็บฮุกแบบอิงเอ็นด์พอยต์ เก็บ (หรือเพิ่ม) URL แบบเดิมไว้เฉพาะเมื่อคุณกำหนดค่าสายสนทนา แบบไดนามิกในเวลารับสาย หรือใช้การเรียกใช้เครื่องมือในโหมดเว็บฮุก — การแลกเปลี่ยน คำขอ/การตอบกลับเหล่านั้นทำงานบนเส้นทางเดิมเท่านั้น
ที่เกี่ยวข้อง
ประเภทเหตุการณ์ทั้งหมดและเพย์โหลดของเหตุการณ์เหล่านั้น
จัดการปลายทางหลายรายการ ตัวกรองเหตุการณ์ และความลับ
คำขอแบบบล็อกที่เซิร์ฟเวอร์ของคุณต้องตอบกลับเพื่อกำหนดค่าการโทร
เพย์โหลดหลังการโทรพร้อมข้อความถอดเสียง บันทึกเสียง และเมตริก