Webhook'lar
HMAC-SHA256 imzalı olay gönderimleri; üstel geri çekilmeyle (exponential backoff) 5 yeniden deneme; panelden veya API'den yeniden gönderim. 16 olay tipi, gizli anahtar yenileme süresi (grace window).
Webhook'lar Moonborn'un çalışma zamanı olaylarını yığınına ittiği (push) yoldur — persona yaşam döngüsü, üretim hattı sonuçları, faturalama değişiklikleri, moderasyon işaretleri. Bugün 16 gerçek olay tipi gönderilir; her gönderim HMAC-SHA256 ile imzalıdır, beş yeniden denemesi vardır, başarısız gönderimler yeniden gönderilebilir.
Bu sayfayı bitirdiğinde
- Bir webhook'a abone olmanın kod akışını bileceksin.
- HMAC-SHA256 imzasını doğrulayabileceksin (zaman güvenli — timing safe).
- 5 yeniden deneme zamanlamasını ve dead-letter (ölü mektup) davranışını anlayacaksın.
- Başarısız gönderimleri yeniden gönderebileceksin (replay).
- İmza gizli anahtarını yenileyebileceksin (rotate) (60 dakikalık geçiş süresi).
- Webhook'un kenar tetiklemeli (edge-triggered) olduğunu ve akış (streaming) alternatifini ayırt edebileceksin.
Ön koşul: API anahtarı + uç nokta URL'i (HTTPS, açıkça erişilebilir).
Abone ol
const hook = await client.webhooks.create({
url: 'https://your-app.com/webhooks/moonborn',
events: ['persona.created', 'persona.audit_failed'],
description: 'Production listener',
});
console.log(hook.signingSecret);
// ⚠ Bu gizli anahtar tam olarak BİR KEZ döner. Şimdi sakla; ikinci bir okuma yok.events: ['*'] tüm tiplere abone olur; üretimde olay başına liste önerilir (işleyiciyi sıkı tutmak ve gereksiz trafiği önlemek için).
Tam olay kataloğu: Webhook olayları.
İmza doğrulama
Her gönderim X-Moonborn-Signature başlığını taşır:
X-Moonborn-Signature: t=1747497600,v1=2c4f8a...t— Unix zaman damgası (saniye, imzalama anı)v1—HMAC-SHA256(secret, "{t}.{rawBody}"), onaltılık (hex) kodlanmış
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(rawBody: string, header: string, secret: string): boolean {
const parts = Object.fromEntries(
header.split(',').map((p) => p.split('=', 2) as [string, string]),
);
const t = Number(parts['t']);
const v1 = parts['v1'];
// Yeniden gönderim penceresi — 5 dakikadan eski gönderimleri reddet
if (Math.abs(Date.now() / 1000 - t) > 300) return false;
const signed = `${t}.${rawBody}`;
const expected = createHmac('sha256', secret).update(signed).digest('hex');
return v1.length === expected.length &&
timingSafeEqual(Buffer.from(v1, 'hex'), Buffer.from(expected, 'hex'));
}Yeniden deneme politikası
| Deneme | Gecikme |
|---|---|
| 1 | anında |
| 2 | 1 dakika |
| 3 | 5 dakika |
| 4 | 30 dakika |
| 5 | 2 saat |
Beş başarısızlık sonrası gönderim dead-letter (ölü mektup) kuyruğuna iner. Uç nokta aktif kalır — sonraki olaylar hâlâ gönderim denemesi yapar. Uç noktayı tamamen devre dışı bırakmak istiyorsan DELETE /v1/webhooks/{id}.
Yeniden deneme zamanlaması geçersiz kılınabilir (api.webhooks.retry.* organizasyon yapılandırması; Enterprise planı).
Yeniden gönderim (replay)
Başarısız gönderimleri yeniden denemeye sokmak:
const failed = await client.webhooks.deliveries.list({
webhookId: hook.id,
status: 'failed',
range: '7d',
});
for (const d of failed.data) {
await client.webhooks.deliveries.replay({
webhookId: hook.id,
deliveryId: d.id,
});
}Yeniden gönderim orijinal yük (payload) + imza zaman damgasını korur. İşleyicin idempotent olmalı; tekrar tespit (dedupe) anahtarı olarak olay yükünün id alanını kullan:
if (await redis.set(`webhook:${event.id}`, '1', { NX: true, EX: 86400 })) {
// Yeni olay — işle
await handleEvent(event);
}
// Aksi halde daha önce işlenmiş, atlaTest gönderimi — uç nokta sağlığı
await client.webhooks.ping({ id: hook.id });Sentetik bir webhook.endpoint.test_ping olayı tetiklenir. Gerçek bir olay beklemeden alıcıyı doğrulayabilirsin. Yanıt 200 ise uç nokta sağlıklıdır.
Gizli anahtar yenileme (secret rotation)
const result = await client.webhooks.rotateSecret({ id: hook.id });
console.log(result.newSecret);
// Eski gizli anahtar 60 dakika daha geçerli kalır60 dakikalık geçiş penceresi süresince iki imza paralel gelir — biri eski gizli anahtarla, biri yeni. Alıcını iki adayı da doğrulayacak şekilde yaz:
const valid = candidates.some((v1) => timingSafeEqual(...));Detay: Webhook imza doğrulama — gizli anahtar yenileme bölümü.
Geçiş penceresi geçersiz kılma: api.webhooks.secret_rotation_grace_minutes (varsayılan 60, en fazla 1440 / 24 saat).
Akış (streaming) alternatifi — ne zaman webhook değil
Webhook'lar kenar tetiklemelidir (edge-triggered): bir şey oldu, bir kez gönderim, sonu var. Şu durumlarda webhook değil akış kullan:
- Üretim hattı ilerlemesi —
POST /v1/personas?stream=trueSSE. Adım adım ilerleme webhook'a sığmaz. - Token-token sohbet yanıtı —
POST /v1/chat/sessions/{id}/messages?stream=trueSSE. - Gerçek zamanlı drift paneli — webhook toplu (batch), panel için yoklama (polling) daha temiz.
Detay: Akış desenleri.
Plan gereksinimi
Team ve üzeri. Pro planında özel olay aboneliği yoktur; Free + Pro yoklama tabanlıdır.
Dürüst kapsam
İlgili
Üretim-hazır HMAC + yeniden gönderim penceresi + gizli anahtar yenileme deseni.
Drift webhook'unu uçtan uca QA kuyruğuna bağlama.
16 olay tipi ve yük şemaları.
Webhook'un alternatifi — token-token akış için SSE.