ThunderPhone 2.0 kini resmi hadir.Gunakan langsung secara mandiri, mulai 2¢/menit.Baca pengumumannya

Webhooks

Ringkasan Webhook

Cara ThunderPhone mengirimkan peristiwa secara real-time, cara memverifikasi tanda tangan, serta perbandingan model pengiriman lama dan berbasis endpoint.

ThunderPhone mengirim permintaan HTTP POST ke server Anda ketika peristiwa terjadi selama panggilan — panggilan masuk dimulai, panggilan berakhir, proses penilaian selesai, peringatan dipicu, dan sebagainya. Ada dua model pengiriman:

Semua jenis peristiwa yang tercantum dalam katalog peristiwa dikirimkan melalui endpoint webhook. Enam peristiwa siklus hidup panggilan (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) juga dikirim ke webhook lama satu URL — jika Anda memiliki URL lama dan endpoint yang sesuai, Anda menerima peristiwa di kedua jalur. Perilaku pemblokiran (pertukaran konfigurasi telephony.incoming / web.incoming dan pengiriman tool mode webhook) hanya tersedia pada jalur lama; setiap pengiriman endpoint adalah notifikasi tanpa menunggu respons.

Format payload

Pengiriman endpoint berupa objek JSON dengan data, event_id, dan type:

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

event_id bersifat unik untuk setiap peristiwa yang diterbitkan. Nilainya sama pada percobaan ulang dan pada setiap endpoint yang menerima peristiwa tersebut — lakukan deduplikasi berdasarkan ID ini.

Webhook lama satu URL mengirim type dan data yang sama, tetapi tanpa event_id:

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

Dalam transmisi, setiap body diserialisasi secara kanonis — kunci diurutkan secara alfabetis, tanpa spasi kosong, UTF-8. Contoh yang ditampilkan dengan format rapi dalam dokumentasi ini hanya untuk keterbacaan.

Lihat Katalog peristiwa untuk daftar lengkap jenis peristiwa dan field payload.

Verifikasi tanda tangan

Setiap permintaan membawa dua tanda tangan, keduanya HMAC-SHA256 yang menggunakan secret endpoint sebagai kunci (atau secret webhook tingkat organisasi Anda untuk pengiriman lama):

  • X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex> menandatangani stempel waktu, metode, jalur dan kueri, serta body mentah. Verifikasi tanda tangan ini, dan tolak permintaan yang t-nya lebih dari 5 menit dari waktu Anda agar permintaan yang ditangkap tidak dapat diputar ulang nanti. Percobaan ulang ditandatangani kembali saat dikirim.
  • X-ThunderPhone-Signature hanya menandatangani body mentah. Tanda tangan ini tetap dikirim tanpa perubahan agar verifier yang sudah ada tetap berfungsi.

Langkah

  1. Baca header, metode, jalur dan kueri mentah, serta body mentah sebelum penguraian apa pun.
  2. Hitung HMAC-SHA256 heksadesimal dari <t>\n<METHOD>\n<path and query>\n<body> menggunakan secret Anda.
  3. Tolak permintaan jika t meleset lebih dari 300 detik, atau jika hasilnya tidak cocok dengan v1 dalam perbandingan waktu konstan.

Body adalah serialisasi JSON kanonis (kunci diurutkan, pemisah ringkas), dan kami menandatangani tepat byte yang kami kirimkan. Panduan verifikasi memiliki string yang ditandatangani secara tepat, contoh lengkap, kode tanpa SDK, dan header lama.

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);
  },
);

Semantik pengiriman

Semantik ini berlaku untuk pengiriman endpoint. Webhook lama dengan satu URL adalah satu upaya sinkron tanpa percobaan ulang, kecuali pertukaran konfigurasi panggilan telepon telephony.incoming, yang dicoba ulang sekali.

Percobaan ulang

Setiap event segera dicoba sekali. Respons 2xx apa pun mengonfirmasi pengiriman. Untuk hasil lainnya (non-2xx, kesalahan koneksi, waktu habis), kami mencoba ulang pada 1 m, 5 m, 30 m, 2 h, 6 h, 12 h, dan 24 h setelah upaya pertama — 8 upaya selama 24 jam. Jika semua upaya gagal, pengiriman berhenti dan endpoint ditandai status="failing" di endpoint webhook; kami mengirim email kepada pemilik dan admin organisasi Anda serta menampilkannya di dasbor. Kembalikan 2xx segera setelah payload diterima secara tahan lama; proses secara asinkron. Pengiriman uji dari API pengujian endpoint mendapatkan satu percobaan ulang sekitar satu menit setelah upaya pertama dan tidak pernah mengubah status endpoint.

Urutan

Urutan pengiriman adalah upaya terbaik. Dalam praktiknya, kami mengirimkan sesuai urutan event dipancarkan, tetapi percobaan ulang dapat mengubah urutan saat terjadi kegagalan. Selalu lakukan deduplikasi dan rekonsiliasi berdasarkan call_id / ID objek.

Duplikat

Pengiriman bersifat setidaknya sekali: percobaan ulang setelah respons yang tidak kami terima dapat menduplikasi event. Setiap percobaan ulang membawa event_id yang sama, jadi simpan ID yang sudah diproses dan lewati pengulangan. event_id juga dibagikan antar-endpoint — dua endpoint yang berlangganan pada event yang sama menerima event_id yang sama.

Waktu habis

Pengiriman endpoint memiliki waktu habis 30 s per upaya. Pada jalur lama, permintaan pemblokiran yang mengendalikan perilaku panggilan langsung — pertukaran konfigurasi telephony.incoming / web.incoming — dibatasi hingga 10 s untuk upaya pertama panggilan telepon dan 13 s untuk seluruh pertukaran termasuk satu percobaan ulangnya, serta hingga 10 s untuk sesi widget. Respons yang lambat menunda pengangkatan panggilan, jadi usahakan menjawab dalam beberapa detik. Pengiriman tool mode webhook mengizinkan 20 s secara default, dan deklarasi tool dapat menetapkan timeout tingkat atas.

IP sumber

Webhook keluar berasal dari rentang IP cloud ThunderPhone. Jika firewall Anda memerlukan daftar izin, hubungi dukungan dan kami akan membagikan rentang saat ini.

Memilih antara webhook legacy dan berbasis endpoint

FiturLegacy (/v1/webhook)Endpoint (/v1/developer/webhook-endpoints)
Jumlah URL1 per organisasiBanyak per organisasi
Cakupan eventHanya telephony.* / web.*Semua 10 jenis event
Filter event—Per endpoint
Percobaan ulangTidak ada, kecuali satu untuk pertukaran konfigurasi panggilan telepon8 percobaan selama 24 jam
Envelopetype + datatype + data + event_id
Rotasi secretMengganti satu secretSecret per endpoint
Nonaktifkan tanpa menghapusPUT /v1/webhook dengan {"url": ""}status=disabled
Visibilitas Status—active / disabled / failing
Pertukaran konfigurasi yang memblokirYa (telephony.incoming / web.incoming)Tidak pernah — hanya notifikasi
Paling sesuai untukKonfigurasi panggilan dinamisKonsumsi event di produksi

Integrasi baru sebaiknya menerima event melalui webhook berbasis endpoint. Pertahankan (atau tambahkan) URL legacy hanya jika Anda mengonfigurasi panggilan secara dinamis saat panggilan diangkat atau menggunakan pengiriman tool mode webhook — pertukaran permintaan/respons tersebut hanya berjalan pada jalur legacy.


Terkait