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ık | Değer |
|---|---|
Content-Type | application/json |
User-Agent | Selwise-Webhook/1.0 |
X-Selwise-Delivery-Id | Teslimat kimliği; gövdedeki id ile aynı. Yeniden denemelerde değişmez |
X-Selwise-Event | Olay adı; gövdedeki event ile aynı |
| Özel başlıklarınız | Webhook'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": { }
}
| Alan | Anlamı |
|---|---|
id | Teslimat kimliği: bir olayın bir webhook'a gidişi. Yeniden denemelerde aynı kalır; tekilleştirmenin en kolay anahtarı |
event | Kanonik olay adı, küçük harf (ör. add_to_cart). Tanınmayan bir ad custom_event olur. Panelden gönderilen test isteğinde test_event |
timestamp | Zarfın Selwise'ta oluşturulduğu an, ISO 8601 UTC. Yeniden denemelerde değişmez |
data | Olay 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 alan | Anlamı |
|---|---|
eventId | Olayı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, productItemCode | Olayın konusu; ürün olaylarında productItemCode ürün beslemenizdeki stok kodudur |
pageUrl, referrer | Sayfa ve yönlendiren adres |
userAgent, ipAddress | Ziyaretçinin tarayıcı ve IP bilgisi |
canonicalEventName, eventSchemaVersion, source | Kanonik ad, şema sürümü, kaynak |
consentSnapshot | Olay anındaki onay: granted, categories, timestamp, source |
correlationId, parentEventId, journeyId, journeySequence | Yolculuk 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_view | pageType, pageTitle, pagePath, pageSearch, language, categories, tags |
product_view, product_click, product_impression, product_dwell_time, wishlist | productItemCode, productName, productPrice, productCategory, productBrand, productVariant, productPosition, productList |
add_to_cart, remove_from_cart, update_cart, cart_view, cart_abandon, cart_restore, cart_add_all | cartId, productItemCode, productItemCodes, quantity, totalPrice, currency, productCount |
checkout_begin, checkout_progress, checkout_option | checkoutStep, checkoutOption, totalPrice, currency, productCount, productItemCodes, products |
purchase | Tarayı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, identify | userId, 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_click | query, results, category, filters, sortBy, sortOrder, page, perPage |
impression, click, close, view, hover, scroll, widget_view, widget_impression, slider_navigate, slider_swipe, tab_return, goal_reached | entityType (campaign, recommendation, widget), entityId (kampanya veya öneri kimliği); click için buttonText, linkUrl |
script_injected, script_error | Betik kimliği ve hata ayrıntısı |
custom_event | Sizin 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/429döndü: Selwise aynı gövdeyi yeniden gönderir. - Aynı satın alma hem tarayıcıdan (
purchaseolayı) hem sipariş uç noktasından gelir.
| Olay türü | Tekilleştirme anahtarı |
|---|---|
| Aynı teslimatın yeniden denemesi | Zarfın id alanı (veya X-Selwise-Delivery-Id başlığı) |
| Tarayıcı olayları | data.eventId |
Sipariş uç noktasından purchase | data.orderId veya data.eventId |
purchase (her iki kaynak) | data.orderId — iki kaynağın tek siparişte birleşmesi için bunu kullanın |
test_event | Anahtar 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
| Durum | Davranış |
|---|---|
2xx | Başarılı |
5xx, 429, zaman aşımı, bağlantı hatası, DNS hatası | Yeniden denenir (kurallar Webhooks sayfasında) |
Diğer 4xx | Yeniden denenmez, failed kalır |
| Webhook yeniden deneme sırasında pasife alınmışsa | Bekleyen yeniden denemeler failed olur |
Alıcı için kontrol listesi
- Ham gövde üzerinden imzayı doğrulayın;
401dönün. - İşi kuyruğa alıp saniyeler içinde
200dönün; süre sınırı varsayılan olarak 30 saniyedir. - Zarfın
idalanıyla (aynı teslimatın tekrarı) veorderIdile (aynı siparişin iki kaynaktan gelişi) tekilleştirin. - Bilmediğiniz
eventadlarını sessizce200ile geçin; Selwise yeni olay adları ekleyebilir. - Sıraya güvenmeyin; olay sırasını
journeySequencevetimestampile siz kurun.
Son güncelleme: 10 Ekim 2026