kerte.

Webhook

Olaylar sistemine push edilir: imzalı payload, yeniden deneme, doğrulama.

Webhook, bir şey olduğunda Kerte’nin senin sunucuna imzalı bir HTTP POST göndermesidir. Sürekli sorgulamak (polling) yerine olayı anında alırsın.

Konsolda Yönetim → Webhooks’tan bir uç (endpoint) URL’i tanımlar, hangi olayları istediğini seçersin. Kerte sana bir imza anahtarı (secret) verir.

Olaylar

OlayNe zaman
employee.syncedİşyeri çalışan senkronu bitti
tesvik.calculation.completedTeşvik hesaplaması tamamlandı
tesvik.error.detectedHatalı teşvik tespit edildi
e-vizite.report.createdYeni istirahat raporu senkron edildi
e-vizite.approval.changedRapor onay durumu değişti
subscription.updatedAbonelik/kapsam değişti
invoice.paidFatura ödendi

Payload

Gövde her zaman aynı zarfı taşır; olaya özel alanlar data içindedir.

{
  "id": "evt_2b9f…",
  "type": "tesvik.calculation.completed",
  "createdAt": "2026-09-12T10:00:00Z",
  "data": {
    "workplaceId": "wp_…",
    "period": "2026-08",
    "total": 128450.75
  }
}

Başlıklar:

X-Kerte-Event: tesvik.calculation.completed
X-Kerte-Delivery: dl_7c1a…
X-Kerte-Signature: t=1734560000,v1=5f2b…e9
Content-Type: application/json

İmza doğrulama

İmza, t (unix saniye) ve gövdenin ham hâli üzerinden hesaplanır: HMAC-SHA256(secret, "{t}.{rawBody}"), hex.

Ham gövdeyi al

İmza ayrıştırılmamış gövde üzerinden hesaplanır. Framework’ün JSON’u parse etmeden önce ham metni yakala (req.rawBody).

İmzayı yeniden üret

Başlıktaki t ile ham gövdeyi . ile birleştir, endpoint secret’ıyla HMAC-SHA256 al.

Sabit-zamanlı karşılaştır

Ürettiğin değeri başlıktaki v1 ile sabit zamanlı karşılaştır (timingSafeEqual). Eşleşmezse isteği reddet.

Tazeliği kontrol et

t şimdiden 5 dakikadan eskiyse reddet: yakalanmış bir isteğin tekrar oynatılmasını (replay) engeller.

Node örneği:

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(",").map((kv) => kv.split("=")),
  );
  const expected = createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 ?? "");
  if (a.length !== b.length || !timingSafeEqual(a, b)) return false;
  // Tazelik: 5 dk
  return Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
}

PHP örneği:

[$t, $v1] = [null, null];
foreach (explode(',', $sigHeader) as $p) {
  [$k, $val] = explode('=', $p, 2);
  if ($k === 't') $t = $val; if ($k === 'v1') $v1 = $val;
}
$expected = hash_hmac('sha256', "$t.$rawBody", $secret);
if (!hash_equals($expected, $v1 ?? '')) http_response_code(400);

Yeniden deneme

Ucun 2xx dönerse teslimat başarılı sayılır. Aksi halde Kerte üstel geri çekilmeyle 5 kez dener. Uç üst üste başarısız olursa otomatik olarak duraklatılır ve konsolda uyarı görürsün.

Idempotency

Aynı olay nadiren birden çok kez ulaşabilir (yeniden deneme). id (olay) ya da X-Kerte-Delivery başlığını bir kez işlediğini kaydet; tekrar gelirse atla.

En iyi pratikler

  • İmzayı her istekte doğrula; imzasız/yanlış imzalı isteği 400 ile reddet.
  • Secret’ı sızdırma; konsoldan istediğin an döndür (rotate).
  • Yalnız ihtiyacın olan olaylara abone ol.
  • Uç adresini panelden test-gönderimle doğrula.