Webhook rehberi
Olay türleri, imza doğrulama (Node, Python, PHP, C#, Go), tekrar deneme ve kaçan olayları yakalama.
Webhook'lar bir şey olduğunda sunucunuza HTTPS POST gönderir. Her olay aynı zarfı taşır:
{
"id": "evt_981",
"type": "calendar.updated",
"created_at": "2027-06-01T10:00:00.000Z",
"livemode": true,
"api_version": "2026-11-01",
"property_id": "5b1c1f1e-…",
"property_seq": 14,
"data": { "closed": [{ "start": "2027-07-10", "end": "2027-07-14" }], "opened": [], "source": "agency" }
}property_seq, o mülkün olaylarının sıra numarasıdır (1, 2, 3…). Bir boşluk gördüğünüzde olay kaçırmışsınız demektir;GET /v1/eventsile yakalayın.- Bir acentenin rezervasyonu diğer abonelere yalnızca
calendar.updated(source: "agency") olarak gider; hangi acente olduğu, misafir veya referans asla paylaşılmaz. - Kendi rezervasyonunuz için
reservation.*vehold.*olayları gelir; bunlar yalnızca size gider.
Adres eklemek
Adres herkese açık bir https adresi olmalıdır. Yerel ve özel ağ adresleri (örn. 10.x, 192.168.x, localhost) kabul edilmez; yerelde denemek için bir tünel (ngrok, Cloudflare Tunnel) kullanın. Yanıtınızın 2xx olması başarıdır; 10 saniye içinde cevap verin ve işi arka planda yapın.
İmzayı doğrulayın
İmzalar Standard Webhooks belirtimini izler. Her istek üç başlık taşır: webhook-id, webhook-timestamp (saniye) ve webhook-signature. İmza, webhook-id.webhook-timestamp.gövde metninin, sırrınızın (whsec_ sonrası base64 çözülmüş) HMAC-SHA256 özetidir. İmzayı ham gövde üzerinden doğrulayın; JSON'u yeniden serileştirmeyin. Zaman damgası 5 dakikadan eskiyse reddedin.
import crypto from 'node:crypto';
export function verify(secret, headers, rawBody) {
const id = headers['webhook-id'];
const ts = Number(headers['webhook-timestamp']);
if (Math.abs(Date.now() / 1000 - ts) > 300) return false;
const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64');
const expected = 'v1,' + crypto.createHmac('sha256', key).update(`${id}.${ts}.${rawBody}`).digest('base64');
// the header may hold several space-separated signatures (during secret rotation)
return headers['webhook-signature'].split(' ').some((sig) => {
const a = Buffer.from(sig), b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
});
}
// Express: app.post('/hooks/bookingpool', express.raw({ type: 'application/json' }), (req, res) => {
// if (!verify(process.env.BP_WHSEC, req.headers, req.body.toString())) return res.sendStatus(400);
// const event = JSON.parse(req.body); /* queue it, then: */ res.sendStatus(200);
// });Doğru çalıştığını denemek için Geliştirici sayfasındaki "Test gönder" düğmesini veya POST /v1/webhook-endpoints/{id}/test uç noktasını kullanın: imzalı bir ping olayı hemen gönderilir.
Tekrar deneme
2xx dışı bir cevap, zaman aşımı veya bağlantı hatası başarısız sayılır ve şu aralıklarla yeniden denenir: 5 sn, 5 dk, 30 dk, 2 saat, 6 saat, 12 saat, 24 saat, 24 saat (yaklaşık üç gün). Sonunda hâlâ başarısızsa teslimat FAILED olur; Geliştirici sayfasından veya POST /v1/webhook-deliveries/{id}/retry ile elle yeniden gönderebilirsiniz. Bir adres art arda çok başarısız olursa e-postayla haber verip kapatırız.
Aynı olay birden fazla kez gelebilir (ağ cevabınızı kaybettiğinde) ve sıra garantisi yoktur. Olay id değerine göre tekrarları yok sayın ve durumu property_seq ile sıralayın.
Sırrı yenilemek
rotate-secret yeni bir sır verir; eski sır 24 saat daha geçerli kalır ve bu sürede webhook-signature başlığı iki imza taşır (boşlukla ayrılmış). Yukarıdaki kodlar bunu zaten ele alır; önce yeni sırra geçin, sonra bekleyin.
Kaçan olayları yakalamak
Sunucunuz bir süre kapalı kaldıysa en son işlediğiniz olayın id değerini GET /v1/events?after=… ile verip devam edin. Günlük, webhook'larınızın taşıdığı aynı olayları aynı sırayla ve aynı görünürlük kurallarıyla verir.