Webhook'lar
Webhook, kuruluşunuzla ilgili bir şey olduğunda sunucunuza haber verir: bir teklif gelir, bir güvenli ödeme hesabına para yatırılır, bir sevkiyat limana ulaşır. Webhook'ları sahipler ve yöneticiler panelde ya da POST /v1/orgs/{org_id}/webhooks ile oluşturur.
Ne alırsınız
Her teslimat, küçük bir JSON gövdesi taşıyan bir POST isteğidir:
{
"id": "01a166eb-2f4e-74bd-a53e-6372d70ebead",
"type": "quote.sent",
"created_at": "2026-10-22T09:14:03.120000+00:00",
"data": {"conversation_id": "01a166e9-…", "quote_id": "01a166eb-…"}
}idolayın kimliğidir. Aynı olay birden fazla kez gelebilir; onu yalnızca bir kez işleyin (işlediğiniz kimlikleri saklayın).datayalnızca kimlik taşır; asla metin, ad, tutar ya da kişi bilgisi taşımaz. Gerisiniorg:readizinli bir anahtarla okuyun, ör.GET /v1/org/quotes/{quote_id}. Olaylar geç ya da sırasız gelse bile her zaman güncel duruma göre işlem yaparsınız.- Olay kataloğu her türü ve taşıdığı kimlikleri listeler. Bir webhook yalnızca istediği türleri alır.
Başlıklar:
| Başlık | Değer |
|---|---|
Birlesa-Signature | t=<unix seconds>,v1=<hex signature> (gizli anahtar yenilenirken iki v1 değeri) |
Birlesa-Event | Olay türü |
Birlesa-Delivery | Bu teslimatın kimliği: bir teslimatın yeniden denemelerinde aynı kalır |
User-Agent | Birlesa-Webhooks/1 |
Her teslimatı doğrulayın
İmza, <t>.<raw body> üzerinde hesaplanan HMAC-SHA256'dır. Anahtar, size gösterildiği haliyle webhook'un gizli anahtarının tamamıdır (brl_whsec_...). İmzayı, JSON'u ayrıştırmadan önce ham baytlar üzerinde kontrol edin. Ele geçirilmiş bir teslimatın sonradan yeniden oynatılamaması için beş dakikadan eski zaman damgalarını reddedin.
import hashlib
import hmac
import time
TOLERANCE_SECONDS = 300
def verify(secret: str, body: bytes, header: str) -> bool:
fields = [part.split("=", 1) for part in header.split(",") if "=" in part]
stamps = [value for name, value in fields if name == "t"]
if len(stamps) != 1 or not stamps[0].isdigit():
return False
if abs(time.time() - int(stamps[0])) > TOLERANCE_SECONDS:
return False
expected = hmac.new(secret.encode(), f"{stamps[0]}.".encode() + body, hashlib.sha256)
return any(
hmac.compare_digest(expected.hexdigest(), value) for name, value in fields if name == "v1"
)import { createHmac, timingSafeEqual } from "node:crypto";
const TOLERANCE_SECONDS = 300;
export function verify(secret, rawBody, header) {
const fields = header.split(",").map((part) => part.split("=", 2));
const stamps = fields.filter(([name]) => name === "t").map(([, value]) => value);
if (stamps.length !== 1 || !/^\d+$/.test(stamps[0])) return false;
if (Math.abs(Date.now() / 1000 - Number(stamps[0])) > TOLERANCE_SECONDS) return false;
const expected = createHmac("sha256", secret).update(`${stamps[0]}.`).update(rawBody).digest();
return fields
.filter(([name]) => name === "v1")
.some(([, value]) => {
const given = Buffer.from(value ?? "", "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
});
}Hızlı yanıt verin
10 saniye içinde herhangi bir 2xx ile yanıt verin, işi sonra yapın. Yanıt gövdenizi okumayız ve yönlendirmeleri izlemeyiz: bir 3xx başarısızlık sayılır.
Yeniden denemeler ve kapatma
Başarısız olan bir teslimat (yanıt yok, zaman aşımı, 2xx dışında bir durum kodu) 1, 5 ve 15 dakika, 1, 3, 6 ve 12 saat sonra, ardından bir gün arayla iki kez daha denenir: yaklaşık üç günde on deneme. Sonra başarısız olarak işaretlenir; teslimat geçmişinden yeniden gönderebilirsiniz (POST .../deliveries/{id}/retry).
Üç gün üst üste, en az on denemede başarısız olan bir webhook kapatılır (status: disabled, disabled_reason: failing) ve bekleyen teslimatlardan vazgeçilir. Uç noktayı düzeltin, webhook'u yeniden açın ({"active": true} ile PATCH), sonra ihtiyacınız olan teslimatları yeniden deneyin.
Teslimat yaptığımız adresler
- Herkese açık bir ana makine adı altında, 443 numaralı bağlantı noktasında
https://. IP adresleri,localhost, iç adlar (.local,.internal,.svc, ...) ve URL içinde kimlik bilgileri reddedilir (webhook_url_refused; nedenini sorun belgesininerrors[0].codealanı söyler:not_https,private_address, ...). - Her teslimattan önce ad yeniden çözümlenir. Adreslerinden herhangi biri özel, geri döngü (loopback), bağlantı-yerel (link-local) ya da başka bir şekilde herkese açık değilse hiçbir şey gönderilmez (
last_error: private_address). - Sertifika, ana makine adı için geçerli olmalıdır.
Gizli anahtarlar
- Gizli anahtar, webhook oluşturulduğunda bir kez gösterilir. Onu mühürlü olarak saklarız ve yeniden gösteremeyiz.
POST .../rotateyeni bir gizli anahtar verir. 24 saat boyunca teslimatlar hem yeni hem eski gizli anahtarla atılmış imzalar taşır; böylece hiçbir teslimatı kaçırmadan yeni anahtarı devreye alabilirsiniz. Bu 24 saat içinde ikinci bir yenileme reddedilir (rotation_pending).
Test etme
POST .../test, bir webhook.test teslimatını kuyruğa alır (boş data). Diğer teslimatlar gibi gönderilir; bu yüzden sonucu, sunucunuzun yanıt verdiği durum koduyla birlikte teslimat geçmişinde (GET .../deliveries) görünür.
Sınırlar
Kuruluş başına en çok 10 webhook; dakikada en çok 5 test isteği ya da elle yeniden deneme. Teslimat geçmişi 30 gün saklanır.