Webhook Payload ve İmza

İstek gövdesi, örnekler, HMAC imza doğrulama ve tekilleştirme

Bir webhook'a giden her istek aynı zarfı taşır; zarfın içindeki data alanı olayın kaynağına göre değişir. Bu sayfa istek biçimini, her olay grubu için örnek gövdeyi, imza doğrulama kodunu (Node ve PHP), tekilleştirmeyi ve yeniden deneme davranışını anlatır. Ekran ve kurulum için bkz. Webhooks.

Gönderilen istek

Selwise uç noktanıza POST gönderir. Gövde JSON'dur.

BaşlıkDeğer
Content-Typeapplication/json
User-AgentSelwise-Webhook/1.0
X-Selwise-Delivery-IdTeslimat kimliği; gövdedeki id ile aynı. Yeniden denemelerde değişmez
X-Selwise-EventOlay adı; gövdedeki event ile aynı
Özel başlıklarınızWebhook'ta tanımladığınız Custom headers (gizli olanlar şifresi çözülmüş değeriyle)
Kimlik doğrulama başlığıSeçtiğiniz türe göre: Authorization veya API anahtarı başlığınız
İmza başlığıSign deliveries açıksa: gövdenin imzası, varsayılan X-Signature. Kimlik doğrulama başlığının yanında gelir
{
  "id": "6b1f0f8e-2a44-4d0c-9a1b-5f3c2e7d9a10",
  "event": "product_view",
  "timestamp": "2026-10-09T10:15:32.481Z",
  "data": { }
}
AlanAnlamı
idTeslimat kimliği: bir olayın bir webhook'a gidişi. Yeniden denemelerde aynı kalır; tekilleştirmenin en kolay anahtarı
eventKanonik olay adı, küçük harf (ör. add_to_cart). Tanınmayan bir ad custom_event olur. Panelden gönderilen test isteğinde test_event
timestampZarfın Selwise'ta oluşturulduğu an, ISO 8601 UTC. Yeniden denemelerde değişmez
dataOlay verisi, aşağıda

Uç noktanız herhangi bir 2xx ile yanıt verirse teslim başarılıdır; yanıt gövdesi yok sayılır (log'a ilk 1000 karakteri yazılır). Süre sınırı varsayılan olarak 30 saniyedir.

data alanı

Tarayıcı olayları

Çerez onayı verilmiş ziyaretçilerin tarayıcıdan gelen olayları. data iki parçanın birleşimidir: olayın kendi alanları (metadata, olay ve kaynağa göre değişir) ve Selwise'ın her olaya eklediği sabit alanlar.

Sabit alanAnlamı
eventIdOlayın benzersiz kimliği (tekilleştirme anahtarı)
requestId, sessionId, visitorId, siteUserIdİstek, oturum, anonim ziyaretçi ve (tanımlıysa) sizin kullanıcı kimliğiniz
entityType, entityId, productItemCodeOlayın konusu; ürün olaylarında productItemCode ürün beslemenizdeki stok kodudur
pageUrl, referrerSayfa ve yönlendiren adres
userAgent, ipAddressZiyaretçinin tarayıcı ve IP bilgisi
canonicalEventName, eventSchemaVersion, sourceKanonik ad, şema sürümü, kaynak
consentSnapshotOlay anındaki onay: granted, categories, timestamp, source
correlationId, parentEventId, journeyId, journeySequenceYolculuk ve sıralama alanları (varsa)

Değeri olmayan alanlar gövdede hiç yer almaz.

{
  "event": "product_view",
  "timestamp": "2026-10-09T10:15:32.481Z",
  "data": {
    "dataSource": "datalayer",
    "productItemCode": "SKU-12345",
    "productName": "Kablosuz Kulaklık",
    "productPrice": 749.9,
    "productCategory": "Elektronik > Kulaklık",
    "productBrand": "Marka",
    "productQuantity": 1,
    "productInStock": true,
    "timestamp": 1791540932399,
    "eventTs": 1791540932400,
    "requestId": "7f3e0c52-3c6e-4f6f-9a54-1b0c1a2b9d11",
    "eventId": "4b0e2b7e-3d1f-4c43-8d2a-6a8d9e0f1a22",
    "sessionId": "s_8f1c2d",
    "visitorId": "v_a41c9e",
    "entityType": "product",
    "entityId": "SKU-12345",
    "pageUrl": "https://magaza.com/urun/sku-12345",
    "referrer": "https://magaza.com/kategori/kulaklik",
    "userAgent": "Mozilla/5.0 ...",
    "ipAddress": "203.0.113.24",
    "eventSchemaVersion": 1,
    "canonicalEventName": "product_view",
    "source": "datalayer",
    "consentSnapshot": {
      "granted": true,
      "categories": { "necessary": true, "analytics": true, "marketing": false, "preferences": false },
      "timestamp": 1791540900000,
      "source": "banner"
    },
    "journeyId": "j_55d0aa",
    "journeySequence": 4
  }
}

Aşağıdaki örneklerde yalnızca olaya özgü alanlar gösterilir; yukarıdaki sabit alanlar hepsinde bulunur. Alan adları, olayı hangi kaynağın ürettiğine göre değişebilir: veri katmanı productName gibi düz alanlar, manuel track çağrısı sizin verdiğiniz metadata anahtarlarını taşır (Event Referansı).

Sipariş uç noktasından gelen satın alma

trackOrder ve sunucudan sunucuya sipariş gönderimi purchase olayını tarayıcı olayından farklı bir gövdeyle üretir: tarayıcı olaylarının sabit alanları (entityType, consentSnapshot ...) yoktur; sipariş nesnesi, oturum alanları ve Selwise'ın bu satın alma için yazdığı olayın kimliği (eventId) vardır.

{
  "id": "0a7c3f52-91d4-4b8e-a6f0-2c5e8d1b7f34",
  "event": "purchase",
  "timestamp": "2026-10-09T10:21:07.020Z",
  "data": {
    "order": {
      "orderId": "ORDER-2026-0001",
      "internalOrderId": "0b6f4c1e-77aa-4d1e-9b0e-2f0d6c5a1e90",
      "currency": "TRY",
      "total": 1499.7,
      "subtotal": 1499.7,
      "shippingTotal": 0,
      "discountTotal": 0,
      "taxTotal": 0,
      "status": "completed",
      "itemCount": 1,
      "items": [
        { "productItemCode": "SKU-12345", "title": "Kablosuz Kulaklık", "quantity": 2, "price": 749.9, "unitPrice": 749.9, "totalPrice": 1499.8 }
      ]
    },
    "cart": { "currency": "TRY", "total": 1499.7, "itemCount": 1 },
    "attribution": { "journeyId": "j_55d0aa" },
    "orderId": "ORDER-2026-0001",
    "eventId": "f3d2c1b0-8e7a-4f69-b5c4-1a2b3c4d5e6f",
    "externalId": "ORDER-2026-0001",
    "currency": "TRY",
    "total": 1499.7,
    "itemCount": 1,
    "sessionId": "s_8f1c2d",
    "visitorId": "v_a41c9e",
    "pageUrl": "https://magaza.com/siparis-tamamlandi"
  }
}

Aynı sipariş hem tarayıcıdan hem bu uçtan gelebilir; iki kaynağı tek siparişte birleştirmek için data.orderId kullanın.

Test isteği

Panelde Test düğmesi şunu gönderir (olay seçiminize bakılmaz):

{
  "event": "test_event",
  "timestamp": "2026-10-09T10:00:00.000Z",
  "data": { "message": "This is a test event from Selwise", "test": true }
}

Olay grupları ve örnek alanlar

Her grubun data içindeki olaya özgü alanları. Sabit alanlar (yukarıda) hepsinde vardır.

OlaylarÖrnek olaya özgü alanlar
page_view, virtual_page_viewpageType, pageTitle, pagePath, pageSearch, language, categories, tags
product_view, product_click, product_impression, product_dwell_time, wishlistproductItemCode, productName, productPrice, productCategory, productBrand, productVariant, productPosition, productList
add_to_cart, remove_from_cart, update_cart, cart_view, cart_abandon, cart_restore, cart_add_allcartId, productItemCode, productItemCodes, quantity, totalPrice, currency, productCount
checkout_begin, checkout_progress, checkout_optioncheckoutStep, checkoutOption, totalPrice, currency, productCount, productItemCodes, products
purchaseTarayıcıdan: orderId, total, subtotal, discountTotal, shippingTotal, taxTotal, currency, coupon, productItemCodes, products. Sipariş uç noktasından: yukarıdaki sipariş gövdesi
user_signup, user_login, user_logout, user_update, identifyuserId, email (SHA-256 karması), firstName, lastName, fullName, gender, age, birthday, newCustomer, method
search_instant_open, search_query, search_filter, search_sort, search_page, search_results, search_zero_results, search_close, category_filter, recent_search_click, popular_search_click, popular_category_click, popular_product_clickquery, results, category, filters, sortBy, sortOrder, page, perPage
impression, click, close, view, hover, scroll, widget_view, widget_impression, slider_navigate, slider_swipe, tab_return, goal_reachedentityType (campaign, recommendation, widget), entityId (kampanya veya öneri kimliği); click için buttonText, linkUrl
script_injected, script_errorBetik kimliği ve hata ayrıntısı
custom_eventSizin gönderdiğiniz alanlar

Örnekler:

{
  "event": "add_to_cart",
  "timestamp": "2026-10-09T10:16:40.113Z",
  "data": {
    "cartId": "cart_91ac",
    "productItemCode": "SKU-12345",
    "productName": "Kablosuz Kulaklık",
    "productPrice": 749.9,
    "quantity": 1,
    "totalPrice": 749.9,
    "currency": "TRY",
    "productItemCodes": ["SKU-12345"],
    "entityType": "basket",
    "entityId": "SKU-12345",
    "eventId": "c2f1a8b0-0f58-4a52-9a4c-8c1d2e3f4a55"
  }
}
{
  "event": "checkout_progress",
  "timestamp": "2026-10-09T10:19:02.774Z",
  "data": {
    "checkoutStep": 3,
    "checkoutOption": "credit_card",
    "stepName": "payment",
    "totalPrice": 1499.7,
    "currency": "TRY",
    "productCount": 2,
    "entityType": "checkout",
    "entityId": "step_3",
    "eventId": "e91b0d6a-2c5b-4ac2-b6a8-5d1f7b9c0d11"
  }
}
{
  "event": "search_query",
  "timestamp": "2026-10-09T10:12:11.309Z",
  "data": {
    "query": "kablosuz kulaklık",
    "results": 42,
    "searchType": "keyword",
    "page": 1,
    "entityType": "search",
    "eventId": "1d9c5f1e-5a3e-4f9a-bd0a-3f2e8c7b6a10"
  }
}
{
  "event": "click",
  "timestamp": "2026-10-09T10:14:55.002Z",
  "data": {
    "entityType": "campaign",
    "entityId": "5b8e3c0a-0d44-45d8-a2d5-9e0b7c1d2f33",
    "buttonText": "Alışverişe Başla",
    "linkUrl": "https://magaza.com/kampanya",
    "eventId": "a7e0c4d2-6b19-4e7f-9d31-0c2b8a5e4f66"
  }
}

Kişisel veri taşıyan alanlar

Her tarayıcı olayında ipAddress ve userAgent düz haliyle bulunur. Kullanıcı takip modülü açıkken user_* olayları ad, soyad, cinsiyet, yaş ve doğum tarihini de düz taşıyabilir; e-posta yalnızca SHA-256 karması olarak gelir. Alıcı sisteminizin KVKK/GDPR yükümlülüğünü buna göre kurun.

HMAC imza doğrulama

Webhook'ta Sign deliveries (Gönderimleri imzala) açıkken Selwise, hangi kimlik doğrulamayı seçmiş olursanız olun, gövdeyi şöyle imzalar:

  • Algoritma: HMAC-SHA256, anahtar sizin Signature Secret değeriniz.
  • İmzalanan veri: gönderilen JSON gövdesinin birebir baytları (JSON.stringify çıktısı).
  • Çıktı: küçük harfli hex, önek yok (sha256= gibi bir şey eklenmez).
  • Başlık: Header Name alanındaki ad, varsayılan X-Signature.

Doğrulama ham gövde üzerinden yapılmalıdır. Gövdeyi ayrıştırıp yeniden serileştirmek baytları değiştirir ve imzayı bozar.

import express from 'express';
import crypto from 'node:crypto';

const SECRET = process.env.SELWISE_WEBHOOK_SECRET;
const app = express();

// Ham gövde: express.json() KULLANMAYIN.
app.post('/webhooks/selwise', express.raw({ type: 'application/json' }), (req, res) => {
  const received = Buffer.from(req.get('X-Signature') || '');
  const expected = Buffer.from(
    crypto.createHmac('sha256', SECRET).update(req.body).digest('hex'),
  );

  if (received.length !== expected.length || !crypto.timingSafeEqual(received, expected)) {
    return res.sendStatus(401);
  }

  const { event, data } = JSON.parse(req.body.toString('utf8'));
  // İşi kuyruğa alın, hemen yanıt verin.
  res.sendStatus(200);
});

app.listen(3000);
<?php
$secret   = getenv('SELWISE_WEBHOOK_SECRET');
$raw      = file_get_contents('php://input');           // ham gövde
$received = $_SERVER['HTTP_X_SIGNATURE'] ?? '';         // başlık adını değiştirdiyseniz HTTP_ADINIZ
$expected = hash_hmac('sha256', $raw, $secret);

if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit;
}

$payload = json_decode($raw, true);
$event   = $payload['event'];
$data    = $payload['data'];

// İşi kuyruğa alın, hemen yanıt verin.
http_response_code(200);

Her iki kod da Selwise'ın imzalama koduyla aynı sonucu üreten örnek bir gövde ve anahtarla doğrulanmıştır. Kendi alıcınızı terminalden denemek için:

BODY='{"event":"test_event","timestamp":"2026-10-09T10:00:00.000Z","data":{"message":"This is a test event from Selwise","test":true}}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SELWISE_WEBHOOK_SECRET" | awk '{print $NF}')
curl -i -X POST http://localhost:3000/webhooks/selwise \
  -H 'Content-Type: application/json' -H "X-Signature: $SIG" --data-binary "$BODY"

Yeniden oynatma koruması

İmza zaman damgası içermez ve timestamp yeniden denemelerde aynı kalır; bu yüzden "5 dakikadan eski isteği reddet" gibi bir kural gerçek yeniden denemeleri de reddeder. Koruma için zarfın id değerini (veya orderId) saklayıp tekrar edenleri atlayın.

Tekilleştirme

Aynı olay şu durumlarda birden fazla kez gelebilir; alıcınız bunlara dayanıklı olmalıdır:

  • Yanıtınız zaman aşımına uğradı veya 5xx/429 döndü: Selwise aynı gövdeyi yeniden gönderir.
  • Aynı satın alma hem tarayıcıdan (purchase olayı) hem sipariş uç noktasından gelir.
Olay türüTekilleştirme anahtarı
Aynı teslimatın yeniden denemesiZarfın id alanı (veya X-Selwise-Delivery-Id başlığı)
Tarayıcı olaylarıdata.eventId
Sipariş uç noktasından purchasedata.orderId veya data.eventId
purchase (her iki kaynak)data.orderId — iki kaynağın tek siparişte birleşmesi için bunu kullanın
test_eventAnahtar yok; işlemeyin

Selwise tarafında aynı eventId ile gelen tekrarlar zaten ayıklanır (iki kez kaydedilmez, iki kez gönderilmez).

Yeniden deneme özeti

DurumDavranış
2xxBaşarılı
5xx, 429, zaman aşımı, bağlantı hatası, DNS hatasıYeniden denenir (kurallar Webhooks sayfasında)
Diğer 4xxYeniden denenmez, failed kalır
Webhook yeniden deneme sırasında pasife alınmışsaBekleyen yeniden denemeler failed olur

Alıcı için kontrol listesi

  • Ham gövde üzerinden imzayı doğrulayın; 401 dönün.
  • İşi kuyruğa alıp saniyeler içinde 200 dönün; süre sınırı varsayılan olarak 30 saniyedir.
  • Zarfın id alanıyla (aynı teslimatın tekrarı) ve orderId ile (aynı siparişin iki kaynaktan gelişi) tekilleştirin.
  • Bilmediğiniz event adlarını sessizce 200 ile geçin; Selwise yeni olay adları ekleyebilir.
  • Sıraya güvenmeyin; olay sırasını journeySequence ve timestamp ile siz kurun.

Son güncelleme: 10 Ekim 2026