Webhooks

Giden webhook, sitenizin "bir şey oldu" demesinin yoludur. Yazı yayına girer ve bir Slack kanalı haberdar olur; yorum gelir ve bir Zapier akışı onu kaydeder; üye kaydolur ve CRM'inize satır düşer. jekcms, olay gerçekleştiği anda sizin sahip olduğunuz bir adrese imzalı JSON POST gönderir.

Giden Webhook'lar formu ve gönderebildiği beş olay
Onay kutuları olay listesinin tamamı - tam olarak beş tane.

Bu sayfa giden yönü anlatıyor. Ters yön için - dış araçların /api/v1/webhook/{aksiyon} üzerinden sitenize içerik göndermesi - Otomasyon bölümündeki Webhook'lar sayfasına bakın.

Tanımlama

Webhook hedefleri API anahtarlarıyla aynı ekranda yaşıyor: Yönetim → API Anahtarları, Giden Webhook'lar kutusu. Bir hedef için ad, https:// ile başlayan bir adres ve abone olunacak olay kümesi gerekir. Düz http reddedilir.

Kayıt bir imza anahtarı üretir ve onu yalnız o ekranda, bir kez gösterir. Anahtar şifrelenmiş saklanır; kurulum şifreleyemiyorsa webhook düz metne düşmek yerine hiç oluşturulmaz - çünkü okunabilir bir imza anahtarı saldırgan için API anahtarı kadar değerlidir.

Her hedefin yanındaki Test düğmesi, olay adı test ve gövdesi {"hello": "jekcms"} olan bir teslimat gönderir; alıcınızın erişilebilir olduğunu ve imza kontrolünüzün çalıştığını doğrulamanın en hızlı yolu budur.

Beş olay

| Olay | Ne zaman tetiklenir | |---|---| | post_published | Yazı yayına girdiğinde - oluşturmada, taslak yayınlandığında ya da zamanlayıcı zamanlanmış yazıyı yayına aldığında | | post_updated | Zaten yayında olan bir yazı yeniden kaydedildiğinde | | post_deleted | Yazı çöpe atıldığında ya da kalıcı silindiğinde | | comment_created | Ziyaretçi yorum gönderdiğinde - onaylı da düşse, beklemede de | | member_registered | Üye e-posta adresini doğruladığında |

Hiçbir olaya abone olmamak, hepsine abone olmakla aynı kapıya çıkar: olay listesi boş bir hedef her olayı alır. post_published yayındaki bir yazıyı düzenlediğinizde bilerek yeniden tetiklenmez - o iş post_updated'ın; bülten ve sosyal entegrasyonlar bu sayede iki kez göndermez.

Zarf

Her teslimatın aynı dört üst düzey anahtarı vardır:

{
  "event": "post_published",
  "site": "https://siteniz.com",
  "timestamp": "2026-04-21T14:32:17+03:00",
  "data": { }
}

timestamp ISO 8601'dir ve UTC değil, sitenin saat diliminde yazılır. site, sitenin genel taban adresidir; tek bir alıcının birden çok jekcms kurulumuna hizmet edebilmesini sağlayan şey budur.

Yanında üç başlık gider:

Content-Type: application/json
User-Agent: jekcms-webhook/1.0
X-Jek-Event: post_published
X-Jek-Signature: sha256=<64 karakterlik onaltilik dize>

Gövdeler

Üç yazı olayı tek bir şekli paylaşır:

{
  "id": 123,
  "title": "Proteini yüksek 10 kahvaltı",
  "slug": "proteini-yuksek-kahvaltilar",
  "status": "published",
  "url": "https://siteniz.com/proteini-yuksek-kahvaltilar"
}

comment_created yorumu ve ait olduğu yazıyı taşır; status onun yayında mı yoksa moderasyon kuyruğunda mı olduğunu söyler:

{
  "id": 456,
  "post_id": 123,
  "author_name": "Alex",
  "status": "pending"
}

member_registered üçünün en küçüğü:

{
  "id": 42,
  "name": "Yeni Üye",
  "email": "uye@example.com"
}

Bu gövdeler bilerek incedir. Size bir kimlik ve ilgilenip ilgilenmeyeceğinize karar verecek kadar bağlam verir; kaydın tamamı gerekiyorsa o kimlikle REST API'yi çağırın.

İmzayı doğrulama

İmza, ham istek gövdesinin HMAC-SHA256'sıdır; onaltılık yazılır ve başına sha256= gelir. Anahtar, webhook'u oluştururken gösterilen gizli değerdir.

const crypto = require('crypto');

const beklenen = 'sha256=' + crypto
  .createHmac('sha256', process.env.JEK_WEBHOOK_SECRET)
  .update(rawBody)              // ham baytlar - JSON.parse'dan ÖNCE
  .digest('hex');

const gelen = req.headers['x-jek-signature'] || '';
if (!crypto.timingSafeEqual(Buffer.from(beklenen), Buffer.from(gelen))) {
  return res.status(401).end();
}

Bunun çalışıp çalışmamasını iki ayrıntı belirler. Aldığınız baytları imzalayın, yeniden serileştirdiğiniz bir nesneyi değil - JSON'u yeniden biçimlendirmek özeti değiştirir. Ve karşılaştırmayı sabit zamanda yapın (Node'da timingSafeEqual, Python'da hmac.compare_digest); uzun ömürlü bir uçta düz === zamanlama sızdırır.

Teslimat davranışı ve yapmadıkları

Teslimatlar istek sürerken kuyruğa alınır ve yanıt ziyaretçiye verildikten sonra gönderilir; böylece yavaş bir alıcı sitenizi hiç yavaşlatmaz. Bağlantı zaman aşımı 2 saniye, isteğin tamamı için 4 saniye.

Tek bir sayfa yüklemesi en fazla 20 teslimat gönderir ve buna en fazla 12 saniye kadar ayırır. Bunun ötesi sessizce düşmez; teslimat günlüğüne deferred işaretiyle yazılır, böylece olduğunu görebilir ve elle yeniden gönderebilirsiniz.

Otomatik yeniden deneme yoktur. 2xx dışı bir yanıt, zaman aşımı ya da bağlantı hatası durum kodu ve hatasıyla kaydedilir; o denemenin sonu budur. Teslimat sizin için kritikse ya alıcınızı hızlıca kabul edip işi arka planda yapacak şekilde kurun ya da teslimat günlüğünü izleyip yeniden gönderin. 410 Gone da diğer hatalar gibi ele alınır; webhook'u devre dışı bırakmaz.

Teslimat günlüğü

Her deneme; olayı, adresi, HTTP durumu, gönderilen istek gövdesi ve yanıtın kısaltılmış bir kopyasıyla saklanır. Yönetim ekranı webhook başına en yeni sekiz denemeyi gösterir; her birinin yanındaki Yeniden gönder düğmesi saklanan gövdeyi hedefin güncel adresine tekrar yollar - çökmüş bir alıcıyı düzelttikten sonra işinizi görür.

Günlük webhook başına en yeni yüz satırı tutar, gerisini budar; yoğun bir sitede sınırsız büyümez. İmza anahtarları saklanan gövdelerde asla yer almaz.

Yeniliklerden ilk sen haberdar ol

Yeni özellikler, sürüm notları ve CMS rehberleri. Ayda birkaç e-posta gönderiyoruz.