ThunderPhone 2.0 এখন লাইভ।নিজেই ব্যবহার শুরু করুন, 2¢/মিনিট থেকে।ঘোষণাটি পড়ুন

Webhooks

Webhooks-এর সারসংক্ষেপ

ThunderPhone কীভাবে রিয়েল-টাইম ইভেন্ট সরবরাহ করে, কীভাবে সিগনেচার যাচাই করবেন এবং লিগ্যাসি ও এন্ডপয়েন্ট-ভিত্তিক ডেলিভারি মডেলগুলোর তুলনা।

ThunderPhone কোনো কলে ঘটনা ঘটলে আপনার সার্ভারে HTTP POST অনুরোধ পাঠায় — ইনবাউন্ড কল শুরু হয়, কল শেষ হয়, গ্রেডিং রান সম্পন্ন হয়, একটি অ্যালার্ট সক্রিয় হয়, ইত্যাদি। এখানে দুটি ডেলিভারি মডেল রয়েছে:

ইভেন্ট ক্যাটালগে তালিকাভুক্ত সব ইভেন্ট টাইপ webhook এন্ডপয়েন্টের মাধ্যমে ডেলিভার করা হয়। ছয়টি কল-লাইফসাইকেল ইভেন্ট (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) লিগ্যাসি একক-URL webhook-এও পাঠানো হয় — আপনার যদি একটি লিগ্যাসি URL এবং একটি মিলিত এন্ডপয়েন্ট থাকে, তবে আপনি উভয় পাথেই ইভেন্টটি পাবেন। ব্লকিং আচরণ (the telephony.incoming / web.incoming কনফিগারেশন এক্সচেঞ্জ এবং webhook-মোড টুল ডিসপ্যাচ) একচেটিয়াভাবে লিগ্যাসি পাথে থাকে; প্রতিটি এন্ডপয়েন্ট ডেলিভারি ফায়ার-অ্যান্ড-ফরগেট নোটিফিকেশন।

পেলোড ফরম্যাট

এন্ডপয়েন্ট ডেলিভারি হলো data, event_id, এবং type-সহ একটি JSON অবজেক্ট:

{
  "data": {
    "call_id": 987654321,
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  },
  "event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
  "type": "telephony.incoming"
}

event_id প্রতিটি নির্গত ইভেন্টের জন্য অনন্য। এটি রিট্রাইয়ের এবং ইভেন্ট গ্রহণকারী প্রতিটি এন্ডপয়েন্টজুড়ে একই থাকে — এটি দিয়ে ডিডুপ করুন।

লিগ্যাসি একক-URL webhook একই type এবং data পাঠায়, কিন্তু event_id ছাড়া:

{
  "type": "telephony.incoming",
  "data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}

নেটওয়ার্কে, প্রতিটি বডি ক্যানোনিক্যালভাবে সিরিয়ালাইজ করা হয় — কী বর্ণানুক্রমে সাজানো থাকে, কোনো হোয়াইটস্পেস থাকে না, UTF-8। এই ডকুমেন্টেশনের সুন্দরভাবে ফরম্যাট করা উদাহরণগুলো শুধু পাঠযোগ্যতার জন্য।

ইভেন্ট টাইপ এবং পেলোড ফিল্ডের সম্পূর্ণ তালিকার জন্য ইভেন্ট ক্যাটালগ দেখুন।

স্বাক্ষর যাচাইকরণ

প্রতিটি রিকোয়েস্টে দুটি স্বাক্ষর থাকে, উভয়ই এন্ডপয়েন্টের secret (অথবা লিগ্যাসি ডেলিভারির জন্য আপনার সংস্থা-স্তরের webhook secret) দিয়ে কী করা HMAC-SHA256:

  • X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex> টাইমস্ট্যাম্প, মেথড, পাথ ও কোয়েরি এবং র' বডিতে স্বাক্ষর করে। এটি যাচাই করুন এবং যেসব রিকোয়েস্টের t আপনার ঘড়ির সময় থেকে 5 মিনিটের বেশি দূরে, সেগুলো প্রত্যাখ্যান করুন, যাতে ধারণ করা কোনো রিকোয়েস্ট পরে পুনরায় চালানো না যায়। পাঠানোর সময় রিট্রাইগুলোতে আবার স্বাক্ষর করা হয়।
  • X-ThunderPhone-Signature শুধু র' বডিতে স্বাক্ষর করে। বিদ্যমান ভেরিফায়ারগুলো কাজ করতে পারে বলে এটি অপরিবর্তিত অবস্থায় এখনও পাঠানো হয়।

ধাপসমূহ

  1. পার্সিংয়ের আগে হেডার, মেথড, অপরিবর্তিত path ও query, এবং অপরিবর্তিত body পড়ুন।
  2. আপনার secret ব্যবহার করে <t>\n<METHOD>\n<path and query>\n<body>-এর হেক্স HMAC-SHA256 গণনা করুন।
  3. t 300 সেকেন্ডের বেশি ব্যবধান হলে, অথবা ফলাফলটি constant-time তুলনায় v1-এর সঙ্গে না মিললে অনুরোধটি প্রত্যাখ্যান করুন।

Body হলো ক্যানোনিকাল JSON serialization (সাজানো key, সংক্ষিপ্ত separator), এবং আমরা যে byte প্রেরণ করি ঠিক সেগুলোতেই স্বাক্ষর করি। যাচাইকরণ নির্দেশিকা-এ সঠিক স্বাক্ষরিত স্ট্রিং, একটি কার্যকর উদাহরণ, SDK ছাড়া কোড এবং পুরোনো header রয়েছে।

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 প্রতিক্রিয়া ডেলিভারি স্বীকার করে। অন্য যেকোনো ফলাফলে (non-2xx, সংযোগ ত্রুটি, টাইমআউট), প্রথম প্রচেষ্টার পর 1 মিনিট, 5 মিনিট, 30 মিনিট, 2 ঘণ্টা, 6 ঘণ্টা, 12 ঘণ্টা এবং 24 ঘণ্টায় আমরা পুনঃচেষ্টা করি — 24 ঘণ্টাজুড়ে 8টি প্রচেষ্টা। প্রতিটি প্রচেষ্টা ব্যর্থ হলে, ডেলিভারি বন্ধ হয়ে যায় এবং এন্ডপয়েন্টকে ওয়েবহুক এন্ডপয়েন্ট-এ status="failing" হিসেবে চিহ্নিত করা হয়; আমরা আপনার প্রতিষ্ঠানের মালিক ও অ্যাডমিনদের ইমেইল করি এবং ড্যাশবোর্ডে তা দেখাই। পেলোড স্থায়ীভাবে গৃহীত হওয়ার সঙ্গে সঙ্গে 2xx ফেরত দিন; অ্যাসিঙ্ক্রোনাসভাবে প্রক্রিয়া করুন। এন্ডপয়েন্ট পরীক্ষা API থেকে পাঠানো পরীক্ষামূলক অনুরোধ প্রথম প্রচেষ্টার প্রায় এক মিনিট পরে একবার পুনঃচেষ্টা পায় এবং কখনোই এন্ডপয়েন্টের স্থিতি পরিবর্তন করে না।

ক্রম

ডেলিভারির ক্রম সর্বোত্তম প্রচেষ্টাভিত্তিক। বাস্তবে, ইভেন্টগুলো যে ক্রমে প্রকাশিত হয় আমরা সেই ক্রমেই ডেলিভার করি, তবে ব্যর্থতার ক্ষেত্রে রিট্রাই ক্রম বদলে দিতে পারে। সবসময় call_id / অবজেক্ট id অনুযায়ী ডিডুপ এবং রিকনসাইল করুন।

ডুপ্লিকেট

ডেলিভারি অন্তত-একবার: আমরা যে রেসপন্স কখনো পাইনি, তার পরের রিট্রাই একটি ইভেন্ট ডুপ্লিকেট করতে পারে। প্রতিটি রিট্রাই একই event_id বহন করে, তাই প্রক্রিয়াকৃত id সংরক্ষণ করুন এবং পুনরাবৃত্তি এড়িয়ে যান। event_id এন্ডপয়েন্টজুড়েও শেয়ার করা হয় — একই ইভেন্টে সাবস্ক্রাইব করা দুটি এন্ডপয়েন্ট একই event_id পায়।

টাইমআউট

এন্ডপয়েন্ট ডেলিভারিতে প্রতিটি প্রচেষ্টার জন্য 30 সেকেন্ড টাইমআউট থাকে। লিগ্যাসি পথে, লাইভ কলের আচরণ নিয়ন্ত্রণকারী ব্লকিং অনুরোধগুলো — অর্থাৎ telephony.incoming / web.incoming কনফিগারেশন বিনিময় — ফোন কলের প্রথম প্রচেষ্টার জন্য 10 সেকেন্ডে এবং একবারের পুনঃচেষ্টাসহ সম্পূর্ণ বিনিময়ের জন্য 13 সেকেন্ডে সীমিত, আর একটি উইজেট সেশনের জন্য 10 সেকেন্ডে সীমিত। ধীর প্রতিক্রিয়া কল গ্রহণে বিলম্ব ঘটায়, তাই কয়েক সেকেন্ডের মধ্যে উত্তর দেওয়ার লক্ষ্য রাখুন। ওয়েবহুক-মোডে টুল ডিসপ্যাচ ডিফল্টভাবে 20 সেকেন্ড অনুমোদন করে, এবং টুল ঘোষণাগুলি শীর্ষ-স্তরের timeout সেট করতে পারে।

সোর্স IP

আউটবাউন্ড ওয়েবহুক ThunderPhone-এর ক্লাউড IP রেঞ্জ থেকে আসে। আপনার ফায়ারওয়ালে allowlist প্রয়োজন হলে, সাপোর্টের সঙ্গে যোগাযোগ করুন এবং আমরা বর্তমান রেঞ্জগুলো শেয়ার করব।

লিগ্যাসি এবং এন্ডপয়েন্ট-ভিত্তিক ওয়েবহুকের মধ্যে নির্বাচন

বৈশিষ্ট্যলিগ্যাসি (/v1/webhook)এন্ডপয়েন্ট (/v1/developer/webhook-endpoints)
URL-এর সংখ্যাপ্রতি প্রতিষ্ঠানে 1টিপ্রতি প্রতিষ্ঠানে একাধিক
ইভেন্ট কভারেজশুধু telephony.* / web.*সব 10 ধরনের ইভেন্ট
ইভেন্ট ফিল্টার—প্রতি এন্ডপয়েন্টে
পুনঃচেষ্টাফোন-কল কনফিগারেশন বিনিময়ের জন্য একটি ছাড়া কোনোটি নয়24 ঘণ্টায় 8টি প্রচেষ্টা
এনভেলপtype + datatype + data + event_id
সিক্রেট রোটেশনএকক সিক্রেট প্রতিস্থাপন করেপ্রতি এন্ডপয়েন্টে সিক্রেট
মুছে না দিয়ে নিষ্ক্রিয় করাPUT /v1/webhook সহ {"url": ""}status=disabled
স্ট্যাটাস দৃশ্যমানতা—active / disabled / failing
ব্লকিং কনফিগারেশন বিনিময়হ্যাঁ (telephony.incoming / web.incoming)কখনোই নয় — শুধু নোটিফিকেশন
এর জন্য সেরাডায়নামিক কল কনফিগারেশনপ্রোডাকশনে ইভেন্ট গ্রহণ

নতুন ইন্টিগ্রেশনগুলোকে এন্ডপয়েন্ট-ভিত্তিক ওয়েবহুকের মাধ্যমে ইভেন্ট গ্রহণ করা উচিত। কেবল তখনই একটি লিগ্যাসি URL রাখুন (বা যোগ করুন), যখন আপনি কল গ্রহণের সময় ডায়নামিকভাবে কল কনফিগার করেন অথবা ওয়েবহুক-মোড টুল ডিসপ্যাচ ব্যবহার করেন — এই রিকোয়েস্ট/রেসপন্স এক্সচেঞ্জগুলো শুধু লিগ্যাসি পাথেই চলে।


সম্পর্কিত