Webhook'lar
Webhook, "şu olay olduğunda şu adrese haber ver" demenin yoludur. Diyelim ki haftada bir blog yazısı yayınlıyorsunuz ve her yayınlandığında Slack'teki ekip kanalına haber düşsün, n8n bir sosyal medya akışı başlatsın, analitik servisiniz de kaydını tutsun istiyorsunuz. Webhook'lar bunu halleder — bir olay ve bir URL kaydediyorsunuz, jekcms o olay her gerçekleştiğinde o URL'ye imzalı bir istek gönderiyor.
Hangi olaylar var?
Şu an şu anlarda webhook tetiklenebilir:
- post.published — bir yazı yayına girdi (zamanlanmış yayın da bunu tetikler)
- post.updated — yayınlanmış bir yazıda herhangi bir alan değişti
- post.deleted — yazı silindi (soft ya da hard)
- comment.approved — bir yorum beklemeden onaylandıya geçti
- order.completed — bir sipariş ödendi olarak işaretlendi (ticaret modülü açıksa)
Her sürümde yeni olaylar ekleniyor. Güncel listeyi webhook admin sayfasındaki açılır menüden görebilirsiniz.
Bir webhook nasıl eklenir?
admin/webhooks.php sayfasını açın. Kayıtlı webhook'ların listesi üstte olay adı, URL, durum ve son teslim zamanıyla görünür.
Yeni eklemek için:
- Event — açılır menüden hangi olayı izleyeceğinizi seçin
- URL — haberin gideceği adres (production için HTTPS şart; yerel geliştirmede HTTP olur)
- Description — kendinize not ("Slack içerik kanalı" gibi)
- Secret — otomatik üretilen gizli anahtar; yükü imzalamak için kullanılır
Ekledikten sonra Test düğmesine basın. jekcms bu URL'ye sahte ama gerçekçi bir yük gönderir — gerçek bir olay tetiklenmeden önce alıcı tarafınızın doğru çalıştığını kontrol edebilirsiniz. İlk deneme genelde bir şeyleri açığa çıkarır.
İmza doğrulama neden önemli?
jekcms her webhook isteğinin başlığına özel bir imza ekler:
X-Webhook-Signature: sha256=b2f3a9e4c1d8...
Content-Type: application/json
User-Agent: jekcms-Webhook/1.0
Bu imza, webhook secret'ınızla istek gövdesi kullanılarak hesaplanır (HMAC-SHA256 diye geçer). Siz alıcı tarafta da aynı hesabı yapıp karşılaştırırsanız yükün gerçekten jekcms'ten geldiğinden emin olursunuz.
Bunu atlarsanız webhook URL'nizi ele geçiren ya da tahmin eden herkes size sahte "yazı yayınlandı" isteği gönderebilir ve sizin sunucunuz bunu gerçek zannedebilir. İmza kontrolü spam ve saldırılara karşı kapıyı kapatır.
İmza doğrulama — dilinize göre örnek
PHP
$raw = file_get_contents('php://input');
$secret = getenv('JEKCMS_WEBHOOK_SECRET');
$expected = 'sha256=' . hash_hmac('sha256', $raw, $secret);
$received = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (!hash_equals($expected, $received)) {
http_response_code(401);
exit('invalid signature');
}
$payload = json_decode($raw, true);
// process $payload safely
Node.js
const crypto = require('crypto');
app.post('/jekcms-hook', express.raw({ type: 'application/json' }), (req, res) => {
const secret = process.env.JEKCMS_WEBHOOK_SECRET;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex');
const received = req.headers['x-webhook-signature'];
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))) {
return res.status(401).send('invalid signature');
}
const payload = JSON.parse(req.body.toString());
// process payload safely
res.sendStatus(200);
});
Python (Flask)
import hmac, hashlib, os
from flask import request, abort
@app.route('/jekcms-hook', methods=['POST'])
def hook():
raw = request.get_data()
secret = os.environ['JEKCMS_WEBHOOK_SECRET'].encode()
expected = 'sha256=' + hmac.new(secret, raw, hashlib.sha256).hexdigest()
received = request.headers.get('X-Webhook-Signature', '')
if not hmac.compare_digest(expected, received):
abort(401)
payload = request.get_json()
# process payload safely
return '', 200
Hepsinin ortak noktasına dikkat: hash_equals, timingSafeEqual, compare_digest gibi sabit zamanlı karşılaştırma kullanıyoruz. Normal == ile karşılaştırmak zamanlama yan kanalı açar; saldırgan bu yolla imzayı yavaş yavaş tahmin edebilir.
Başarısız olursa ne olur?
jekcms 10 saniye içinde alıcı tarafınızdan "2xx" (başarı) yanıtı bekler. Gelmezse — zaman aşımı, bağlantı reddi, DNS hatası, 5xx — yeniden dener:
- İlk deneme: hemen
- İkinci deneme: 30 saniye sonra
- Üçüncü deneme: 5 dakika sonra
Üçü de başarısız olursa teslim failed_permanent olur ve webhook'un failure_count sayacı bir artar. Bu sayaç 20'yi geçerse jekcms webhook'u otomatik devre dışı bırakır ve size admin'de uyarı düşürür — yanlış yapılandırılmış bir URL yüzünden kuyruğun sonsuza kadar tıkanmasını böyle engeller.
Log'lara nasıl bakarım?
Her deneme (başarılı ya da başarısız) webhook_attempts tablosuna kaydedilir: zaman damgası, HTTP durumu, cevap gövdesi (ilk 2 KB), gidip gelme süresi. Automation → Webhooks → webhook'a tıkla → Logs üzerinden görürsünüz. Durum koduna, tarihe göre filtreleyebilir, belirli bir yük arayabilirsiniz.
30 günden eski log satırları backup.rotate zamanlanmış görevi tarafından temizlenir.
Alıcı tarafta neler kurmanız gerekebilir?
n8n kullanıyorsanız: Önce bir Webhook node'u ekleyin (POST), arkasından imzayı doğrulayan bir Function node'u koyun. Secret'ı iş akışı JSON'ına yazmayın, $env.JEKCMS_WEBHOOK_SECRET ile çevre değişkeninden okuyun. İmza onayı geçmeden hiçbir downstream node'a güvenmeyin.
Slack kullanıyorsanız: Slack gelen webhook'ları HMAC doğrulaması yapmaz ama URL'nin kendisi gizlidir. Slack'te bir "incoming webhook" oluşturun, URL'yi jekcms'e yapıştırın. Arada bir küçük dönüştürücü (Cloudflare Worker ya da n8n) koymanız gerekir çünkü Slack jekcms'in JSON formatını aynen anlamaz — kendi block-kit formatına çevirmelisiniz.