Panelde webhook’ları kur, teslimatları al ve HMAC imzasını doğrula – curl, Node.js ve PHP örnekleriyle.
Bir webhook, çalışma alanında bir şey olduğu anda sunucuna bir HTTP isteği gönderir – örneğin bir sayfa yayınlandığında. Böylece bir şeyin değişip değişmediğini sürekli sorman gerekmez. Sunucunun gerçek mesajları sahtelerinden ayırabilmesi için her teslimat imzalanır.
Gereksinimler
- Çalışma alanında sahip veya yönetici – “Webhook’lar” menü öğesi yalnızca bu roller için görünür
- Creator Pro’dan itibaren; Creator Free’de “Webhook’lar Creator Pro’dan itibaren kullanılabilir.” yazar
- Creator Pro’da en fazla 5, Creator Agency’de 25, Enterprise’da 100 webhook (ayarlanabilir)
- Herkese açık bir https adresinden erişilebilen bir sunucu
Webhook’ları yalnızca panelde yönetirsin. API anahtarlarıyla oluşturulamaz veya değiştirilemezler.
Webhook oluştur
- Gezinmede “Webhook’lar”ı aç
- “+ Yeni webhook”a tıkla
- Hedef URL’yi gir ve olayları seç
- İsteğe bağlı: bir açıklama gir ve durumu seç
- “Webhook oluştur”a tıkla
- “Bitti” adımında imzalama anahtarını (“İmzalama anahtarı – yalnızca şimdi görünür”) kopyala ve sunucunda sakla – yalnızca şimdi gösterilir
- Webhook’u “Test” ile test et. Sonuç bir sonraki teste kadar kartta kalır: “Başarıyla teslim edildi” ya da HTTP koduyla (veya “yanıt yok”) “Teslim edilmedi”, süre ve yanıtın başlangıcı
- “Hedef URL (https://…)”
- En fazla 2048 karakter. Yalnızca https, URL’de kimlik bilgisi yok, localhost adresi yok ve .local, .internal veya .lan gibi dahili adlar yok. Ad herkese açık IP adreslerini göstermelidir; LinkHarbor bunu her teslimattan önce yeniden kontrol eder.
- “Olaylar”
- En az bir olay. Her grupta “Tümünü seç” ve “Seçimi kaldır” vardır.
- “Açıklama”
- İsteğe bağlı, en fazla 255 karakter – örneğin webhook’un ne için olduğu.
- “Durum”
- “Aktif” veya “Devre dışı”. Devre dışı webhook’lar teslimat almaz.
Olaylar
| Olay | Panelde | Ne zaman | data içeriği |
|---|---|---|---|
| page.published | Sayfa yayınlandı | Bir sayfa yayınlandı – panelde, API üzerinden veya bir yapay zekâ asistanı tarafından | page_id, version, checksum, published_by_user_id (API anahtarları ve yapay zekâ asistanları için null) |
| form.submitted | Form gönderildi | Bir ziyaretçi sayfalarından birinde bir form gönderdi | form_id, form_name, submission_id, page_id, block_id, submitted_at, values (alan anahtarı → değer), consent (onay anahtarı → true/false) |
| domain.verified | Alan adı doğrulandı | Özel bir alan adı başarıyla doğrulandı | domain_id, hostname, verification_method, status |
| domain.disabled | Alan adı devre dışı bırakıldı | Özel bir alan adı panelde devre dışı bırakıldı (plan düşürmede değil) | domain_id, hostname, status |
| webhook.test | – (“Test” düğmesi) | “Test”e tıkladığında | message (testi başlatan kişinin hesap dilinde bir not; buna göre eşleştirme yapma) |
form.submitted değerleri tam olarak ziyaretçinin gönderdiği gibi içerir ama asla IP adresini veya tarayıcısını içermez. Teslimat arka planda çalışır: ziyaretçi onu beklemez ve başarısız bir teslimat gönderimi engellemez.
Bir teslimatın yapısı
LinkHarbor her teslimatı JSON gövdeli bir POST olarak ve şu başlıklarla gönderir:
| Başlık | İçerik |
|---|---|
| Content-Type | application/json |
| X-LinkHarbor-Event | Olayın adı, örneğin page.published |
| X-LinkHarbor-Delivery-Id | Bu teslimatın benzersiz kimliği (UUID), gövdedeki id ile aynı |
| X-LinkHarbor-Timestamp | Unix saniyesi cinsinden gönderim zamanı |
| X-LinkHarbor-Signature | sha256= ardından hex olarak HMAC-SHA256 imzası |
| X-LinkHarbor-Signature-Version | v1 |
{
"id": "3f1c2a9e-8d4b-4a51-9f0e-6b7c1d2e3f40",
"event": "page.published",
"created_at": "2026-11-01T09:30:12+00:00",
"data": {
"page_id": 42,
"version": 8,
"checksum": "9b1e5c…",
"published_by_user_id": 7
}
} Yeniden teslimatlar yeni bir id ile birlikte redelivery_of (tekrarlanan teslimatın kimliği) ve delivery_root (bu zincirdeki ilk teslimatın kimliği) alanlarını alır.
İmzayı doğrula
Her webhook’un kendi imzalama anahtarı (32 hex karakter) vardır. Onu tam olarak bir kez görürsün: webhook’u oluştururken son adımda ve “Gizli anahtar ↺”dan hemen sonra. Onu hemen sunucuna kopyala – LinkHarbor onu daha sonra yeniden göstermez. LinkHarbor imzayı onunla şöyle hesaplar:
- Mesajı oluştur: zaman damgası, nokta, teslimat kimliği, nokta, ham gövde – yani timestamp.delivery_id.body
- Bu mesaj üzerinde anahtar olarak imzalama anahtarıyla HMAC-SHA256 hesapla
- Sonucu sha256= önekiyle bir hex dizesi olarak gönder
Sunucun imzayı sabit zamanlı bir karşılaştırmayla kontrol etmeli, zaman damgası 300 saniyeden eski teslimatları reddetmeli ve tekrarları tanımak için teslimat kimliklerini en az bu süre boyunca saklamalıdır. Önemli: imzalanan, tam olarak geldiği gibi ham gövdedir – yeniden kodladığın JSON değil.
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const SECRET = process.env.LH_WEBHOOK_SECRET;
const seen = new Set(); // canlı ortamda: süre sonlu bir veritabanı veya Redis
app.post('/webhooks/linkharbor', express.raw({ type: 'application/json' }), (req, res) => {
const ts = req.get('X-LinkHarbor-Timestamp') || '';
const id = req.get('X-LinkHarbor-Delivery-Id') || '';
const sig = req.get('X-LinkHarbor-Signature') || '';
if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) {
return res.status(400).send('timestamp');
}
const expected = 'sha256=' + crypto
.createHmac('sha256', SECRET)
.update(ts + '.' + id + '.')
.update(req.body) // Buffer olarak ham gövde
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(sig);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).send('signature');
}
const event = JSON.parse(req.body.toString('utf8'));
const key = event.delivery_root || event.id; // aynı zincirin yeniden teslimatlarını tanı
if (!seen.has(key)) {
seen.add(key);
// burada işle, tercihen bir kuyrukta eşzamansız olarak
}
res.sendStatus(200);
});
app.listen(3000); <?php
$secret = getenv('LH_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_LINKHARBOR_TIMESTAMP'] ?? '';
$id = $_SERVER['HTTP_X_LINKHARBOR_DELIVERY_ID'] ?? '';
$sig = $_SERVER['HTTP_X_LINKHARBOR_SIGNATURE'] ?? '';
if (!ctype_digit($ts) || abs(time() - (int)$ts) > 300) {
http_response_code(400);
exit('timestamp');
}
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $id . '.' . $body, $secret);
if (!hash_equals($expected, $sig)) {
http_response_code(401);
exit('signature');
}
$event = json_decode($body, true);
// Yinelenen teslimatları $event['delivery_root'] ?? $event['id'] ile tanı,
// ardından işle.
http_response_code(200); Uç noktanı curl ile test et
Bu betik kendi sunucuna doğru imzalanmış bir test teslimatı gönderir – webhook’u LinkHarbor’da oluşturmadan önce kullanışlıdır:
SECRET="imzalama-anahtarin"
URL="https://example.com/webhooks/linkharbor"
TS=$(date +%s)
ID=$(uuidgen | tr 'A-Z' 'a-z')
BODY='{"id":"'"$ID"'","event":"webhook.test","created_at":"2026-11-01T09:30:12+00:00","data":{"message":"Bu, bu webhook için bir test olayıdır."}}'
SIG="sha256=$(printf '%s' "$TS.$ID.$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')"
curl -X POST "$URL" \
-H "Content-Type: application/json" \
-H "X-LinkHarbor-Event: webhook.test" \
-H "X-LinkHarbor-Delivery-Id: $ID" \
-H "X-LinkHarbor-Timestamp: $TS" \
-H "X-LinkHarbor-Signature: $SIG" \
-H "X-LinkHarbor-Signature-Version: v1" \
-d "$BODY" Yanıt, zaman aşımı ve yeniden teslimat
- 2xx durumlu her yanıt başarı sayılır; yönlendirmeler (3xx) izlenmez
- Sunucunun yanıt vermek için 10 saniyesi ve bağlantıyı kurmak için en fazla 5 saniyesi vardır
- Bir olayın tüm webhook’ları toplam 25 saniyeyi paylaşır; o zamana kadar sırası gelmeyenler başarısız olarak işaretlenir ve yeniden teslim edilebilir
- LinkHarbor başarısız teslimatları otomatik olarak yeniden denemez
- Başarısız teslimatları elle yeniden gönderebilirsin, ama bu arada başarılı olmuş birini değil. Yeniden teslimatın yeni bir id’si ve yeni bir created_at’i vardır
- Olay başına ilk teslimat dahil en fazla 3 denemeye izin verilir; sonrasında “Ölü mektuplar” altına düşer ve artık yeniden gönderilemez
Paneldeki teslimatlar
“Teslimatlar” bir webhook’un kaydını açar. Üç sekmesi vardır:
- “Tüm teslimatlar”
- Olay, durum (“Başarılı (2xx)”, “İstemci hatası (4xx)”, “Sunucu hatası (5xx)”, “Başarısız”) ve “Limit” filtreleriyle tüm teslimatlar. “↺ Tekrar dene”, daha sonra başarılı bir teslimat olmadığı sürece başarısız bir teslimatı yeniden teslim eder. Bir satıra tıklamak isteği, yanıtı, gövdeyi ve ham JSON’u gösterir.
- “Yeniden oynatmalar”
- “Düzeldi” veya “Hâlâ başarısız” sonucu ve deneme sayısıyla yeniden teslimat zincirleri.
- “Ölü mektuplar”
- İzin verilen her denemenin başarısız olduğu teslimatlar – ilk teslimat ve yeniden teslimatlar birlikte. Sekme yalnızca görüntülemek içindir: artık yeniden teslim edilemezler. Uç noktanı kontrol et; yeni olaylar ardından her zamanki gibi teslim edilir. Verilere ihtiyacın varsa API üzerinden çek.
Bir yeniden teslimat gerçekleşmezse panel nedenini söyler:
- “Yeniden teslim edilmedi: bu olay zaten … kez başarısız oldu, daha fazla deneme yapılamaz. ‘Ölü mektuplar’ altında bulabilirsin.”
- 3 denemenin tamamı kullanıldı.
- “Yeniden teslim edilmedi: bu olay bu arada başarıyla teslim edildi.”
- Aynı zincirdeki sonraki bir teslimat zaten başarılı oldu.
Panelde doğrulama
“Doğrulama” altında iki yardımcı bulursun:
- “Doğrulama kiti”
- “Kiti yükle” algoritmayı, başlık adlarını, imzalanan mesajın biçimini ve önerilen 300 saniyelik toleransı gösterir. Gizli anahtarın kendisi dahil değildir.
- “İmzayı doğrula”
- Aldığın bir teslimatın teslimat kimliğini, zaman damgasını, imzasını ve ham istek gövdesini gir. LinkHarbor ardından “İmza geçerli” veya “İmza geçersiz” der. Zaman damgasını ve imzayı X-LinkHarbor-Timestamp ve X-LinkHarbor-Signature başlıklarından kopyala. Kontrol yalnızca son 5 dakikadaki teslimatlar için çalışır; daha eskiler için imza doğru olsa bile “İmza geçersiz” bildirir.
Gizli anahtarı yenile, devre dışı bırak, sil
- “Gizli anahtar ↺” yeni bir imzalama anahtarı oluşturur ve bir kez gösterir; eskisi hemen çalışmayı bırakır ve sunucunun yenisini kullanması gerekir
- Teslimatları duraklatmak için “Düzenle” altında durumu “Devre dışı” olarak ayarla
- Çöp kutusu simgesi webhook’u siler; mesajı kapatana kadar “Geri al” ile iptal edebilirsin
Daha küçük bir plana geçtiğinde yeni limiti aşan webhook’lar, Creator Free’de ise hepsi devre dışı bırakılır. Korunurlar; bir yükseltmeden sonra LinkHarbor devre dışı webhook’ları yeni planın limitine kadar otomatik olarak yeniden etkinleştirir – kendin devre dışı bıraktıkların dahil.
Bunlar da işine yarayabilir
Bir şey bulamadın mı?
Neye ihtiyacın olduğunu bize anlat, destek ekibimiz sana kişisel olarak yardımcı olsun.