# Webhooks

Kendi sisteminize olay gönderme
Kaynak: https://selwise.com/docs/outbound/webhooks

Selwise'ın topladığı olayları, siz bir uç nokta tanımladığınız anda kendi sisteminize HTTP `POST` isteğiyle gönderir. Bu sayfa panel ekranını ve kurulum akışını anlatır; isteğin gövdesi, imza doğrulama kodu ve tekilleştirme için bkz. [Webhook Payload ve İmza](/docs/outbound/webhook-payloads).

## Panelde nerede

Sol menüde **Ayarlar → Entegrasyonlar** (Settings → Integrations). Sayfadaki **Webhooks** bölümünde **Manage Webhooks** (Webhook'ları Yönet) bağlantısı listeye götürür. Doğrudan adres: `/dashboard/integrations/webhooks`; yeni kayıt için **Create Webhook** (Webhook Oluştur) düğmesi `/dashboard/integrations/webhooks/new`, düzenleme `/dashboard/integrations/webhooks/<id>` adresindedir.

Webhook'lar **kanala** aittir: üstteki kanal seçicide hangi kanal seçiliyse onun olayları gider. Kanal seçili değilse ekran "Please select a site first" (Önce bir site seçin) der.

## Tek dışa aktarım yolu

Selwise'tan dışarıya veri yalnızca webhook ile çıkar; olayları bir reklam ya da analitik platformuna kendisi aktarmaz. Böyle bir hedefe veri göndermeniz gerekiyorsa webhook'u kendi sisteminize bağlayın ve aktarımı oradan yapın. Ters yön, sitenizin mevcut `dataLayer` verisinden Selwise'ı beslemek, ayrı bir konudur: [Veri Katmanı](/docs/integration/data-layer).

## Ne için kullanılır

| Amaç | Örnek |
|---|---|
| Bülten ve kullanıcı olaylarını kendi sisteminize taşımak | `user_signup` olayını CRM'e yazmak |
| Kendi veri ambarınıza olay akıtmak | Seçtiğiniz olayları kendi API'nize göndermek |
| İç sistemleri tetiklemek | `purchase` olayında stok veya lojistik servisini çağırmak |

Selwise e-posta göndermez, adres toplamaz; webhook yalnızca olayı sizin uç noktanıza iletir.

## Liste ekranı

Her webhook bir kart olarak görünür: ad, adres, kimlik doğrulama rozeti, seçili olay sayısı (**Events** (Event)), **Delivered** (Teslim), **Failed** (Başarısız) ve **Last Status** (Son Durum). Kartın altında **Test** (Test Et), **Logs** (Loglar), **Edit** (Düzenle) ve silme düğmeleri vardır. Webhook **Active** değilse **Test** düğmesi gridir.

**Delivered** ve **Failed** olay sayar, deneme değil: bir olay ilk denemede ya da bir yeniden denemede `2xx` alırsa bir kez **Delivered**, bütün denemeler tükenirse bir kez **Failed** sayılır. Hâlâ yeniden denenen bir olay ikisinde de görünmez.

## Webhook tanımlama

| Alan | Açıklama |
|---|---|
| **Name** (Ad) | Panelde görünen ad, en fazla 255 karakter |
| **Endpoint URL** | `http://` veya `https://` ile başlayan, herkese açık adres |
| **Active** (Aktif) | Kapalıyken hiçbir olay gönderilmez ve test yapılamaz |
| **Events to Send** (Gönderilecek Event'ler) | En az bir olay seçilir; webhook yalnızca seçilenleri alır |
| **Authentication** (Kimlik Doğrulama) | Aşağıda |
| **Sign deliveries** (Gönderimleri imzala) | Aşağıda; kimlik doğrulamadan bağımsız bir anahtar |
| **Custom headers** (Özel başlıklar) | Aşağıda |
| **Retry Policy** (Yeniden Deneme Politikası) | Aşağıda |

### Adres kuralları

Adres sunucudan çağrıldığı için şu adresler **reddedilir** (400): `localhost`, özel ağ ve loopback adresleri (`10.x`, `172.16-31.x`, `192.168.x`, `127.x`, `169.254.x`), adı bu adreslere çözülen alan adları, adreste `kullanici:sifre@` biçiminde kimlik bilgisi ve veritabanı ile posta gibi ayrılmış portlar (`22`, `25`, `465`, `587`, `3306`, `5432`, `6379`, `27017` gibi). Yerelde geliştirme için [tünel](#adres-ve-tünel-ile-test) kullanın.

Adres her gönderimde **yeniden** kontrol edilir (kaydedildikten sonra alan adı başka bir adrese yönlendirilmiş olabilir) ve gönderim, kontrol edilen adrese yapılır. **Yönlendirme izlenmez:** uç noktanız `301`, `302` ya da başka bir `3xx` dönerse teslimat başarısız sayılır. Adresi son hâliyle girin; örneğin `http://` yerine `https://`, eski alan adı yerine yenisi.

### Olay seçimi

Liste, Selwise'ın bütün olay adlarını gösterir (52 ad; kategorileri ve ne zaman üretildikleri [Event Referansı](/docs/integration/events) sayfasındadır). Her seçili olay için bir HTTP isteği gider; toplu gönderim yoktur. `impression`, `scroll`, `hover` veya `product_impression` gibi yüksek hacimli olayları yalnızca gerçekten işleyecekseniz seçin.

Olay adı, sunucunun normalize ettiği kanonik addır: tanınmayan bir ad `custom_event` olarak gelir.

### Kimlik doğrulama

| Seçenek | Alanlar | Gönderilen |
|---|---|---|
| **No Auth** (Yetkilendirme Yok) | yok | Doğrulama yok; açık uçlu bir adreste kullanmayın |
| **Bearer Token** | **Bearer Token** | `Authorization: Bearer <token>` |
| **Basic Auth** | **Username**, **Password** | `Authorization: Basic <base64>` |
| **API Key** | **Header Name** (varsayılan `X-API-Key`), **API Key Value** | Seçtiğiniz başlıkta anahtar |

Seçilen türün gizli alanı zorunludur: token'ı boş bir **Bearer Token** hiç `Authorization` başlığı göndermezdi, form bunu artık kaydetmez.

Gizli değerler kayıttan sonra **geri okunamaz**; ekranda `••••` ile görünür ve veritabanında şifrelenmiş saklanır. Değeri korumak için kutuya dokunmayın; değiştirmek için yenisini yazın. Başka bir alanı değiştirmek (ör. kullanıcı adını) kayıtlı gizli değeri korur.

### İmza

**Sign deliveries** (Gönderimleri imzala) açıkken her gönderim, gövdenin HMAC-SHA256 imzasını **Signature Secret** ile hesaplanmış olarak **Header Name** başlığında (varsayılan `X-Signature`) taşır. İmza kimlik doğrulamanın bir türü değil, onun **yanındadır**: Bearer Token, Basic Auth veya API Key ile birlikte açılabilir. Gönderenin Selwise olduğunu ve gövdenin yolda değişmediğini kanıtlayan tek ayar budur; açık tutmanızı öneririz. Doğrulama kodu: [Webhook Payload ve İmza](/docs/outbound/webhook-payloads#hmac-imza-doğrulama).

Eskiden kimlik doğrulama türü olarak **HMAC Signature** seçilmiş webhook'lar formda "No Auth + imza açık" olarak görünür ve aynı şekilde imzalanmaya devam eder.

### Özel başlıklar

**Custom headers** (Özel başlıklar) her gönderime eklenecek ek `ad: değer` çiftleridir; uç noktanız bir kiracı kimliği, yönlendirme anahtarı ya da ikinci bir kimlik bilgisi bekliyorsa buraya yazın. **Add header** (Başlık ekle) ile satır ekleyin.

| Kural | Neden |
|---|---|
| En fazla 20 başlık; ad en fazla 100, değer en fazla 2000 karakter | Sunucunun kabul ettiği sınırlar |
| Ad yalnızca harf, rakam ve `-` gibi başlık karakterlerinden oluşur; boşluk ve `:` olmaz | Geçersiz bir adla HTTP isteği hiç gönderilemez |
| Değer satır sonu içeremez | Başlık enjeksiyonunu önler |
| `Content-Type`, `Content-Length`, `Host`, `User-Agent`, `Authorization`, `X-Selwise-Delivery-Id`, `X-Selwise-Event` kullanılamaz | Bunları Selwise her gönderimde kendisi ekler; `Authorization` için kimlik doğrulama ayarını kullanın |
| API anahtarının ve imzanın gönderildiği başlık adı kullanılamaz | Aynı ad iki kez gönderilemez |
| Aynı ad iki kez yazılamaz (büyük/küçük harf fark etmez) | `x-tenant` ile `X-Tenant` aynı başlıktır |

**Secret** (Gizli) işaretli bir başlığın değeri şifrelenmiş saklanır ve kayıttan sonra `••••` olarak görünür; kimlik doğrulama sırlarıyla aynı kural geçerlidir: dokunmazsanız korunur, yenisini yazarsanız değişir. Gizli bir başlığın **adını** değiştirir ya da **Secret** işaretini kaldırırsanız değeri yeniden girmeniz gerekir, çünkü kayıtlı değer başlığın eski hâline aittir. Gizli olmayan değerler panelde açık görünür; parola veya token taşıyan bir değeri gizli olarak işaretleyin.

### Yeniden deneme

| Alan | Aralık | Varsayılan |
|---|---|---|
| **Max Attempts** (Maks. Deneme) | 1 – 10 | 3 |
| **Initial Delay (ms)** (İlk Gecikme) | 1000 – 300000 | 60000 |
| **Backoff Multiplier** (Backoff Çarpanı) | 1 – 5, tam sayı | 2 |

Bir istek **zaman aşımına** uğrarsa (varsayılan 30 saniye), bağlantı kurulamazsa, `5xx` veya `429` yanıtı alırsa yeniden denenir. Diğer `4xx` yanıtlar (`400`, `401`, `404`…) **yeniden denenmez**; bunlar sizin tarafınızdaki bir yapılandırma hatasıdır.

**Max Attempts**, ilk denemeden sonraki **yeniden deneme** sayısıdır: varsayılanlarla bir olay en fazla dört kez gönderilir. Yeniden denemeler arasındaki bekleme:

| Deneme | Ne zaman (varsayılanlarla) |
|---|---|
| 1. deneme | Olay geldikten hemen sonra, kuyruktan |
| 1. yeniden deneme | İlk hatadan 60 sn sonra |
| 2. yeniden deneme | Öncekinden 120 sn sonra |
| 3. yeniden deneme | Öncekinden 240 sn sonra |

Genel kural: n. yeniden deneme `Initial Delay × Backoff Multiplier^(n-1)` bekler. Bir `4xx` yanıtı (`429` hariç) uç noktanızın reddidir; ne ilk denemede ne bir yeniden denemede tekrar gönderilmez. Yeniden denemeler aynı gövdeyi ve aynı imzayı taşır.

## Teslimat logları

Kartta **Logs** (Loglar) son 50 kaydı açar. Her kayıtta olay adı, durum (`success`, `failed`, `retrying`), yeniden deneme sayısı (**Retry n**), bir sonraki deneme zamanı (**Next retry at**), hata (**Error**), uç noktanızın yanıtının ilk 1000 karakteri (**Response**) ve gönderilen gövde (**Event Data**) vardır.

Her olay log'da **tek satırdır** ve denemeler ilerledikçe aynı satır güncellenir: `pending` (sırada, henüz gönderilmedi) → `success`, ya da `retrying` (bir sonraki deneme bekleniyor) → `success` / `failed`. Log'lar ödeme ve kişisel veri içerebilen gövdeyi aynen saklar; ekranı paylaşırken dikkat edin.

## Adres ve tünel ile test

1. Yerelde bir alıcı çalıştırın (örnek kod [burada](/docs/outbound/webhook-payloads#hmac-imza-doğrulama)) ve bir tünel açın: `ngrok http 3000` veya `cloudflared tunnel --url http://localhost:3000`. Hızlı gözlem için [webhook.site](https://webhook.site) de yeterlidir.
2. Tünelin `https://` adresini **Endpoint URL** olarak girin, kimlik doğrulamayı seçin, **Active** açık kalsın ve kaydedin.
3. Kartta **Test**'e basın. Uç noktanıza `event: "test_event"` olan bir istek gider ve sonuç ekranda görünür; olay seçiminden bağımsızdır.
4. **Logs**'ta isteğin, yanıt kodunuzun ve imzanın doğru olduğunu görün.
5. Gerçek olay için kendi sitenizde bir sayfayı gezin; seçtiğiniz olay saniyeler içinde gelir.

Test isteği de başarısız olursa kuralları aynen izler ve yeniden denenir.

## Tipik akış

1. Alıcınızı yazın: imzayı doğrulasın, hemen `200` dönsün, işi kuyruğa alsın.
2. Webhook'u tanımlayın, **Test** ile doğrulayın.
3. Yalnızca ihtiyacınız olan olayları seçin.
4. İlk gerçek olaylardan sonra **Logs**'ta `success` satırlarını ve **Failed** sayacını izleyin.

## Neden boş, neden gri

| Belirti | Neden |
|---|---|
| Ekran menüde yok | Hesabınızda **Integrations** modülü satın alınmamış; hesap yöneticinize başvurun |
| **Create Webhook** hata veriyor | Planınızdaki webhook sayısı sınırına ulaşıldı |
| **Test** gri | Webhook **Active** değil |
| Hiç olay gelmiyor | Webhook pasif; seçtiğiniz olay üretilmiyor; ziyaretçi çerez onayı vermediği için olay hiç alınmadı (bkz. [Onay Yönetimi](/docs/integration/consent)); ya da kanal seçili değil |
| Yalnızca `401` görüyorum | Alıcınız gizli değeri/başlığı reddediyor; `4xx` yeniden denenmez, düzeltip yeni olay bekleyin |
| Aynı olay iki kez geliyor | Yeniden deneme veya iki kaynak; `eventId` ile tekilleştirin ([ayrıntı](/docs/outbound/webhook-payloads#tekilleştirme)) |
| Kayıt 400 ile reddedildi | Adres özel ağa çözülüyor, ayrılmış port kullanıyor veya olay adı geçersiz |

> **Sıra ve garanti**
>
> Her olay, gönderilmeden önce teslimat satırı olarak kaydedilir ve gönderimi arka plan işçisi yapar; API yeniden başlasa da bekleyen teslimat kaybolmaz, işçi kaldığı yerden devam eder. Olaylar eşzamanlı gönderilir; varış sırası **garanti değildir**. **Data Layer** ekranındaki **Test Mode** açıkken kanalın hiçbir olayı webhook'lara gitmez ([Veri Katmanı Ayarları](/docs/integration/data-layer-settings)). Bir olay, siz `2xx` dönene veya yeniden denemeler tükenene kadar teslim edilmiş sayılmaz; tükenirse log'da `failed` kalır ve otomatik yeniden gönderilmez.
