Webhook
ThunderPhone
ThunderPhone, bir çağrı sırasında gerçekleşen durumlarda — gelen çağrının başlaması, çağrının sona ermesi, derecelendirme çalışmasının tamamlanması, uyarının tetiklenmesi vb. — sunucunuza HTTP POST istekleri gönderir. İki teslim modeli vardır:
Birden fazla URL, uç nokta başına gizli anahtarlar, uç nokta başına olay filtreleri
ve otomatik yeniden denemeler.
GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints üzerinden yönetin.
Kuruluş başına bir URL. Engelleyici yapılandırma alışverişleri de dahil olmak üzere çağrı yaşam döngüsü olaylarını taşır. GET/PUT /v1/webhook üzerinden yönetilir.
Olay kataloğundaki on olay türünün tümü webhook uç noktaları üzerinden teslim edilir. Altı çağrı yaşam döngüsü olayı
(telephony.incoming, telephony.complete, telephony.tool,
web.incoming, web.complete, web.tool) eski tek URL'li webhook'a
ayrıca gönderilir — hem eski bir URL'niz hem de eşleşen bir uç noktanız varsa olayı her iki yolda da alırsınız. Engelleyici davranış (telephony.incoming / web.incoming yapılandırma
alışverişi ve webhook modundaki
araç yönlendirme) yalnızca eski yolda bulunur; her uç nokta teslimi, yanıt beklemeden gönderilen bir bildirimdir.
Yük biçimi
Uç nokta teslimleri, data, event_id ve type içeren bir JSON nesnesidir:
{
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
},
"event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
"type": "telephony.incoming"
}event_id, yayımlanan her olay için benzersizdir. Yeniden denemeler arasında
ve olayı alan her uç nokta arasında aynıdır — tekilleştirme için bunu kullanın.
Eski tek URL'li webhook aynı type ve data değerlerini, ancak
event_id olmadan gönderir:
{
"type": "telephony.incoming",
"data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}Aktarım sırasında her gövde standart biçimde serileştirilir — anahtarlar alfabetik olarak sıralanır, boşluk içermez ve UTF-8 kullanır. Bu belgelerdeki girintili örnekler yalnızca okunabilirlik içindir.
Olay türlerinin ve yük alanlarının tam listesi için Olay kataloğu sayfasına bakın.
İmza doğrulama
Her istek, X-ThunderPhone-Signature başlığında ham istek
gövdesi üzerinde oluşturulmuş bir HMAC-SHA256 imzası taşır. İmzalama anahtarı,
uç noktanın secret değeridir (veya eski teslimatlar için kuruluş düzeyindeki webhook
secret değerinizdir).
Adımlar
- Herhangi bir ayrıştırma işleminden önce ham istek gövdesini okuyun.
hmac_sha256(secret, body).hexdigest()değerini hesaplayın.- Sonucu
X-ThunderPhone-Signaturebaşlığıyla sabit zamanda karşılaştırın.
Gönderdiğimiz baytları tam olarak imzalarız ve bu baytlar kanonik JSON serileştirmesidir (sıralanmış anahtarlar, sıkıştırılmış ayırıcılar). Bu nedenle ham gövdeye karşı doğrulama her zaman çalışır — çerçeveniz yalnızca ayrıştırılmış JSON veriyorsa, bunu sıralanmış anahtarlar ve sıkıştırılmış ayırıcılarla yeniden serileştirmek aynı baytları üretir. Her iki yöntem de doğrulama kılavuzunda açıklanmıştır.
import hmac
import hashlib
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature or "")
# Example Flask handler
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/thunderphone-webhook")
def handle():
body = request.get_data()
sig = request.headers.get("X-ThunderPhone-Signature", "")
if not verify_signature(body, sig, WEBHOOK_SECRET):
abort(401)
event = request.get_json()
# dispatch on event["type"] …
return "", 204import crypto from "node:crypto";
import express from "express";
function verifySignature(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
if (!signature || expected.length !== signature.length) return false;
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature),
);
}
const app = express();
app.post(
"/thunderphone-webhook",
express.raw({ type: "application/json" }),
(req, res) => {
const sig = req.header("X-ThunderPhone-Signature") || "";
if (!verifySignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
// dispatch on event.type …
res.sendStatus(204);
},
);Teslimat anlamları
Bu anlamlar uç nokta teslimatları için geçerlidir. Eski tek URL'li webhook, yeniden denemesi olmayan tek bir eşzamanlı denemedir.
Yeniden denemeler
Her olay hemen bir kez denenir. Herhangi bir 2xx yanıtı
teslimatı onaylar. Diğer tüm sonuçlarda (2xx olmayan yanıt,
bağlantı hatası, zaman aşımı) ilk denemeden 1 dk., 5 dk., 30 dk.,
2 sa., 6 sa., 12 sa. ve 24 sa. sonra yeniden deneriz — 24 saate
yayılan 8 deneme. Her deneme başarısız olursa teslimat durur ve uç
nokta webhook uç noktalarında
status="failing" olarak işaretlenir. Yük kalıcı olarak kabul
edilir edilmez 2xx döndürün; işlemi eşzamansız yapın.
Sıralama
Teslimat sıralaması en iyi çaba esasına dayanır. Uygulamada olayları
yayımlandıkları sırayla teslim ederiz, ancak yeniden denemeler hata
durumunda sıralamayı değiştirebilir. Her zaman call_id / nesne
kimliğine göre yinelenenleri kaldırın ve mutabakat sağlayın.
Yinelenenler
Teslimat en az bir kez gerçekleşir: hiç görmediğimiz bir yanıttan
sonra yapılan yeniden deneme bir olayı yineleyebilir. Her yeniden
deneme aynı event_id değerini taşır; bu nedenle işlenen kimlikleri
saklayın ve tekrarları atlayın. event_id uç noktalar arasında da
paylaşılır — aynı olaya abone iki uç nokta aynı event_id değerini
alır.
Zaman aşımları
Uç nokta teslimatlarında deneme başına 30 sn. zaman aşımı vardır.
Eski yolda, canlı çağrı davranışını yönlendiren engelleyici istekler —
telephony.incoming / web.incoming
yapılandırma alışverişi — 10 sn. sonra zaman aşımına uğrar; ancak
yavaş bir yanıt çağrının yanıtlanmasını geciktirir, bu nedenle birkaç
saniye içinde yanıt vermeyi hedefleyin. Webhook modundaki
araç yönlendirme varsayılan olarak 20 sn. tanır
ve araç bildirimleri üst düzeyde bir timeout ayarlayabilir.
Kaynak IP'ler
Giden webhook'lar ThunderPhone'un bulut IP aralığından gelir. Güvenlik duvarınız izin listesi gerektiriyorsa destek ekibiyle iletişime geçin; güncel aralıkları paylaşırız.
Eski ve uç nokta tabanlı webhook'lar arasında seçim yapma
| Özellik | Eski (/v1/webhook) | Uç noktalar (/v1/developer/webhook-endpoints) |
|---|---|---|
| URL sayısı | Kuruluş başına 1 | Kuruluş başına birçok |
| Olay kapsamı | Yalnızca telephony.* / web.* | 10 olay türünün tümü |
| Olay filtresi | — | Uç nokta başına |
| Yeniden denemeler | Yok | 24 saat içinde 8 deneme |
| Zarf | type + data | type + data + event_id |
| Gizli anahtar rotasyonu | Tek gizli anahtarı değiştirir | Uç nokta başına gizli anahtar |
| Silmeden devre dışı bırakma | — | status=disabled |
| Durum görünürlüğü | — | active / disabled / failing |
| Engelleyici yapılandırma alışverişi | Evet (telephony.incoming / web.incoming) | Asla — yalnızca bildirimler |
| En uygun kullanım | Dinamik çağrı yapılandırması | Üretimde olay tüketimi |
Yeni entegrasyonlar olayları uç nokta tabanlı webhook'lar üzerinden tüketmelidir. Yalnızca çağrıları yanıtlanma anında dinamik olarak yapılandırıyorsanız veya webhook modunda araç yönlendirme kullanıyorsanız eski bir URL'yi koruyun (veya ekleyin) — bu istek/yanıt alışverişleri yalnızca eski yolda çalışır.
İlgili
Tüm olay türleri ve yükleri.
Birden çok uç noktayı, olay filtrelerini ve gizli anahtarları yönetin.
Çağrıları yapılandırmak için sunucunuzun yanıtlaması gereken engelleyici istek.
Transkript, kayıt ve metrikleri içeren çağrı sonrası yük.