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 بمفتاح هو secret الخاص بنقطة النهاية (أو secret الخاص بخطاف الويب على مستوى مؤسستك لعمليات التسليم القديمة):

  • يوقّع 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);
  },
);

دلالات التسليم

تنطبق هذه الدلالات على عمليات تسليم نقطة النهاية. إن webhook القديم ذي عنوان URL واحد هو محاولة متزامنة واحدة بلا إعادة محاولة، باستثناء تبادل إعدادات مكالمة الهاتف telephony.incoming الذي يُعاد مرة واحدة.

إعادة المحاولات

تتم محاولة كل حدث مرة واحدة فورًا. أي استجابة 2xx تُقِرّ بالتسليم. عند أي نتيجة أخرى (غير 2xx، خطأ في الاتصال، انتهاء المهلة)، نعيد المحاولة بعد المحاولة الأولى بـ 1 دقيقة، و5 دقائق، و30 دقيقة، وساعتين، و6 ساعات، و12 ساعة، و24 ساعة — 8 محاولات تمتد على مدار 24 ساعة. إذا فشلت كل محاولة، يتوقف التسليم وتُعلَّم نقطة النهاية بالقيمة status="failing" في نقاط نهاية webhook؛ ونرسل بريدًا إلكترونيًا إلى المالكين والمشرفين في مؤسستك ونعرض ذلك في لوحة التحكم. أعد 2xx بمجرد قبول الحمولة بشكل دائم؛ وعالجها بشكل غير متزامن. تحصل عمليات الإرسال الاختبارية من واجهة API لاختبار نقطة النهاية على إعادة محاولة واحدة بعد نحو دقيقة من المحاولة الأولى، ولا تغيّر حالة نقطة النهاية مطلقًا.

الترتيب

ترتيب التسليم هو بأفضل جهد. عمليًا، نُسلّم الأحداث بالترتيب الذي تُصدر به، لكن إعادة المحاولات قد تغيّر الترتيب عند الفشل. أزل التكرارات دائمًا وطابِق البيانات باستخدام call_id / معرّف الكائن.

التكرارات

التسليم مرة واحدة على الأقل: قد تؤدي إعادة المحاولة بعد استجابة لم نرها إلى تكرار حدث. تحمل كل إعادة محاولة المعرّف نفسه event_id، لذا خزّن المعرّفات التي عولجت وتخطَّ التكرارات. يُشارك event_id أيضًا بين نقاط النهاية — إذ تتلقى نقطتا نهاية مشتركتان في الحدث نفسه event_id نفسه.

انتهاء المهلات

تتضمن عمليات تسليم نقطة النهاية مهلة قدرها 30 ثانية لكل محاولة. في المسار القديم، تقتصر الطلبات الحاجبة التي تتحكم في سلوك المكالمة الحية — أي تبادل الإعدادات telephony.incoming / web.incoming — على 10 ثوانٍ للمحاولة الأولى لمكالمة هاتفية و13 ثانية للتبادل كاملًا، بما في ذلك إعادة المحاولة الواحدة، وعلى 10 ثوانٍ لجلسة أداة مصغّرة. تؤخر الاستجابة البطيئة الرد على المكالمة، لذا احرص على الاستجابة خلال ثانيتين تقريبًا. يتيح إرسال الأدوات في وضع webhook مدة 20 ثانية افتراضيًا، ويمكن لتعريفات الأدوات تعيين timeout على المستوى الأعلى.

عناوين IP المصدر

تنشأ عمليات webhook الصادرة من نطاق عناوين IP السحابية لـ ThunderPhone. إذا كان جدار الحماية لديك يتطلب قائمة سماح، فاتصل بالدعم وسنشاركك النطاقات الحالية.

الاختيار بين عمليات webhook القديمة وتلك المستندة إلى نقاط النهاية

الميزةالقديم (/v1/webhook)نقاط النهاية (/v1/developer/webhook-endpoints)
عدد عناوين URL1 لكل مؤسسةعدة عناوين لكل مؤسسة
تغطية الأحداثtelephony.* / web.* فقطجميع أنواع الأحداث العشرة
تصفية الأحداث—لكل نقطة نهاية
عمليات إعادة المحاولةلا توجد، باستثناء واحدة لتبادل إعدادات المكالمة الهاتفية8 محاولات خلال 24 ساعة
الغلافtype + datatype + data + event_id
تدوير السريستبدل السر المفردسر لكل نقطة نهاية
التعطيل دون حذفPUT /v1/webhook مع {"url": ""}status=disabled
إظهار الحالة—active / disabled / failing
تبادل الإعدادات الحاجبنعم (telephony.incoming / web.incoming)مطلقًا — إشعارات فقط
الأنسب لـإعداد المكالمات الديناميكياستهلاك الأحداث في بيئة الإنتاج

ينبغي لعمليات التكامل الجديدة استهلاك الأحداث عبر عمليات webhook المستندة إلى نقاط النهاية. احتفظ بعنوان URL قديم (أو أضفه) فقط إذا كنت تضبط المكالمات بشكل ديناميكي عند وقت الرد أو تستخدم إرسال الأدوات في وضع webhook — فتبادلات الطلب/الاستجابة هذه لا تعمل إلا عبر المسار القديم.


ذو صلة