İçeriğe geç
Belgeler menüsü

Webhook

YHA Abone · Çıkışlar'da webhook türünde bir çıkış açın. Yeni haber, düzeltme ve iptalde adresinize POST gelir.

  • Adres yalnızca https; bağlantı noktası 443 ya da 1024–65535. Özel ve yerel ağ adresleri reddedilir.
  • Zaman aşımı 10 saniye; yönlendirme izlenmez (3xx hata sayılır).
  • User-Agent: YHA-Webhook/1, Content-Type: application/json.
  • Varsayılan yük tam içeriktir; profilde "ince" seçilirse yalnızca kimlik ve adres gelir, içeriği API'den alırsınız.

Gövde

json
{ "surum": 1, "olay_turu": "haber.duzeltme", "zaman": "2026-10-07T11:19:02Z", "deneme": false, "veri": { "olay_id": "…" } }

olay_turu: haber.yeni, haber.duzeltme, haber.iptal, varlik.yeni, varlik.iptal, varlik.guncelleme, sinama.ping. veri bir DisOlay'dır. Gövde 256 KB'ı aşarsa govde boşaltılır ve govde_kesildi: true gelir.

Yanıtınız

YanıtBiz ne yaparız
2xxTeslim edildi
5xx, 408, 429, 401, 403, 404, 3xx, bağlantı hatasıYeniden deneriz: 30 sn, 1 dk, 2 dk, 5 dk, sonra 15 dakikada bir (yaklaşık 24 saat); 429'da Retry-After'a uyarız
400, 413, 422Bu içerik için vazgeçeriz
410Çıkışı duraklatırız ve size bildiririz

Art arda hatalar sürerse çıkış "arızalı" görünür, Teknik Destek uyarılır ve her 15 dakikada yalnızca bir deneme yapılır; ilk başarıda biriken içerik sırayla gider. Sıra garantisi yoktur (flaş öne geçer): eski düzeltmeyi surum_no ile yok sayın.

İmza (Standard Webhooks)

metin
webhook-id: <teslim kimliği>          (yeniden denemelerde aynı)
webhook-timestamp: 1791371942          (Unix saniye)
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=

İmzalanan metin <webhook-id>.<webhook-timestamp>.<ham gövde>; anahtar sırrın whsec_ önekinden sonraki base64 çözülmüş baytları; HMAC-SHA256, base64. Zaman damgasını ±5 dakikada kabul edin, sabit zamanlı karşılaştırın ve webhook-id'yi çift işlememek için saklayın. Sır döndürüldüğünde eski sır 24 saat daha geçerlidir ve başlık iki imza taşır (v1,<yeni> v1,<eski>); birinin tutması yeter.

python
import base64, hmac, hashlib, time
def imza_gecerli(sir: str, b: dict, govde: bytes) -> bool:
    anahtar = base64.b64decode(sir.removeprefix("whsec_"))
    wid, zaman = b["webhook-id"], b["webhook-timestamp"]
    if abs(time.time() - int(zaman)) > 300: return False
    beklenen = base64.b64encode(hmac.new(anahtar, f"{wid}.{zaman}.".encode() + govde, hashlib.sha256).digest()).decode()
    return any(hmac.compare_digest(p[3:], beklenen) for p in b["webhook-signature"].split() if p.startswith("v1,"))
js
// JavaScript (Node): govde ham Buffer olmalı
import { createHmac, timingSafeEqual } from 'node:crypto';
export function imzaGecerli(sir, b, govde) {
  const anahtar = Buffer.from(sir.replace(/^whsec_/, ''), 'base64');
  const zaman = b['webhook-timestamp'];
  if (Math.abs(Date.now() / 1000 - Number(zaman)) > 300) return false;
  const beklenen = createHmac('sha256', anahtar).update(`${b['webhook-id']}.${zaman}.`).update(govde).digest('base64');
  return b['webhook-signature'].split(' ').some((p) => p.startsWith('v1,') && p.length - 3 === beklenen.length
    && timingSafeEqual(Buffer.from(p.slice(3)), Buffer.from(beklenen)));
}
csharp
using System.Security.Cryptography; using System.Text;
static bool ImzaGecerli(string sir, string id, string zaman, byte[] govde, string imzaBasligi) {
    if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - long.Parse(zaman)) > 300) return false;
    using var hmac = new HMACSHA256(Convert.FromBase64String(sir["whsec_".Length..]));
    var imzalanan = Encoding.UTF8.GetBytes($"{id}.{zaman}.").Concat(govde).ToArray();
    var beklenen = Encoding.ASCII.GetBytes(Convert.ToBase64String(hmac.ComputeHash(imzalanan)));
    return imzaBasligi.Split(' ').Where(p => p.StartsWith("v1,"))
        .Any(p => CryptographicOperations.FixedTimeEquals(Encoding.ASCII.GetBytes(p[3..]), beklenen));
}

Ham gövdeyi JSON'a çevirmeden önce imzayı doğrulayın (yeniden biçimlendirilmiş gövdenin imzası tutmaz). Tam örnekler ornekler/ klasöründedir.

Sınama

Çıkış ekranındaki "Bağlantıyı sına" sinama.ping gönderir ve yanıt kodunuzu gösterir; "Deneme gönder" son uygun içeriği deneme: true ile yollar.

Yazar Haber Ajansı Webhook Rehberi: Haberleri Yayınlandığı Anda Alın

Yazar Haber Ajansı webhook servisi, yeni bir haber servis edildiğinde, düzeltildiğinde veya iptal edildiğinde sizin belirlediğiniz https adresine imzalı bir POST isteği gönderir. Böylece sisteminiz "yeni haber var mı?" diye sürekli sormak zorunda kalmaz; haber hazır olduğu anda size gelir.

Webhook, YHA geliştirici belgeleri içindeki entegrasyon yöntemlerinden biridir. Varsayılan olarak tam içeriği taşır; isterseniz yalnızca kimlik ve adres taşıyan "ince" yükü seçip haberin ayrıntısını Yazar Haber Ajansı API ile alırsınız.

Push ve pull: webhook neden daha hızlı?

Haber almanın iki temel yolu vardır. Pull (çekme) modelinde sisteminiz belirli aralıklarla API'ye veya RSS beslemesine istek atar. Push (itme) modelinde ise ajans, bir olay gerçekleştiğinde size haber verir. Webhook bir push yöntemidir.

Kriter Pull (API akışı / RSS) Push (Webhook)
Gecikme Sorgulama aralığı kadar Saniyeler
Gereksiz istek Çok (çoğu sorguda yeni haber yoktur) Yok, yalnızca olay olduğunda
Kurulum Basit, yalnızca istemci Herkese açık bir HTTPS adresi gerekir
Kesinti durumunda Bir sonraki sorguda imleçten telafi edilir Ajans yaklaşık 24 saat yeniden dener
En uygun kullanım Basit siteler Son dakika ağırlıklı siteler, uygulamalar

Kendi tarafınızda herkese açık bir adres açamıyorsanız aynı hızı anlık akışla (SSE) da alabilirsiniz: bu kez bağlantıyı siz açarsınız ve olaylar birkaç saniye içinde gelir.

Webhook kurulumu: adım adım

  1. Alıcı adresi hazırlayın. Sunucunuzda POST isteklerini kabul eden bir adres oluşturun (ör. https://siteniz.com/yha-webhook). Adres yalnızca https olabilir; bağlantı noktası 443 ya da 1024–65535 aralığında olmalıdır. Özel ve yerel ağ adresleri reddedilir.
  2. Çıkışı açın. YHA Abone · Çıkışlar ekranında webhook türünde bir çıkış açın ve adresi girin. Çıkışın imza sırrı whsec_ önekiyle başlar.
  3. Sırrı güvenle saklayın. Sırrı sunucunuzda ortam değişkeni olarak tanımlayın; kod deposuna veya paylaşılan belgelere yazmayın.
  4. İmza doğrulamayı ekleyin. Aşağıdaki örneklerden kendi dilinize uygun olanı kullanarak her isteğin gerçekten YHA'dan geldiğini doğrulayın.
  5. Sınayın. Çıkış ekranındaki "Bağlantıyı sına" sinama.ping gönderir ve yanıt kodunuzu gösterir; "Deneme gönder" son uygun içeriği deneme: true ile yollar; "Alıcıyı denetle" alıcınızın imzayı gerçekten doğrulayıp doğrulamadığını ölçer (aşağıda).

Güvenlik duvarınız gelen istekleri süzüyorsa ajansın çıkış adreslerine izin verin; adresler canlıya geçişte yayımlanır ve değişiklik 30 gün önceden duyurulur.

Olay türleri

Her bildirimin gövdesinde bir olay_turu bulunur:

olay_turu Ne zaman gönderilir Sizin yapmanız gereken
haber.yeni Haber ilk kez servis edildiğinde Haberi içe aktarın ya da editör kuyruğuna ekleyin
haber.duzeltme Haberin yeni sürümü servis edildiğinde surum_no büyükse mevcut yazıyı güncelleyin
haber.iptal Haber iptal edildiğinde Yayından kaldırın
varlik.yeni, varlik.iptal, varlik.guncelleme Tek başına servis edilen fotoğraf ya da video yeni geldiğinde, iptal edildiğinde ya da bilgisi değiştiğinde Medya kütüphanenizi güncelleyin
sinama.ping "Bağlantıyı sına" düğmesinde 2xx dönün

İptal olayını mutlaka işleyin. Ajans bir haberi iptal ettiğinde sizin sitenizde yayında kalması yanlış bilginin yayılmasına ve hukuki risklere yol açabilir; abonelik koşulları da iptal edilen içeriğin yayından kaldırılmasını ister. Yeni olay türleri geriye uyumlu eklemedir: tanımadığınız olay_turu'nu 2xx ile kabul edip yok sayın.

Gövde

İstek POST yöntemiyle, Content-Type: application/json ve User-Agent: YHA-Webhook/1 başlıklarıyla gelir:

{
  "surum": 1,
  "olay_turu": "haber.duzeltme",
  "zaman": "2026-10-07T11:19:02Z",
  "deneme": false,
  "veri": { "olay_id": "…", "olay": "duzeltme", "icerik": "haber", "haber": { "no": "H-001230", "surum_no": 2, "…": "…" }, "varlik": null }
}

veri, API'deki akışla aynı olay nesnesidir (DisOlay): içinde haberin başlığı, spotu, gövdesi, kategorisi, embargo bilgisi, kullanım notu ve medya bilgisi bulunur. Gövde 256 KB'ı aşarsa govde boşaltılır ve govde_kesildi: true gelir; bu durumda tam metni API'den alın. Profilde "ince" yük seçilirse veri yalnızca olay_id, olay, icerik, id, no, surum_no ve adres taşır.

İmza doğrulama (Standard Webhooks)

Webhook adresiniz internete açık olduğundan herkes oraya sahte bir istek gönderebilir. YHA her isteği Standard Webhooks biçiminde imzalar ve üç başlık gönderir:

webhook-id: <teslim kimliği>          (yeniden denemelerde aynı)
webhook-timestamp: 1791371942          (Unix saniye)
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=

İmzalanan metin <webhook-id>.<webhook-timestamp>.<ham gövde>'dir. Anahtar, sırrın whsec_ önekinden sonraki kısmının base64 çözülmüş baytlarıdır; imza HMAC-SHA256 ile hesaplanır ve base64 olarak v1, önekiyle yazılır.

Önemli kurallar:

  • İmzayı ham gövde üzerinden hesaplayın; JSON'u çözüp yeniden yazmak imzayı bozar.
  • Karşılaştırmayı sabit zamanlı fonksiyonla yapın (hash_equals, timingSafeEqual, compare_digest).
  • webhook-timestamp şimdiye göre ±5 dakika dışındaysa reddedin (tekrar oynatma saldırısı).
  • Sır döndürüldüğünde eski sır 24 saat daha geçerlidir ve başlık iki imza taşır (v1,<yeni> v1,<eski>); birinin tutması yeterlidir.
  • İmza tutmazsa 401 dönün ve hiçbir iş yapmayın.

PHP

<?php
$sir     = getenv('YHA_WEBHOOK_SIRRI');                 // whsec_...
$govde   = file_get_contents('php://input');            // ham gövde
$wid     = $_SERVER['HTTP_WEBHOOK_ID'] ?? '';
$zaman   = $_SERVER['HTTP_WEBHOOK_TIMESTAMP'] ?? '';
$imzalar = $_SERVER['HTTP_WEBHOOK_SIGNATURE'] ?? '';

if (!ctype_digit($zaman) || abs(time() - (int) $zaman) > 300) {
    http_response_code(401); exit;
}
$anahtar  = base64_decode(preg_replace('/^whsec_/', '', $sir), true);
$beklenen = base64_encode(hash_hmac('sha256', "{$wid}.{$zaman}.{$govde}", $anahtar, true));
$gecerli  = false;
foreach (explode(' ', $imzalar) as $p) {
    if (str_starts_with($p, 'v1,') && hash_equals($beklenen, substr($p, 3))) { $gecerli = true; }
}
if (!$gecerli) { http_response_code(401); exit; }

kuyruga_ekle($wid, json_decode($govde, true));          // webhook-id ile tekrarı ayıklayın
http_response_code(200);

JavaScript (Node)

// govde ham Buffer olmalı (ör. express.raw({ type: 'application/json' }))
import { createHmac, timingSafeEqual } from 'node:crypto';
export function imzaGecerli(sir, b, govde) {
  const anahtar = Buffer.from(sir.replace(/^whsec_/, ''), 'base64');
  const zaman = b['webhook-timestamp'];
  if (Math.abs(Date.now() / 1000 - Number(zaman)) > 300) return false;
  const beklenen = createHmac('sha256', anahtar).update(`${b['webhook-id']}.${zaman}.`).update(govde).digest('base64');
  return b['webhook-signature'].split(' ').some((p) => p.startsWith('v1,') && p.length - 3 === beklenen.length
    && timingSafeEqual(Buffer.from(p.slice(3)), Buffer.from(beklenen)));
}

Python

import base64, hmac, hashlib, time

def imza_gecerli(sir: str, b: dict, govde: bytes) -> bool:
    anahtar = base64.b64decode(sir.removeprefix("whsec_"))
    wid, zaman = b["webhook-id"], b["webhook-timestamp"]
    if abs(time.time() - int(zaman)) > 300:
        return False
    beklenen = base64.b64encode(
        hmac.new(anahtar, f"{wid}.{zaman}.".encode() + govde, hashlib.sha256).digest()).decode()
    return any(hmac.compare_digest(p[3:], beklenen)
               for p in b["webhook-signature"].split() if p.startswith("v1,"))

Dört dilde (Python, JavaScript, PHP, C#) çalışır alıcılar entegrasyon kitinde bulunur.

Hızlı 2xx yanıt ve kuyruk

Ajans yanıt için 10 saniye bekler ve yönlendirmeleri izlemez (3xx hata sayılır). Alıcınızın tek görevi isteği doğrulamak, kaydetmek ve hemen 2xx dönmektir. Haberi API'den çekmek, görselleri indirmek, yazıyı oluşturmak gibi uzun işleri aynı istek içinde yapmayın.

Önerilen akış ("dürt ve çek"):

  1. Gövdeyi ham bayt olarak okuyun, imzayı ve zaman damgasını doğrulayın.
  2. Olayı veritabanına veya bir kuyruğa yazın.
  3. 2xx dönün.
  4. Arka planda çalışan işçi olayları işlesin; ince yükte ya da kesilmiş gövdede içeriği akıştan çeksin.

Aynı olay iki kez gelirse

Yeniden denemeler nedeniyle aynı bildirim birden fazla kez gelebilir. webhook-id'yi en az 24 saat saklayın; yeniden gelirse 2xx dönün ama işlemeyin. Ayrıca haberleri kendi kimlikleriyle eşleştirin; böylece haber.yeni iki kez gelse bile tek yazı oluşur.

Sıra garantisi yoktur (flaş öne geçebilir): eski bir düzeltme yeni sürümden sonra gelirse surum_no ile yok sayın.

Yanıtınız ve yeniden deneme

Yanıtınız Ajans ne yapar
2xx Teslim edildi
5xx, 408, 429, 401, 403, 404, 3xx, bağlantı hatası Yeniden dener: 30 sn, 1 dk, 2 dk, 5 dk, sonra 15 dakikada bir (yaklaşık 24 saat); 429'da Retry-After'a uyar
400, 413, 422 Bu içerik için vazgeçer
410 Çıkışı duraklatır ve size bildirir

Art arda hatalar sürerse çıkış "arızalı" görünür, Teknik Destek uyarılır ve her 15 dakikada yalnızca bir deneme yapılır; ilk başarıda biriken içerik sırayla gider. Uzun bir kesintiden sonra eksik kalan olayları API'deki akıştan saklanan imleçle tamamlayabilirsiniz. Ajans tarafındaki kesintileri YHA servis durumu sayfasından takip edebilirsiniz.

Alıcı denetimi

En sık entegrasyon hatası imzanın doğrulanmamasıdır. Webhook çıkışının ayrıntısındaki "Alıcıyı denetle" düğmesi alıcınıza dört sınama isteği gönderir (olay_turu: "sinama.denetim", deneme: true):

No İstek Beklenen
1 Doğru imza 2xx
2 Bozuk imza 400, 401 ya da 403
3 Doğru imza, 10 dakika eski zaman damgası 400, 401 ya da 403
4 Aynı webhook-id, doğru imza 2xx (sessizce kabul)

Profil başına saatte en çok 6 denetim yapılabilir. Ayrıntılar: Alıcı denetimi.

Güvenlik kontrol listesi

  • Adres yalnızca HTTPS üzerinden çalışmalı.
  • İmza sırrını kodun içine değil, ortam değişkenine veya gizli anahtar kasasına koyun.
  • İmza ve zaman damgası doğrulaması olmadan hiçbir olayı işlemeyin.
  • Adresi tahmin edilemez yapmak ek bir katmandır ama imzanın yerini tutmaz.
  • Gövdedeki metni sitenize basmadan önce HTML açısından temizleyin (XSS'e karşı).
  • Sırrı döndürürken geçiş süresinde iki imzayı da kabul eden kodu kullanın.

Örnek akış: son dakika haberi sitenize nasıl ulaşır?

Ajans editörü haberi onaylar ve servis eder. Birkaç saniye içinde YHA, sizin adresinize haber.yeni olayını gönderir. Alıcınız imzayı doğrular, olayı kuyruğa yazar ve 2xx döner. Arka plandaki işçi olaydaki haberi alır, gerekiyorsa medyayı API'den indirir ve sitenizde taslak ya da doğrudan yayında bir yazı oluşturur. Embargo bilgisi varsa yazıyı embargo saatine zamanlar. Dakikalar sonra ajans haberi düzelttiğinde haber.duzeltme gelir ve aynı yazı surum_no karşılaştırmasıyla güncellenir.

İzleme ve loglama

Webhook entegrasyonu sessizce bozulabilir: bir sertifikanın süresi dolar, bir güvenlik kuralı değişir ya da sunucu taşınır. Bunu erken fark etmek için:

  • Gelen her olay için zaman, olay_turu, webhook-id ve döndürdüğünüz durum kodunu kaydedin.
  • Kuyrukta bekleyen olay sayısını izleyin; sayı sürekli artıyorsa işçiniz yetişemiyor demektir.
  • Başarısız imza doğrulamalarını ayrıca sayın; ani artış yanlış yapılandırmaya veya kötü niyetli denemelere işaret eder.
  • YHA Abone'deki çıkış durumunu ve teslim listesini düzenli kontrol edin.

Sık karşılaşılan hatalar ve çözümleri

Belirti Olası neden Çözüm
Her istek 401 dönüyor İmza yeniden biçimlendirilmiş gövde üzerinden hesaplanıyor ya da sır base64 çözülmüyor Ham gövdeyi kullanın; whsec_ önekini atıp sırrı base64 çözün
İmza bazen tutuyor, bazen tutmuyor Sunucu saati kaymış ya da döndürmede tek imza denetleniyor NTP ile saati eşitleyin; başlıktaki tüm v1, imzalarını deneyin
Aynı haber birden çok kez oluşuyor 10 saniyede yanıt verilmedi, yeniden denendi Önce 2xx dönün, işi kuyruğa bırakın; webhook-id'yi saklayın
Hiç bildirim gelmiyor Güvenlik duvarı, CDN veya WAF isteği engelliyor; adres yönlendiriyor Çıkış adreslerine izin verin, yönlendirmesiz son adresi girin
Gövde eksik İnce yük seçili ya da govde_kesildi: true İçeriği API'den alın
Çıkış duraklatılmış Alıcı 410 döndü ya da uzun süre hata verdi Sorunu giderin, çıkışı yeniden etkinleştirin

WordPress sitelerinde webhook

WordPress sitesi için alıcıyı sıfırdan yazmanız gerekmez. Ajansın WordPress eklentisi "Anlık" kipte çalışırken ajans sitenizin POST /wp-json/yha-haber/v1/bildirim yolunu imzalı bir istekle dürter ve eklenti hemen akıştan çeker. Bunun için paketinizde webhook kanalı açık olmalı ve güvenlik eklentiniz bu yolu engellememelidir. Ayrıntılar: YHA WordPress eklentisi.

Push ve pull modelinin farkını genel hatlarıyla webhook nedir? rehberinde anlattık.

Sıkça Sorulan Sorular

Yazar Haber Ajansı webhook'u nasıl etkinleştirilir?

Paketinizde webhook kanalı açık olmalıdır (otomatik çıkışlar pakete sözleşmeyle eklenir). Ardından YHA Abone · Çıkışlar'da webhook türünde çıkış açar, adresinizi girer ve imza sırrını sunucunuza eklersiniz. "Bağlantıyı sına" ile alıcınızın çalıştığını doğrulayın.

Webhook mı, RSS mi kullanmalıyım?

Saniyeler önemliyse webhook ya da anlık akış; basit bir kurulum istiyorsanız RSS. İkisini birlikte kullanmak da mümkündür.

Localhost'ta webhook test edebilir miyim?

Hayır; ajans yalnızca genel internet adreslerine ve https adreslerine bağlanır. Geliştirme sırasında yerel sunucuyu geçici olarak internete açan bir tünel aracı kullanabilir ya da deneme ortamındaki anlık akışla çalışabilirsiniz.

Aynı haber sitemde iki kez yayınlandı, neden?

Büyük olasılıkla alıcınız 10 saniye içinde yanıt vermedi ve bildirim yeniden gönderildi. Hızlı 2xx yanıtı ve webhook-id kontrolü bu sorunu çözer.

Webhook isteklerinin sırası garanti mi?

Hayır. Flaş haberler öne geçebilir; eski düzeltmeyi surum_no ile yok sayın.