ThunderPhone 2.0 באוויר.בשירות עצמי, החל מ-2¢/דקה.קראו את הודעת ההשקה

Webhooks

סקירת Webhooks

כיצד ThunderPhone שולח אירועים בזמן אמת, כיצד לאמת חתימות, וכיצד מודלי המסירה המיושן ומבוסס נקודות הקצה משתווים.

ThunderPhone שולחת בקשות HTTP מסוג POST לשרת שלכם כאשר מתרחשים אירועים במהלך שיחה — שיחה נכנסת מתחילה, שיחה מסתיימת, הרצת דירוג מושלמת, התראה מופעלת וכן הלאה. קיימים שני מודלי מסירה:

כל עשרת סוגי האירועים בקטלוג האירועים נמסרים באמצעות נקודות קצה של 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 על גוף הבקשה הגולמי בכותרת X-ThunderPhone-Signature. מפתח החתימה הוא ה-secret של נקודת הקצה (או ה-secret של ה-webhook ברמת הארגון שלכם עבור מסירות מדור קודם).

שלבים

  1. קראו את גוף הבקשה הגולמי לפני כל ניתוח.
  2. חשבו את hmac_sha256(secret, body).hexdigest().
  3. השוו בזמן קבוע לכותרת X-ThunderPhone-Signature.

אנו חותמים בדיוק על הבתים שאנו שולחים, ובתים אלה הם סריאליזציית ה-JSON הקנונית (מפתחות ממוינים, מפרידים קומפקטיים). לכן אימות מול הגוף הגולמי תמיד פועל — ואם המסגרת שלכם מספקת רק JSON מנותח, סריאליזציה מחדש עם מפתחות ממוינים ומפרידים קומפקטיים מפיקה בתים זהים. שתי השיטות מתועדות במדריך האימות.

Python
import hmac
import hashlib
 
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature or "")
 
# Example Flask handler
from flask import Flask, request, abort
app = Flask(__name__)
 
@app.post("/thunderphone-webhook")
def handle():
    body = request.get_data()
    sig = request.headers.get("X-ThunderPhone-Signature", "")
    if not verify_signature(body, sig, WEBHOOK_SECRET):
        abort(401)
    event = request.get_json()
    # dispatch on event["type"] …
    return "", 204
Node.js (Express)
import crypto from "node:crypto";
import express from "express";
 
function verifySignature(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  if (!signature || expected.length !== signature.length) return false;
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature),
  );
}
 
const app = express();
app.post(
  "/thunderphone-webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const sig = req.header("X-ThunderPhone-Signature") || "";
    if (!verifySignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
      return res.sendStatus(401);
    }
    const event = JSON.parse(req.body.toString("utf8"));
    // dispatch on event.type …
    res.sendStatus(204);
  },
);

סמנטיקת מסירה

סמנטיקה זו חלה על מסירות אל נקודות קצה. הוובהוק הישן עם כתובת URL יחידה מבצע ניסיון סינכרוני יחיד ללא ניסיונות חוזרים.

ניסיונות חוזרים

כל אירוע נשלח מיד פעם אחת. כל תגובת 2xx מאשרת את המסירה. בכל תוצאה אחרת (שאינה 2xx, שגיאת חיבור, תפוגת זמן), ננסה שוב לאחר 1 דקה, 5 דקות, 30 דקות, שעתיים, 6 שעות, 12 שעות ו-24 שעות מהניסיון הראשון — 8 ניסיונות לאורך 24 שעות. אם כל הניסיונות נכשלים, המסירה נפסקת ונקודת הקצה מסומנת כ-status="failing" ב- נקודות קצה של וובהוקים. החזירו 2xx ברגע שהמטען התקבל באופן עמיד; עבדו אותו באופן אסינכרוני.

סדר

סדר המסירה הוא לפי מיטב המאמץ. בפועל אנו מוסרים אירועים לפי סדר הפליטה שלהם, אך ניסיונות חוזרים יכולים לשנות את הסדר במקרה של כישלון. תמיד הסירו כפילויות ובצעו התאמה לפי call_id / מזהה אובייקט.

כפילויות

המסירה היא לפחות פעם אחת: ניסיון חוזר לאחר תגובה שמעולם לא ראינו יכול ליצור אירוע כפול. כל ניסיון חוזר נושא את אותו event_id, לכן שמרו מזהים שעובדו ודלגו על חזרות. event_id הוא גם משותף בין נקודות קצה — שתי נקודות קצה שמנויות לאותו אירוע מקבלות את אותו event_id.

תפוגות זמן

למסירות לנקודות קצה יש תפוגת זמן של 30 שניות לכל ניסיון. בנתיב הישן, בקשות חוסמות שמניעות התנהגות של שיחה חיה — חילופי התצורה של telephony.incoming / web.incoming — מגיעות לתפוגת זמן לאחר 10 שניות, אך תגובה איטית מעכבת את המענה לשיחה, לכן שאפו להשיב בתוך כמה שניות. שיגור כלים במצב וובהוק שיגור כלים מאפשר 20 שניות כברירת מחדל, והצהרות כלים יכולות להגדיר timeout ברמה העליונה.

כתובות IP מקור

וובהוקים יוצאים מגיעים מטווח כתובות ה-IP בענן של ThunderPhone. אם חומת האש שלכם דורשת רשימת היתרים, פנו לתמיכה ונשתף את הטווחים העדכניים.

בחירה בין וובהוקים ישנים לוובהוקים מבוססי נקודות קצה

תכונהישן (/v1/webhook)נקודות קצה (/v1/developer/webhook-endpoints)
מספר כתובות URL1 לכל ארגוןרבות לכל ארגון
כיסוי אירועיםtelephony.* / web.* בלבדכל 10 סוגי האירועים
מסנן אירועיםלכל נקודת קצה
ניסיונות חוזריםללא8 ניסיונות לאורך 24 שעות
מעטפהtype + datatype + data + event_id
החלפת סודמחליפה סוד יחידסוד לכל נקודת קצה
השבתה ללא מחיקהstatus=disabled
נראות סטטוסactive / disabled / failing
חילופי תצורה חוסמיםכן (telephony.incoming / web.incoming)לעולם לא — התראות בלבד
מתאים במיוחד לתצורת שיחות דינמיתצריכת אירועים בייצור

אינטגרציות חדשות צריכות לצרוך אירועים דרך וובהוקים מבוססי נקודות קצה. השאירו (או הוסיפו) כתובת URL ישנה רק אם אתם מגדירים שיחות באופן דינמי בזמן המענה או משתמשים בשיגור כלים במצב וובהוק — חילופי בקשה/תגובה אלה פועלים רק בנתיב הישן.


קשור