ThunderPhone 2.0 jest już dostępny.Uruchom samodzielnie, od 2¢/min.Przeczytaj komunikat

Webhooks

Przegląd webhooków

Jak ThunderPhone dostarcza zdarzenia w czasie rzeczywistym, jak weryfikować podpisy oraz jak wypada porównanie starszego modelu dostarczania z modelem opartym na punktach końcowych.

ThunderPhone wysyła żądania HTTP POST do Twojego serwera, gdy coś dzieje się podczas połączenia — rozpoczyna się połączenie przychodzące, połączenie się kończy, uruchomienie oceny zostaje ukończone, zostaje wyzwolony alert itd. Dostępne są dwa modele dostarczania:

Wszystkie wymienione typy zdarzeń w katalogu zdarzeń są dostarczane przez endpointy webhooków. Sześć zdarzeń cyklu życia połączenia (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) jest również wysyłanych do starszego webhooka z jednym adresem URL — jeśli masz zarówno starszy adres URL, jak i pasujący endpoint, otrzymasz zdarzenie na obu ścieżkach. Zachowanie blokujące (wymiana konfiguracji telephony.incoming / web.incoming oraz wywoływanie narzędzi w trybie webhooka) jest dostępne wyłącznie na starszej ścieżce; każde dostarczenie do endpointu jest powiadomieniem typu fire-and-forget.

Format ładunku

Dostarczenia do endpointów mają postać obiektu JSON z polami data, event_id i type:

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

event_id jest unikalne dla każdego wyemitowanego zdarzenia. Jest identyczne przy ponownych próbach oraz we wszystkich endpointach, które otrzymują zdarzenie — usuwaj duplikaty na jego podstawie.

Starszy webhook z jednym adresem URL wysyła te same pola type i data, ale bez event_id:

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

W transmisji każde body jest serializowane kanonicznie — klucze są sortowane alfabetycznie, bez białych znaków, w UTF-8. Przykłady sformatowane dla czytelności w tej dokumentacji służą wyłącznie ułatwieniu lektury.

Zobacz Katalog zdarzeń, aby uzyskać pełną listę typów zdarzeń i pól ładunku.

Weryfikacja podpisu

Każde żądanie zawiera dwa podpisy, oba HMAC-SHA256 z kluczem secret punktu końcowego (lub secret webhooka na poziomie organizacji w przypadku starszych dostaw):

  • X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex> podpisuje znacznik czasu, metodę, ścieżkę i zapytanie oraz surową treść. Zweryfikuj ten podpis i odrzucaj żądania, których t różni się od czasu na Twoim zegarze o więcej niż 5 minut, aby przechwycone żądanie nie mogło zostać później ponownie odtworzone. Ponowienia są podpisywane ponownie w momencie wysłania.
  • X-ThunderPhone-Signature podpisuje tylko surową treść. Nadal jest wysyłany bez zmian, aby istniejące mechanizmy weryfikujące nadal działały.

Kroki

  1. Odczytaj nagłówek, metodę, surową ścieżkę i zapytanie oraz surowe ciało przed jakimkolwiek parsowaniem.
  2. Oblicz szesnastkowy HMAC-SHA256 ciągu <t>\n<METHOD>\n<path and query>\n<body> przy użyciu swojego sekretu.
  3. Odrzuć żądanie, jeśli t różni się o więcej niż 300 sekund lub jeśli wynik nie odpowiada v1 w porównaniu ze stałym czasem wykonania.

Ciała mają kanoniczną serializację JSON (posortowane klucze, zwięzłe separatory) i podpisujemy dokładnie te bajty, które przesyłamy. Przewodnik po weryfikacji zawiera dokładny podpisywany ciąg, przykład z objaśnieniem, kod bez SDK oraz starszy nagłówek.

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

Semantyka dostarczania

Te zasady dotyczą dostarczania do endpointów. Starszy webhook z jednym adresem URL wykonuje pojedynczą synchroniczną próbę bez ponowień, z wyjątkiem wymiany konfiguracji połączenia telefonicznego telephony.incoming, która jest ponawiana jednokrotnie.

Ponowienia

Każde zdarzenie jest natychmiast podejmowane raz. Każda odpowiedź 2xx potwierdza dostarczenie. Przy każdym innym wyniku (innym niż 2xx, błędzie połączenia, przekroczeniu limitu czasu) ponawiamy próbę po 1 min, 5 min, 30 min, 2 godz., 6 godz., 12 godz. i 24 godz. od pierwszej próby — łącznie 8 prób w ciągu 24 godzin. Jeśli wszystkie próby zakończą się niepowodzeniem, dostarczanie zostanie zatrzymane, a endpoint otrzyma wartość status="failing" w sekcji endpointy webhooków; wyślemy wiadomość e-mail do właścicieli i administratorów Twojej organizacji oraz wyświetlimy to w panelu. Zwróć 2xx, gdy tylko ładunek zostanie trwale przyjęty; przetwarzaj go asynchronicznie. Wysyłki testowe z interfejsu API testowania endpointów otrzymują jedno ponowienie około minuty po pierwszej próbie i nigdy nie zmieniają statusu endpointu.

Kolejność

Kolejność dostarczania jest realizowana według najlepszych starań. W praktyce dostarczamy zdarzenia w kolejności ich emisji, ale ponowienia mogą zmienić kolejność po niepowodzeniu. Zawsze deduplikuj i uzgadniaj według call_id / identyfikatora obiektu.

Duplikaty

Dostarczanie odbywa się co najmniej raz: ponowienie po odpowiedzi, której nie otrzymaliśmy, może zduplikować zdarzenie. Każde ponowienie zawiera ten sam event_id, dlatego przechowuj przetworzone identyfikatory i pomijaj powtórzenia. event_id jest także współdzielony między punktami końcowymi — dwa punkty końcowe subskrybujące to samo zdarzenie otrzymują ten sam event_id.

Limity czasu

Dostarczanie do endpointów ma limit czasu 30 s na próbę. W starszej ścieżce blokujące żądania sterujące zachowaniem aktywnego połączenia — wymiana konfiguracji telephony.incoming / web.incoming — są ograniczone do 10 s dla pierwszej próby połączenia telefonicznego i 13 s dla całej wymiany, łącznie z jednym ponowieniem, oraz do 10 s dla sesji widżetu. Powolna odpowiedź opóźnia odebranie połączenia, dlatego staraj się odpowiadać w ciągu kilku sekund. Wysyłanie narzędzi w trybie webhooka domyślnie umożliwia 20 s, a deklaracje narzędzi mogą ustawiać timeout na najwyższym poziomie.

Źródłowe adresy IP

Wychodzące webhooki pochodzą z zakresu adresów IP chmury ThunderPhone. Jeśli zapora wymaga listy dozwolonych adresów, skontaktuj się z pomocą techniczną, a udostępnimy aktualne zakresy.

Wybór między starszymi webhookami a webhookami opartymi na punktach końcowych

FunkcjaStarsze (/v1/webhook)Punkty końcowe (/v1/developer/webhook-endpoints)
Liczba adresów URL1 na organizacjęWiele na organizację
Obsługiwane zdarzeniaTylko telephony.* / web.*Wszystkie 10 typów zdarzeń
Filtr zdarzeń—Dla każdego punktu końcowego
Ponowne próbyBrak, z wyjątkiem jednej dla wymiany konfiguracji połączenia telefonicznego8 prób w ciągu 24 h
Kopertatype + datatype + data + event_id
Rotacja sekretuZastępuje pojedynczy sekretSekret dla każdego punktu końcowego
Wyłączenie bez usuwaniaPUT /v1/webhook z {"url": ""}status=disabled
Widoczność statusu—active / disabled / failing
Blokująca wymiana konfiguracjiTak (telephony.incoming / web.incoming)Nigdy — tylko powiadomienia
Najlepsze zastosowanieDynamiczna konfiguracja połączeńObsługa zdarzeń w środowisku produkcyjnym

Nowe integracje powinny odbierać zdarzenia przez webhooki oparte na punktach końcowych. Zachowaj (lub dodaj) starszy adres URL tylko wtedy, gdy konfigurujesz połączenia dynamicznie w momencie odebrania lub używasz wywoływania narzędzi w trybie webhooków — te wymiany żądanie/odpowiedź działają tylko w starszej ścieżce.


Powiązane