Webhooks
Webhook'lar, "bir şey olduğunda bana haber ver" mekanizmasıdır. Siteyi boş yere sorgulamak yerine, bir yazı yayınlandığında ya da bir sipariş ödendiğinde jekcms sizin URL'nize POST atar. Hedef fark etmez — n8n, Zapier, Make, bir Lambda, Cloudflare Worker — HTTPS kabul eden her şey çalışır.
Bu sayfa API tarafı: hangi olaylar var, payload nasıl, imzayı nasıl doğrularsınız. Webhook eklemek ve teslim kayıtlarını görmek için admin tarafı Webhook yönetimi.
Hangi olaylar var
| Olay | Ne zaman tetiklenir | |-------|-----------| | post.published | Bir yazı herhangi bir durumdan published'a geçtiğinde | | post.updated | Zaten yayındaki bir yazı düzenlenip kaydedildiğinde | | post.deleted | Bir yazı çöpe taşındığında veya kalıcı silindiğinde | | post.restored | Çöpteki bir yazı geri alındığında | | comment.approved | Bir yorum onaylandığında (manuel veya otomatik) | | comment.rejected | Bir yorum spam olarak işaretlendiğinde | | order.completed | Bir sipariş paid durumuna geçtiğinde | | order.refunded | Ödenmiş bir sipariş iade edildiğinde | | license.activated | Bir lisans anahtarı bir domain'de aktifleştirildiğinde | | license.deactivated | Bir lisans pasifleştirildiğinde (elle veya süre dolumu) | | support.ticket_created | Yeni destek talebi açıldığında | | support.ticket_replied | Talebe herhangi bir taraf yanıt verdiğinde |
Bir URL'ye istediğiniz kadar olay abone edebilirsiniz, ama downstream tarafın temiz kalması için genelde webhook başına tek olay seçmek daha iyi.
Payload'ın ortak iskeleti
Hangi olay olursa olsun, dış zarf aynı:
{
"event": "post.published",
"timestamp": "2026-04-21T14:32:17Z",
"signature": "sha256=a1b2c3...",
"data": { /* olaya özgü, aşağıda */ }
}
event— yukarıdaki tablodaki stringtimestamp— ISO 8601, hep UTCsignature— istek gövdesinin HMAC-SHA256'sı,sha256=ön eklidata— olaya özgü nesne
data içinde ne var
post.* olayları
{
"post": {
"id": 123,
"title": "My post title",
"slug": "my-post-title",
"excerpt": "First 160 chars...",
"url": "https://yoursite.com/my-post-title",
"status": "published",
"published_at": "2026-04-21T14:32:17Z"
},
"author": { "id": 1, "name": "Jane Doe", "email": "jane@example.com" },
"categories": ["Nutrition"],
"tags": ["protein", "cutting"]
}
comment.approved, comment.rejected
{
"comment": {
"id": 456,
"post_id": 123,
"author_name": "Alex",
"author_email": "alex@example.com",
"content": "Great write-up.",
"status": "approved"
},
"post": { "id": 123, "title": "...", "url": "..." }
}
order.completed, order.refunded
{
"order": {
"id": 789,
"reference": "JEK-2026-00789",
"amount_cents": 4900,
"currency": "USD",
"status": "paid",
"paid_at": "2026-04-21T14:32:17Z"
},
"customer": { "id": 42, "email": "buyer@example.com", "name": "Buyer Name" },
"items": [{ "sku": "pro-annual", "name": "Pro Annual", "price_cents": 4900 }]
}
license.* olayları
{
"license": {
"key": "JEK-XXXX-XXXX-XXXX",
"tier": "pro",
"domain": "example.com",
"activated_at": "2026-04-21T14:32:17Z",
"expires_at": "2027-04-21T00:00:00Z"
},
"customer": { "id": 42, "email": "buyer@example.com" }
}
support.* olayları
{
"ticket": {
"id": 555,
"subject": "Can't upload images",
"status": "open",
"priority": "normal",
"url": "https://yoursite.com/admin/support/555"
},
"message": { "id": 9001, "author_type": "customer", "body": "..." },
"customer": { "id": 42, "email": "buyer@example.com" }
}
İmzayı doğrula — en kritik kısım
Webhook URL'niz herkese açık, yani teoride başkası da oraya POST atabilir. İmza doğrulaması, gelen isteğin gerçekten jekcms'ten olduğunu garanti eder. Formül:
signature = "sha256=" + hex( HMAC_SHA256( secret, raw_json_body ) )
- Secret — webhook'u Automation → Webhooks altında oluşturduğunuzda bir kez gösterilir, sonra tekrar göremezsiniz. Kaybederseniz yenisini üretin.
- Girdi — ayrıştırmadan önceki ham istek gövdesi byte'ları. JSON.parse edip sonra yeniden stringify etmek imzayı kırar.
Node.js'te:
const crypto = require('crypto');
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(rawBody) // Buffer or string — must be the raw body
.digest('hex');
if (expected !== payload.signature) {
return res.status(401).end();
}
Production'da düz === yerine sabit zamanlı karşılaştırma kullanın — Node'da crypto.timingSafeEqual, Python'da hmac.compare_digest. === karakter karakter kısa devre yapar ve bir saldırganın karakterleri teker teker tahmin etmesine yetecek zamanlama sinyali sızdırır.
Başarısızlıkta ne olur
Uç noktanız 2xx dışında bir şey dönerse (ya da hiç yanıt vermezse) jekcms üstel geri çekilmeyle yeniden dener:
| Deneme | Öncekinden bu yana | |---------|--------------------------| | 1 | (ilk) | | 2 | 1 saniye sonra | | 3 | 10 saniye sonra | | 4 | 60 saniye sonra |
4 kez başarısız olursa teslim failed olarak işaretlenir ve jekcms vazgeçer. Hata kaydı Automation → Webhooks → Delivery log altında 30 gün saklanır — payload'ı ve hata yanıtını inceleyip elle yeniden tetikleyebilirsiniz.
Yanıt kodlarının anlamı
2xx— teslim alındı, her şey tamam- 2xx dışı (
4xx,5xx, timeout) — yukarıdaki programa göre yeniden denenir 410 Gone— özel anlam: "bu uç nokta kalıcı olarak kapandı". jekcms yeniden denemez ve webhook'u otomatik devre dışı bırakır. Bir servisi gerçekten emekliye ayırırken kullanın.
Teslim timeout'u 10 saniye. Uç noktanız bundan daha uzun iş yapacaksa hemen 200 dönün, asıl işi kuyruğa atıp istek thread'inden çıkarın. Yavaş uç nokta = timeout = gereksiz yeniden deneme fırtınası.