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 יחידה — אם יש לכם גם כתובת מדור קודם וגם נקודת קצה תואמת, תקבלו את האירוע בשני הנתיבים גם יחד. ההתנהגות החוסמת (חילוף התצורה של 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 של נקודת הקצה (או על ה־secret של ה־webhook ברמת הארגון שלכם עבור מסירות מדור קודם):

  • X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex> חותמת על חותמת הזמן, השיטה, הנתיב והשאילתה, ועל הגוף הגולמי. אמתו חתימה זו, ודחו בקשות שה־t שלהן מרוחק ביותר מ־5 דקות משעון המערכת שלכם, כדי שלא ניתן יהיה להפעיל מחדש בקשה שנלכדה מאוחר יותר. ניסיונות חוזרים נחתמים מחדש בעת שליחתם.
  • X-ThunderPhone-Signature חותמת על הגוף הגולמי בלבד. היא עדיין נשלחת ללא שינוי, כדי שמאמתים קיימים ימשיכו לפעול.

שלבים

  1. קראו את הכותרת, את השיטה, את הנתיב ואת השאילתה הגולמיים, ואת הגוף הגולמי לפני כל ניתוח.
  2. חשבו את ערך ה-HMAC-SHA256 ההקסדצימלי של <t>\n<METHOD>\n<path and query>\n<body> באמצעות הסוד שלכם.
  3. דחו את הבקשה אם t חורג ביותר מ-300 שניות, או אם התוצאה אינה תואמת ל-v1 בהשוואה בזמן קבוע.

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

Python (Flask)
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 "", 204
Node.js (Express)
import 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, ו-24 h מהניסיון הראשון — 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)
מספר כתובות URL1 לכל ארגוןרבות לכל ארגון
כיסוי אירועיםtelephony.* / web.* בלבדכל 10 סוגי האירועים
סינון אירועים—לכל נקודת קצה
ניסיונות חוזריםללא, למעט ניסיון חוזר אחד עבור החלפת תצורת שיחת טלפון8 ניסיונות לאורך 24 שעות
מעטפהtype + datatype + data + event_id
החלפת סודמחליף סוד יחידסוד לכל נקודת קצה
השבתה ללא מחיקהPUT /v1/webhook עם {"url": ""}status=disabled
נראות סטטוס—active / disabled / failing
החלפת תצורה חוסמתכן (telephony.incoming / web.incoming)לעולם לא — התראות בלבד
המתאים ביותר עבורתצורת שיחות דינמיתצריכת אירועים בייצור

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


קשורים