Webhook'lar kimlik tespiti olaylarını sunucunuza gerçek zamanlı olarak iletir. Bir
ziyaretçi her tanımlandığında TRACIO, yapılandırdığınız webhook URL'sine bir HTTP
POST isteği gönderir. İsteğin gövdesi olayın payload'ının ta kendisidir.
Ayrıca geç kararları ileten tek kanaldır: ziyaretçinin davranışının, sayfa yüklendikten sonra onun otomatikleştirilmiş olduğunu kanıtladığı kararları.
Bunları panelde Settings → Webhooks altında ayarlayın. Webhook'lar Pro veya daha üst bir plan gerektirir.
| Olay | Ne zaman | Plan |
|---|---|---|
identification | Her ziyarette — primary, late ve correction fazları | Tümü |
account_takeover | Bir hesap altındaki davranış artık sahibinin profiline uymuyor | Business+ |
account_assessment | Bir hesabın hesap ele geçirme değerlendirme durumu: değerlendirildi ve temiz, değerlendirildi ve sapıyor ya da değerlendirilmedi | Business+ |
attack_detected | Sitenizde bot sayısında ani artış | Business+ |
reputation_changed | Bağlı bir kişinin itibarı başka bir banda geçti | Business+ |
transaction_state_changed | POST /v2/transactions'a gönderdiğiniz bir işlemin sonucu değişti | Business+ |
login_risk | POST /v2/logins/assess ile yapılan bir giriş değerlendirmesi challenge veya review ile sonuçlandı | Tümü |
trusted_device_enrolled | Bir cihaz bir hesap için güvenilir yapıldı ya da güveni yenilendi | Tümü |
trusted_device_revoked | Bir cihazın güveni iptal edildi — API üzerinden ya da panelden | Tümü |
affiliate_threshold_crossed | Bir affiliate için öneri kötüleşti (none → review, none → hold, review → hold) | Tümü |
Olay adları noktayla değil, her zaman alt çizgiyle yazılır — visitor.created veya
session.created diye bir şey yoktur.
Bir webhook belirli türlere abone olur; ayrı bir değer olan * ise "sonradan
eklenenler dahil her tür" anlamına gelir. Beş tür istisnadır: *,
account_assessment, login_risk, trusted_device_enrolled,
trusted_device_revoked ve affiliate_threshold_crossed türlerini kapsamaz — bunların
her birini açıkça adıyla belirtin. account_assessment bir bulgu değil kapsama
durumunu bildirir; bu yüzden linked_id taşıyan ziyaret başına yaklaşık bir kez gelir —
diğer olaylardan farklı büyüklükte bir hacim. Giriş riski ve affiliate türleri yalnızca
bu API'leri çağıran bir entegrasyon için anlamlıdır. Bu olaylar var olmadan önce
ayarladığınız bir joker karakter, onları almaya verilmiş bir onay değildir.
Abonelik oluşturulurken veya düzenlenirken bilinmeyen bir tür 400 ile reddedilir;
böylece bir yazım hatası sizi sessizce hiç tetiklenmeyen bir webhook'la baş başa
bırakmaz.
identification olayının fazlarıTek bir ziyaret, aynı request_id'yi paylaşan en fazla üç teslimat üretir:
primary — sayfa yüklenirken verilen ilk karar.late — yavaş kontroller tamamlandığında, yaklaşık dokuz saniye sonraki zenginleştirme.correction — davranışa dayalı düzeltme (işaretçi, klavye, kaydırma).Bunları request_id ile ilişkilendirin, phase ile birbirinden ayırın. Sonraki faz
önceliklidir: primary human dediyse ve correction bot diyorsa, doğru cevap
ikincisidir.
Geliş sırasına güvenmeyin. Her faz bağımsız olarak ve kendi yeniden deneme
takvimiyle teslim edilir; primary yeniden denemeye düşmüşken late ilk denemede
başarılı olduysa, bunları ters sırada alırsınız. Önceliği alınma zamanından değil,
phase alanından belirleyin.
Bir identification olayının fazları yalnızca bu üçüdür. Size ulaşan bir değer daha
vardır: account_takeover ve account_assessment, phase: "beacon" taşır; çünkü ikisi
de oturumun davranışsal beacon'ından yükseltilir.
Bunun yarattığı uyumsuzluğa dikkat edin, çünkü idempotency'yi etkiler. Üretimdeki bir
identification teslimatının event_id değeri tam olarak <request_id>:<phase>
biçimindedir, ancak diğer teslimatlar bu formülü bozar. Bir account_takeover
<request_id>:ato olur — sonek, phase alanının değeri değil, birebir ato dizesidir —
bir account_assessment ise <request_id>:ato-state-<state> olur. Panelden gönderilen
bir test teslimatı <request_id>:test olur; buna karşılık gövdesindeki phase hâlâ
primary yazar — şema 1 gövdesinde ise phase alanı hiç bulunmaz, dolayısıyla bu
sonekin göründüğü tek yer başlıktır. event_id değerini doğrudan idempotency anahtarı
olarak kullanın ve onu asla request_id ile phase'ten yeniden birleştirmeyin.
İşlediğiniz değerlerle eşleştirin; geri kalanını teslimatı reddetmek yerine yok sayın.
Bazı olayların ziyareti yoktur: attack_detected (workspace düzeyi),
reputation_changed (kişi düzeyi), transaction_state_changed (işlem düzeyi),
login_risk, trusted_device_enrolled ve trusted_device_revoked (hesap düzeyi) ve
affiliate_threshold_crossed (affiliate düzeyi). Bunların request_id'si,
visitor_id'si ve browser, geo, bot ya da decision bloklarının hiçbiri yoktur —
bu anahtarlar, X-Tracio-Request-Id başlığı gibi, basitçe bulunmaz.
account_takeover ve account_assessment ise belirli bir ziyaretten doğar ve planınıza
ait tam kimlik tespiti gövdesini taşır. Tüm olayları tek bir handler'da
ayrıştırıyorsanız, ziyaret alanlarına dokunmadan önce event alanını kontrol edin.
Yeni webhook'lar payload sürüm 3'ü kullanır. Sürüm 1 veya 2'deki mevcut webhook'lar seçtikleri sürümü korur; eski iki şema da dondurulmuştur ve 2027-04-12 tarihinde kaldırılacaktır. Geçiş için paneldeki webhook kartında sürüm 3'ü seçin.
| Sürüm | Durum |
|---|---|
1 | Dondurulmuş; 2027-04-12 tarihinde kaldırılacak |
2 | Dondurulmuş; 2027-04-12 tarihinde kaldırılacak |
3 | Yeni webhook'lar için varsayılan; snake_case anahtarlar |
Sürüm 3, sürüm 2 ile aynı alanları ve değerleri taşır; anahtarlar snake_case'tir ve en
üst düzeyde version: 3 bulunur. İmza algoritması ve başlıklar değişmez
(X-Tracio-Payload-Version: 3). Kendi fields sözlüğünüzün içindeki anahtarlar sizin
verinizdir ve yeniden adlandırılmaz.
| v2 | v3 |
|---|---|
eventId | event_id |
requestId | request_id |
visitorId | visitor_id |
linkedId | linked_id |
userAgent | user_agent |
network.connectionType | network.connection_type |
network.proxyDetected | network.proxy_detected |
network.realIp | network.real_ip |
bot.antidetectScore | bot.antidetect_score |
identification.matchType | identification.match_type |
identification.matchConfidence | identification.match_confidence |
identification.incognitoVisits | identification.incognito_visits |
identification.driftScore | identification.drift_score |
decision.riskScore | decision.risk_score |
decision.suspectScore | decision.suspect_score |
deviceInfo | device_info |
deviceInfo.deviceId | device_info.device_id |
deviceInfo.crossBrowser | device_info.cross_browser |
deviceInfo.linkedBrowsers | device_info.linked_browsers |
screen.colorDepth | screen.color_depth |
screen.pixelRatio | screen.pixel_ratio |
clientHints | client_hints |
clientHints.platformVersion | client_hints.platform_version |
clientHints.deviceName | client_hints.device_name |
osEnvironment | os_environment |
environment.virtualMachine | environment.virtual_machine |
spoofing.spoofedAxes | spoofing.spoofed_axes |
spoofing.anonymousBrowser | spoofing.anonymous_browser |
session.durationSeconds | session.duration_seconds |
velocity.uniqueIps | velocity.unique_ips |
velocity.uniqueLocations | velocity.unique_locations |
accountAlert | account_alert |
accountAlert.accountId | account_alert.account_id |
accountAlert.driftScore | account_alert.drift_score |
accountAssessment | account_assessment |
accountAssessment.accountId | account_assessment.account_id |
accountAssessment.profile.windowsEffective | account_assessment.profile.windows_effective |
accountAssessment.profile.oldestWindowAgeSeconds | account_assessment.profile.oldest_window_age_seconds |
attack.windowMinutes | attack.window_minutes |
attack.recentBots | attack.recent_bots |
attack.recentTotal | attack.recent_total |
personId | person_id |
reputation.overallRisk | reputation.overall_risk |
linkedAccountsCount | linked_accounts_count |
linkedVisitorsCount | linked_visitors_count |
reputationChange | reputation_change |
reputationChange.personId | reputation_change.person_id |
reputationChange.previousBand | reputation_change.previous_band |
reputationChange.visitorIds | reputation_change.visitor_ids |
reputationChange.linkedAccountsCount | reputation_change.linked_accounts_count |
{ "version": 3, "event": "identification", "event_id": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31:primary", // "<request_id>:<phase>" — the idempotency key "request_id": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31", // visit identifier, shared by all phases "phase": "primary", "visitor_id": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "linked_id": "user-42", // your ?lid=, if you passed one "tag": "checkout", "fields": { "order_ref": "A-1029", "plan": "pro" }, // custom fields that arrived with the visit "timestamp": "2026-07-30T12:00:00Z", "url": "https://shop.example.com/checkout", "ip": "203.0.113.44", "user_agent": "Mozilla/5.0 …", "browser": { "name": "Chrome", "version": "138" }, "os": { "name": "macOS", "version": "15.5" }, "device": "desktop", "gpu": "Intel Iris Plus Graphics 655", // video adapter model, normalized; absent when unknown "geo": { "country": "DE", "city": "Berlin", "lat": 52.52, "lon": 13.405, "timezone": "Europe/Berlin" }, "network": { "vpn": false, "proxy": true, "tor": false, "datacenter": true, "connection_type": "DCH", "proxy_detected": true // HTTP traffic and the raw network path exit through different networks }, "bot": { "result": "human", "score": 3.2 }, // human | bot | uncertain "identification": { "confidence": 0.97, "incognito": false }, "decision": { "action": "real", "risk_score": 12.2 }, // real | fake | suspicious "extensions": ["metamask", "privacy_badger"] // detected browser extensions; absent when none}Sıfır ve boş değerler çıkarılır. Sıfır değerli metin ve sayı alanları (örneğin bir
insan için bot.type ya da bot.antidetect_score: 0) JSON'da bulunmaz — bunları
şemalarınızda zorunlu yapmayın ve iç içe blokları savunmacı biçimde okuyun.
bot.score ve decision.risk_score, virgülden sonra tek basamaklı, 0..100
ölçeğinde ondalıklı sayılardır — panelin ve Data API'nin aynı ziyaret için raporladığı
sayıların tıpatıp aynısı. (Dondurulmuş v1 şemasında farklı birimler kullanılır:
sırasıyla 0..1 aralığında bir kesir ve 0..255.)
bot.type ya tanınan bir botun adıdır, ya doğrulanmış bir yapay zekâ ajanıdır
(ai_agent:<vendor>) ya da bir aile etiketidir. Sözlük için
Bot türleri bölümüne bakın — dahili kontrol adları
hiçbir planda açığa çıkarılmaz. ai_agent:<vendor>, isteğin o sağlayıcının
altyapısından geldiğini kanıtladığı anlamına gelir — sağlayıcının yayımladığı bir
anahtarla yapılmış geçerli bir Web Bot Auth imzası ya da sağlayıcının yayımladığı IP
aralıklarının içindeki bir adres — yalnızca user agent'ta bunu iddia etmesi değil.
Yapay zekâ ajanı olduğunu iddia eden ve sağlayıcının yayımladığı her kanıtla çelişen bir
istek impersonation olarak raporlanır.
| Alan | Tür | Açıklama |
|---|---|---|
version | number | Payload şema sürümü (3) |
event | string | Olay türü |
event_id | string | Teslimat tanımlayıcısı — idempotency anahtarı; olay başına benzersizdir, onu alan tüm webhook'larınızca paylaşılır, yeniden denemeler boyunca sabit kalır |
request_id | string | Ziyaret tanımlayıcısı (UUID); ziyaretin tüm fazlarınca paylaşılır |
phase | string | primary, late, correction; account_takeover ve account_assessment beacon taşır |
visitor_id | string | Kararlı ziyaretçi tanımlayıcısı |
linked_id | string | İstemcinin sağladığı bağlı tanımlayıcı |
tag | string | İstemcinin sağladığı özel etiket |
fields | object | Toplama anında ziyarete eklenen özel alanlar. Yalnızca ziyaretle birlikte gelenler — sonradan Data API üzerinden eklenen bir alan, hiçbir fazda veya yeniden denemede webhook'ta görünmez. Anahtarlar ve değerler dizedir. Ziyaret hiç alan taşımadıysa bulunmaz |
timestamp | string | Olay zamanı (RFC 3339) |
url | string | Olayın yakalandığı sayfanın URL'si |
ip | string | İstemcinin IP adresi |
user_agent | string | İstemcinin ham user-agent dizesi |
browser.name / .version | string | Tespit edilen tarayıcı |
os.name / .version | string | Tespit edilen işletim sistemi |
device | string | Cihaz sınıfı (ör. desktop, mobile) |
gpu | string | Tarayıcının bildirdiği (WebGL) ekran kartı modeli, okunabilir bir ada normalleştirilir (Intel Iris Xe Graphics, Apple M1 Pro); yazılım rasterleştiricilerde Software renderer; bilinmediğinde bulunmaz |
geo | object | IP coğrafi konumu: country, city, lat, lon, timezone |
network | object | vpn, proxy, tor, datacenter (boolean) ve connection_type |
network.proxy_detected | boolean | Ziyaretin HTTP trafiği ile ham ağ yolları farklı ağlardan çıkıyor — tarayıcının önünde bir proxy ya da VPN var. Aynı sağlayıcının iki adresi (operatör NAT'ı, aynı VPN'in ikinci çıkışı) sayılmaz |
bot.result | string | human, bot veya uncertain |
bot.type | string | Bot tespit edildiğinde bot adı, doğrulanmış yapay zekâ ajanı veya aile etiketi |
bot.score | number | Bot skoru (0–100) |
identification.confidence | number | Kimlik tespiti güveni (0.0–1.0) |
identification.incognito | boolean | Özel/gizli tarama bağlamı |
decision.action | string | real, fake veya suspicious |
decision.risk_score | number | Toplam risk skoru (0–100) |
extensions | array | Bu ziyarette tespit edilen tarayıcı uzantıları, kararlı makine slug'ları olarak (adlar, kategoriler ve mağaza bağlantıları panelde ve Data API'dedir). Hiçbir şey tespit edilmediğinde bulunmaz |
Pro ve üzeri — ziyaretçinin zaman içindeki davranışı:
{ "identification": { "match_type": "exact", // exact | fuzzy | new — how the visitor was recognized "match_confidence": 0.93, "visits": 42, "incognito_visits": 3 }, // Present when visitor counters are available at event time (usually primary). // A missing block means "no data", not "zeros". "velocity": { "events5m": 7, "unique_ips": 2, "unique_locations": 1 }, "bot": { "antidetect_score": 0 }, // antidetect indicators, 0..100 "session": { "duration_seconds": 95 } // the correction phase and the account_takeover alert}Business ve üzeri — kararın neden böyle çıktığı:
{ "reasons": [ // at most 8, sorted by importance { "code": "headless_browser", "severity": "high" }, { "code": "privacy_hardening", "severity": "low" } ], // Behavioral biometrics — present only when behavioral scoring ran for the // visit. A missing block means "no data", never "nothing suspicious". "behavior": { "score": 87, "verdict": "human", "confidence": 0.92 }, // The smoothed behavior score the account-takeover verdict was made on. It is // measured by beacons that arrive after the identification event, so it is // empty in identification deliveries — see the account_takeover event. "identification": { "drift_score": 0.41 }, "device_info": { "device_id": "…", // the physical device across browsers on it "cross_browser": true, "confidence": 0.88, "linked_browsers": 3 }, "network": { "isp": "Deutsche Telekom", "asn": 3320, // the public address observed on the raw network path, i.e. the address // behind the proxy or VPN; absent when no such address was observed "real_ip": { "address": "203.0.113.7", "country": "NL", "isp": "KPN" } }, "geo": { "isp": "Deutsche Telekom" }, // The desktop environment MEASURED on a Linux machine ("Mint 22+", "Ubuntu", // "GNOME", "KDE"); a User-Agent cannot express a distribution. Absent when // not determined — most Linux visits, and every non-Linux one. "os_environment": "Mint 22+", // What the visit claimed about itself versus what independent checks // measured. Present only when a spoof was actually detected; an empty // `real` field means "the check stayed silent", never "confirmed". With the // `gpu` axis, `claimed.gpu` carries the claimed adapter as the same readable // model name as the top-level `gpu` field. "spoofing": { "detected": true, "claimed": { "os": "Windows 10", "browser": "Chrome 139.0" }, "real": { "os": "macOS" }, "spoofed_axes": ["os", "screen"], // os | gpu | screen | network | browser "anonymous_browser": { "detected": true, "names": ["Linken Sphere"] } }, // Device facts — what the visitor's browser reports about the machine, // sanitized on our side. screen: resolution, color depth and the device // pixel ratio. locale: the browser's own preferred languages and timezone — // as opposed to geo.timezone, which is derived from the IP address; a // mismatch between the two is a common sign of a spoofed location. // client_hints: User-Agent Client Hints — CPU architecture and bitness, // device model (Android: the model code in `model`, e.g. "SM-A556B", and // its marketing name from the Google Play device list in `device_name`, // e.g. "Samsung Galaxy A55 5G") and the exact platform version; only // Chromium-based browsers report them. Every block is absent when the // visit carried no such data, so treat each as optional. "screen": { "width": 2560, "height": 1600, "color_depth": 30, "pixel_ratio": 2 }, "locale": { "languages": ["en-US", "de"], "timezone": "Europe/Berlin" }, "client_hints": { "architecture": "arm", "bitness": "64", "platform_version": "15.5.0" }, // Present only when the video adapter identified itself as a virtual one; // hypervisor is a closed dictionary (vmware, virtualbox, parallels, qemu, // hyperv, bochs, intel-gvt, vgpu). A missing block means no such evidence. "environment": { "virtual_machine": true, "hypervisor": "vmware" }, "decision": { "suspect_score": 4.1 }, "guidance": { "version": 3, "overall": "review" } // see below}Neden kodu sözlüğü ve severity'nin ne anlama geldiği için
Bot Tespiti sayfasına bakın.
Çoklu hesap alanları (Business ve üzeri). Workspace'iniz için kişi modu
etkinleştirildiğinde gövde ayrıca person_id, bir reputation bloğu (score,
categories, overall_risk), linked_accounts_count ve linked_visitors_count
taşır — ziyaretçinin başka ziyaretçilere ve hesaplara bağlı olup olmadığı. Kişi katmanı
şu anda gözlem modunda çalışır ve canlıya geçene kadar bu alanlar gövdede bulunmaz.
Bunları şemalarınızda zorunlu yapmayın.
guidance, her entegrasyon noktası için hazır "ne yapmalı" önerileri taşır; böylece
ham skorlardan bir politika türetmek zorunda kalmazsınız. Her v3 Business+ olayında
bulunur — allow açıkça belirtilir:
{ "guidance": { "version": 3, "overall": "review", // the strictest advice across the scenarios "payment": "review", // whether to accept the payment "registration": "challenge", // whether to create the account "login": "challenge", // whether to let them into the account "affiliate": "review", // whether to credit the conversion to the partner "basis": ["risk", "network"] // the axes that determined the advice }}Her senaryo allow ile başlar ve merdivende yalnızca yukarı doğru hareket eder:
allow → challenge → review → deny. Bir senaryo içinde tetiklenen en katı eksen
kazanır; overall ise dört senaryonun tümü arasındaki en katı olandır.
| Öneri | Ödeme | Kayıt | Giriş | Affiliate |
|---|---|---|---|---|
allow | İşleyin | Oluşturun | İçeri alın | Dönüşümü hesaba yazın |
challenge | 3-D Secure / onay | Captcha, e-posta veya telefon onayı | Step-up 2FA, yeniden kimlik doğrulama | Aktivite görülene kadar şüpheli işaretleyin |
review | İşleyin, ancak incelemeye alın | Kısıtlamalarla oluşturun | İçeri alın, bir uyarı oluşturun | İnceleme yapılana kadar ödemeyi bekletin |
deny | İşlemi gerçekleştirmeyin | Hesabı oluşturmayı reddedin | İçeri almayın | Dönüşümü hesaba yazmayın |
basis, öneriyi belirleyen eksenleri listeler — önerisi benimsenenden daha yumuşak
olan bir eksen listeye girmez. Sabit bir küme varsaymak yerine onu koda göre okuyun:
Eksen (basis) | Anlamı |
|---|---|
list | Ziyaretçi, workspace listelerinizden enforce modundaki biriyle eşleşti. Bir allow listesi her ekseni geçersiz kılar: her senaryo allow olur ve basis tam olarak ["list"] olur |
rule | Ziyaret, workspace kurallarınızdan enforce modundaki biriyle eşleşti; bir kural yalnızca kendi senaryosunun önerisini değiştirir (bir allow kuralı yalnızca onu yumuşatır) ve bir liste zaten devreye girdiyse atlanır |
bot | Bot dedektörü bunun otomasyon olduğu sonucuna vardı — her senaryoyu reddeder |
risk | Ziyaretin kararı ve genel risk skoru |
behavior | Davranışsal biyometri yeterli güvenle bot diyor — ret yerine sürtünme ekler |
account_takeover | Bu hesap altındaki davranış artık sahibinin profiline uymuyor — giriş challenge'a, ödeme review'a |
network | Tor ya da bir veri merkezinden çıkan VPN |
affiliate_pattern | Kendi kendine üretilmiş yönlendirmelerin biçimi — affiliate dönüşümü challenge olarak bekletilir |
fraud_reputation, multiaccounting | Ziyaretçinin arkasındaki kişinin itibarı ve hesap kümelenmesi; kişi katmanı canlıya geçtiğinde görünür |
version, kural setinin sürümüdür — mantık geliştikçe artırılır, bu yüzden onu
loglarınızda tutun. Sürüm 2, öneriyi yumuşatabilen ilk eksen olan list eksenini
getirdi; sürüm 3, account_takeover giriş eşiklerini hesap ele geçirme kararı skorunun
ölçeğine taşıdı; bu yüzden aynı ziyaret, sürüm 2'nin challenge verdiği yerde deny
alabilir, tersi de olabilir.
Guidance eklemelidir: yeni senaryolar sözleşmeyi bozmadan yeni anahtarlar olarak gelir.
Sonraki faz kazanır, kısmi öneri hariç: eksik bir girdi kümesi üzerinde hesaplanan
bir teslimat "partial": true olarak işaretlenir ve kısmi öneri, aynı request_id için
daha önce alınmış tam öneriyi geçersiz kılmaz. Olağan bir teslimatta partial
alanı hiç bulunmaz.
Kesin eşikler bilinçli olarak belgelenmez. Tersine mühendislikle bir skora
dönüştürülebilen öneri, savunma olmaktan çıkar. Tam olarak bir bilinçli istisna vardır:
aşağıda açıklanan hesap ele geçirme kararının karar sınırı olan
account_assessment.verdict.threshold.
account_takeover olayıYalnızca Business ve Enterprise; daha düşük planlarda, bir webhook bu olaya abone olsa
bile teslimat oluşturulmaz. Gövde, planınıza ait tam kimlik tespiti zarfı artı bir
account_alert bloğu ve bir sonraki bölümde açıklanan account_assessment bloğudur;
ziyaret başına en fazla bir kez teslim edilir:
{ "version": 3, "event": "account_takeover", "event_id": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31:ato", "request_id": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31", "phase": "beacon", // the alert is raised from a beacon; only the event_id says "ato" "account_alert": { "type": "behavior-drift/2", // kind of alert and the version of its construction "account_id": "user-42", // your linked_id for the account "drift_score": 0.71 // the value the verdict was made on }, "account_assessment": { "type": "behavior-drift/2", "account_id": "user-42", "state": "assessed_alert", "verdict": { "severity": "high", "score": 0.71, "threshold": 0.3565, "scale": "manhattan-normalized", "basis": "ring", "windows": 9 }, "profile": { "windows": 6, "windows_effective": 5, "oldest_window_age_seconds": 1837 } } // …the remaining identification fields}type neden bir sürüm taşır. Skorun arkasındaki yapı daha önce değişti: kararın
ölçeği ve temeli. behavior-drift/2 ilk sürümlü yapıdır. Kendi kurallarınızı bu sayıya
göre kalibre ettiyseniz, bu değerin değişmesini onları yeniden kontrol etme işareti
olarak görün.
account_alert.drift_score ve identification.drift_score aynı sayıdır
(2026-10-03'ten beri): kararın dayandığı, hesap sahibinin geçmiş güvenilir pencereler
halkasına karşı ölçülen düzleştirilmiş davranış skoru. Bu tarihten önce
identification.drift_score farklı bir ölçekte ham bir mesafe taşıyordu — bu tarihin iki
yanındaki değerleri karıştırmayın. Bir pencere değerlendirilmediğinde alan sıfır değil,
bulunmaz. Sayıya, karşılaştırıldığı eşikle birlikte ihtiyacınız olduğunda
account_assessment.verdict kullanın.
v1'de blok type, linkedId ve drift içeren accountAlert'tir ve değerlendirme
bloğu yoktur. v2'de uyarı iki alanı yeniden adlandırır — linkedId → accountId ve
drift → driftScore — ve accountAssessment ekler; v3 yukarıdaki snake_case adları
kullanır. Sürüm değiştirdiğinizde handler'ınızı güncelleyin; aksi hâlde hesap ele
geçirme mantığınız veriyi sessizce görmeyi bırakır.
account_assessment olayıYalnızca Business ve Enterprise. Açık bir abonelik gerektirir: * onu kapsamaz.
Bu olay olmadan uyarının yokluğu aynı anda iki farklı şey anlamına gelir: ya oturumu hesap sahibinin profiline göre değerlendirdik ve eşleşti, ya da onu hiç değerlendiremedik — sahibin profili hazır değil, pencere fazla seyrekti ya da trafik bir insan değildi. İkisi de sessizlik gibi görünür ve sessizlik güvenlik gibi okunur. Genellikle öyle değildir: Eylül 2026'da tam bir üretim gününde pencerelerin %73'ünde ve hesapların %80'inde karar vermekten kaçındık. "Uyarı yoksa sorun yok" üzerine kurulmuş bir süreç, çoğunlukla elimizde olmayan bir duruma dayanır.
{ "version": 3, "event": "account_assessment", "event_id": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31:ato-state-not_assessed", "request_id": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31", "phase": "beacon", "account_assessment": { "type": "behavior-drift/2", "account_id": "user-42", "state": "not_assessed", // always present, one of three values "reason": "profile_not_ready", // only when state is not_assessed "profile": { "windows": 3, // windows in the owner's reference ring "windows_effective": 2, // of those, how many yielded a distance "oldest_window_age_seconds": 1837 } } // …the remaining identification fields}state asla eksik ve asla boş değildir:
state | Anlamı | Ne yapmalı |
|---|---|---|
assessed_clear | Değerlendirildi; davranış sahibiyle eşleşiyor | Hiçbir şey |
assessed_alert | Değerlendirildi; davranış sapıyor | Step-up — account_takeover uyarısı aynı kararı taşır |
not_assessed | Karar verilmedi | Temiz saymayın; kendi sinyallerinize dönün |
reason (yalnızca not_assessed ile):
reason | Anlamı |
|---|---|
profile_not_ready | Sahibin referansı şu anda bu hesap için karar üretemiyor. Bunu bir aşama değil, bir durum olarak görün: hiç değişmeyebilir, bu yüzden beklemeyin |
profile_learning | Referans hâlâ biriktiriliyor |
window_too_sparse | Bir insan vardı, ancak pencere çok az etkileşim taşıyordu |
not_computable | Pencere ile referansın ortak bilgilendirici ekseni yoktu |
bot_traffic | Yeterli veri vardı ve değerlendirilecek bir insan yoktu |
2026-10-04 18:00 UTC'den beri window_too_sparse ve not_computable, referansı hazır
olan bir sahip için artık verilmez — böyle bir pencere profile_not_ready olarak
raporlanır. Bu iki neden listede kalır, çünkü daha önceki teslimatlar onları taşır:
handler'ınız bunlara göre dallanıyorsa profile_not_ready'yi de aynı yola yönlendirin
ve bu nedenlerin oranlarını bu tarihin iki yanında karşılaştırmayın.
state ve reason plana bağlı değildir. verdict, drift_score gibi Business+'tır.
verdict bloğu yalnızca assessed_clear ve assessed_alert ile bulunur.
not_assessed ile blok sıfırlarla doldurulmaz, bulunmaz — 0 threshold yanında 0
score, "davranış tam olarak eşleşti" diye okunurdu.
| Alan | Anlamı |
|---|---|
severity | low veya high — bilinçli olarak iki bant: orta bir bant aynı ölçekte ikinci bir eşik gerektirirdi |
score | Kararın dayandığı değer |
threshold | Gerçekte karşılaştırıldığı değer |
scale | Skorun nasıl kurulduğu: manhattan-normalized, normalleştirilmiş davranış uzayında d/(1+d)'dir; 0 tam eşleşme demektir |
basis | ring — sahibin geçmiş güvenilir pencerelerinden en yakınına olan mesafe; centroid — ortalama profiline olan mesafe |
windows | Skorda kaç pencerenin birleştirildiği |
score ve threshold her zaman aynı, adı belirtilmiş ölçektedir; bu yüzden çift kararı
yeniden üretir: uyarı tam olarak score > threshold olduğunda tetiklenir.
Ne sıklıkla gelir. Ziyaret başına durum başına en fazla bir teslimat — pratikte
davranış penceresi başına değil, linked_id taşıyan ziyaret başına bir tane. Bir durum
tek bir ziyaret içinde değişebilir — örneğin referans öğrenmeyi bitirir ve
not_assessed, assessed_clear olur — ve o zaman ikisini de sırayla alırsınız. Bu geçiş
mümkündür, vaat edilmez: profile_not_ready hesabın tüm ömrü boyunca sürebilir.
Neyi vaat etmez. En iyi korunan hesaplar, uzun oturumları ve tam bir referans profili olan aktif kullanıcılardır; en kötü korunanlar ise ele geçirmenin daha tehlikeli olduğu seyrek kullanıcılardır. Bu, ayarlanabilecek bir eşik değil, yapının bir özelliğidir. Olay, bir referanstan davranışsal sapmayı bildirir — genel olarak hesap ele geçirmeyi yakalama iddiası değildir.
attack_detected olayıBot artışı uyarısı, bir attack bloğuyla ortak v3 zarfında gelir. Kimlik tespiti alanı
yoktur — bu workspace düzeyinde bir olaydır:
{ "version": 3, "event": "attack_detected", "event_id": "c0a8e1f2-…", // alert id; matches X-Tracio-Event-Id "timestamp": "2026-07-30T12:00:00Z", "attack": { "kind": "bot_spike", "severity": "critical", // warning | critical "window_minutes": 15, "recent_bots": 4210, "recent_total": 5100, "expected": 180.5 // the baseline expected over a window this size }}Payload sürüm 1'deki webhook'lar tarihsel düz uyarı şemasını alır — bu şema değişmez.
login_risk, trusted_device_enrolled ve trusted_device_revoked olaylarıBu üç olay, giriş riski API'sine (POST /v2/logins/assess) ve onun güvenilir
cihazlarına yaptığınız kendi çağrılarınızdan gelir. Yalnızca adıyla açık bir
abonelikte teslim edilirler — * onları kapsamaz — ve yalnızca payload sürüm 2 veya
3'teki webhook'lara; sürüm 1'in onlar için bir gövdesi yoktur.
login_risk, bir değerlendirme challenge veya review döndürdüğünde gönderilir —
allow, deny veya not_assessed durumunda asla. login_risk bloğu, saklanan
değerlendirmedir; senkron yanıtın verdiği hâliyle birebir. Olay kimliği:
login-risk:<id>; burada <id> saklanan kaydın bizdeki tanımlayıcısıdır — kendi
assessment_id değerinizi gövdeden alın.trusted_device_enrolled ve trusted_device_revoked, güvenilir bir cihazın her
kaydında, yenilenmesinde ve iptalinde gönderilir. trusted_device blokları —
user_id, device_ref, enrolled_at, expires_at, revoked_at, revoked_by
(api veya dashboard) — olay anındaki bir anlık görüntüdür;
trusted_device_enrolled ile revoked_at ve revoked_by null olur. Olay kimliği:
trusted-device:<n>.Asenkron olarak, çağrıdan sonra yaklaşık beş saniyeye kadar gönderilirler ve
X-Tracio-Request-Id başlığı taşımazlar — ziyareti bulmak için
login_risk.request_id kullanın. Webhook denetim ve uyarı için bir bildirimdir; kararın
kendisi senkron yanıttır.
{ "version": 3, "event": "login_risk", "event_id": "login-risk:4b1f9e2c-6d3a-4f80-9b7e-2a5c8d1e0f37", "timestamp": "2026-10-17T10:00:00Z", "login_risk": { "assessment_id": "snap-1", "user_id": "alice", "state": "assessed", "recommendation": "challenge", "reasons": ["new_device"] // …the rest of the assessment }}{ "version": 3, "event": "trusted_device_revoked", "event_id": "trusted-device:7", "timestamp": "2026-10-17T11:00:00Z", "trusted_device": { "user_id": "alice", "device_ref": "7978151c54e94838", "enrolled_at": "2026-10-17T10:00:00Z", "expires_at": "2026-11-16T10:00:00Z", "revoked_at": "2026-10-17T11:00:00Z", "revoked_by": "dashboard" }}affiliate_threshold_crossed olayıYalnızca adıyla açık bir abonelikte teslim edilir — * onu kapsamaz — ve yalnızca
payload sürüm 2 veya 3'teki webhook'lara. TRACIO her 15 dakikada bir, yeterli verisi olan
her affiliate'in kalite skorunu yeniden hesaplar ve önerisi kötüleştiğinde olayı
gönderir: none → review, none → hold veya review → hold. Bir iyileşme hiçbir şey
göndermez ve bir sonraki kötüleşmenin yeniden bildirilmesine izin verir. Olay
workspace'e aittir: her ortamın abone webhook'larına gider ve X-Tracio-Request-Id
başlığı taşımaz. Olay kimliği:
affiliate-threshold:<affiliate_id>:<recommendation>:<unix time>.
{ "version": 3, "event": "affiliate_threshold_crossed", "event_id": "affiliate-threshold:aff_17:review:1792490400", "timestamp": "2026-10-20T10:00:00Z", "affiliate_threshold": { "affiliate_id": "aff_17", "recommendation": "review", // none | review | hold "previous_recommendation": "none", "quality_score": 72, // 0..100, higher is better "hold_days": 14, // the current hold period of the workspace "crossed_at": "2026-10-20T10:00:00Z", "metrics": { "reg_to_ftd": 0.31, "active14_share": 0.42, "dup_device_share": 0.3, "dup_person_share": 0.1, "ring_share": 0.05, "bonus_hunter_share": 0.2, "dc_vpn_bot_share": 0.1, "chargeback_share": 0.03, "affiliate_fraud_share": 0, "no_visit_share": 0.05 } }}metrics, affiliate'in son 90 gündeki paylarıdır; panel raporunun gösterdiklerinin
aynısı: ilk depozitoya ulaşan kayıtların payı (reg_to_ftd), kayıttan 14 gün sonra hâlâ
aktif olan oyuncuların payı (active14_share) ve yinelenen bir cihaz veya kişiyle, bir
dolandırıcılık halkasından, bonus avcılarından, bir veri merkezinden, VPN'den veya
bottan gelen, chargeback ya da affiliate dolandırıcılığı olarak etiketlenen ve
bulunmuş bir ziyareti olmayan dönüşümlerin payları. TRACIO yalnızca önerir — bekletmenin
kendisi ve herhangi bir ödeme kararı affiliate platformunuzda kalır. Payload sürüm
2'de aynı gövde camelCase anahtarlara sahiptir: blok affiliateThreshold'dur;
affiliateId, previousRecommendation, qualityScore ve benzerleriyle.
transaction_state_changed olayıBusiness ve üzeri. POST /v2/transactions'a gönderdiğiniz bir işlemin sonucu
değiştiğinde gönderilir: kurallar REVIEW veya DECLINE kararı verdi (bir APPROVE
hiçbir şey göndermez), bir analist işlemi panelde incelemeye gönderdi ya da bir etiket
ayarlandı, değiştirildi veya kaldırıldı. Bir talep incelemedeyken bonusu bekletmek ve
sonuç netleşince onu yoklama yapmadan alıkoymak ya da serbest bırakmak için kullanın.
* bu olayı kapsar; yalnızca payload sürüm 2 veya 3'teki webhook'lara teslim edilir. Bir
ortama bağlı webhook onu yalnızca o ortam için alır.
{ "version": 3, "event": "transaction_state_changed", "event_id": "txn-state:7d1c2b3a-0000-4000-8000-000000000042:118", "timestamp": "2026-10-15T10:04:00Z", "transaction": { "id": "7d1c2b3a-0000-4000-8000-000000000042", "transaction_id": "bonus-claim-1842", "state": "REVIEW", // always the decision of the rules "fraud_score": 50, "effective_state": "DECLINE", // the outcome to act on "recommendations": ["withhold_bonus"], "label": "fraud_detection_bonus_abuse", "label_source": "api", // api | dashboard "label_at": "2026-10-15T10:04:00Z", "previous_effective_state": "REVIEW" // …applied_rules and evidence, as in the transaction response }}| Anahtar | Anlamı |
|---|---|
effective_state | Göre hareket edilecek sonuç: ayarlanmışsa analistin veya etiketin durumu, aksi hâlde state |
recommendations | effective_state'ten türetilen, bonusla ne yapılacağı |
label, label_source, label_at | Geçerli etiket, nerede ayarlandığı (api veya dashboard) ve ne zaman; işlemin etiketi yoksa üçü de null'dır |
previous_effective_state | Bu değişiklikten önceki effective_state; otomatik kararda gönderilen olay için null |
Blok, işlemi olay gönderildiği andaki hâliyle gösterir: iki değişiklik hızla birbirini
izlerse, iki olay da en son durumu taşır; her biri kendi previous_effective_state ve
timestamp değeriyle. Sıra garanti edilmez — timestamp'e göre sıralayın ve geçerli
durumu için işlemi API üzerinden okuyun. Olay kimliği: otomatik karar için
txn-state:<id>:created, sonraki her değişiklik için txn-state:<id>:<n>. Olay,
etiketi kimin ayarladığını söylemez — yalnızca nereden geldiğini.
reputation_changed olayıBusiness ve üzeri. Kuruluşunuzun gördüğü bir kişinin müşteriler arası itibarı başka bir
banda geçtiğinde gönderilir (örneğin clean → suspicious). Şu anda gözlem modunda
çalışan kişi katmanını gerektirir — bu nedenle olay yalnızca cihazlar arası kimlik
çözümlemesinin etkin olduğu workspace'lerde tetiklenir. Bu kişi düzeyinde bir olaydır:
request_id'si ve ziyaret blokları yoktur.
{ "version": 3, "event": "reputation_changed", "event_id": "person-reputation:pn_4f2a…:clean->suspicious:2026-07-30T12:10:00.123456Z", "timestamp": "2026-07-30T12:10:00Z", "reputation_change": { "person_id": "pn_4f2a…", "score": 46, "band": "suspicious", // clean | suspicious | fake "previous_band": "clean", "categories": ["chargeback"], "visitor_ids": ["X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"], // the person's visitors in YOUR data "linked_accounts_count": 4 // omitted when zero }}Blok anahtarı reputation değil, reputation_change'dir: ilki belirli bir ziyaret
bağlamındaki itibar için kullanılır ve ikisi farklı şeylerdir. Şema 1 tarihsel düz
biçimi teslim eder — aynı alanlar en üst düzeyde.
Her teslimat bir X-Tracio-Signature başlığı içerir:
X-Tracio-Signature: t=1710432000,v1=5257a869e7ecebed…t, isteğin imzalandığı Unix zaman damgasıdır (saniye).v1, webhook gizli anahtarınızla anahtarlanmış "<t>.<rawRequestBody>" değerinin
onaltılık kodlanmış HMAC-SHA256'sıdır.Zaman damgası imzalanan içeriğin parçasıdır; bu da replay koruması sağlar.
Doğru yapılması gereken iki şey var; aksi hâlde doğrulama üretimde başarısız olur:
v1= değeriyle eşleşmeyi kabul edin. Gizli anahtar rotasyonu
sırasında başlık iki imza taşır ve bunlardan yalnızca birini saklayan bir
ayrıştırıcı, rotasyon penceresi boyunca geçerli teslimatları reddeder.// Express.js exampleimport express from "express"import crypto from "crypto"
const app = express()
// Capture the raw body so the signature can be verified byte-for-byte.app.use( express.json({ verify: (req, _res, buf) => { ;(req as any).rawBody = buf }, }),)
function verifySignature(rawBody: Buffer, header: string, secret: string): boolean { if (!header) return false
const parts = header.split(",").map((p) => p.trim()) const ts = parts.find((p) => p.startsWith("t="))?.slice(2) if (!ts) return false
// Replay protection: reject timestamps more than five minutes old. if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false
// Sign the raw bytes: the "<t>." prefix plus the raw request body. const signed = Buffer.concat([Buffer.from(`${ts}.`, "utf8"), rawBody]) const expected = crypto.createHmac("sha256", secret).update(signed).digest("hex") const exp = Buffer.from(expected, "hex")
// During a rotation window the header carries several v1= — any may match. return parts.some((p) => { if (!p.startsWith("v1=")) return false const got = Buffer.from(p.slice(3), "hex") // Compare lengths BEFORE timingSafeEqual: it throws on differing lengths, // and one junk header would turn the handler into a 500. return got.length === exp.length && crypto.timingSafeEqual(got, exp) })}
app.post("/webhook/tracio", (req, res) => { const header = req.headers["x-tracio-signature"] as string if (!verifySignature((req as any).rawBody, header, WEBHOOK_SECRET)) { return res.status(401).json({ error: "Invalid signature" }) }
const event = req.body console.log(`Visitor: ${event.visitor_id}`) console.log(`Bot: ${event.bot?.result}`) // "human" | "bot" | "uncertain"
res.status(200).send("OK")})Şema 2 ve 3 teslimatları ek olarak X-Tracio-Signature-Ed25519
(t=<unix>,kid=<id>,v1=<base64>) taşır. HMAC gizli anahtarını iki taraf da bilir; bu
nedenle HMAC, gönderenin gizli anahtarı bildiğini kanıtlar ama isteğin TRACIO'dan
geldiğini kanıtlamaz — bunu asimetrik imza yapar. Genel anahtarlar
https://api.tracio.ai/.well-known/webhook-keys adresinde yayımlanır ve kid ile
indekslenir: public_key alanını okuyun. Eski takma ad publicKey aynı değeri taşır ve
2027-04-12 tarihinde kaldırılacaktır.
Panelden gönderilen test teslimatları yalnızca HMAC ile imzalanır — platformun özel
anahtarı teslimat düğümlerinde yaşar ve bilinçli olarak panele açık değildir.
Ed25519'u katı biçimde zorunlu kılan bir doğrulayıcı, test teslimatlarını geçirmek
zorundadır (bunların event_id değerinde :test soneki bulunur); aksi hâlde üretim
sapasağlamken panelden test yapmak başarısız olur. Aynı dikkat biçim denetimleri için
de geçerlidir: bir test teslimatı request_id değerini test_<hex> biçiminde ve
visitor_id olarak birebir test_visitor dizesini taşır; bunları üretim biçimlerine
göre doğrulayan bir handler, aslında kusursuz olan bir teslimatı reddeder.
Rotasyondan sonra her iki gizli anahtar da 24 saat geçerli kalır ve başlık her iki imzayı da taşır; böylece teslimat kaybetmeden yapılandırmanızı güncelleyebilirsiniz. Revoke now eylemi bu pencereyi kısa keser. Gizli anahtarı kendi tarafınızda 24 saat içinde güncelleyin: pencere kapandığında eski anahtar eşleşmeyi bırakır ve uç noktanız geçersiz imzaya 4xx ile yanıt veriyorsa, arka arkaya beş böyle yanıt webhook'u devre dışı bırakır.
| Başlık | Açıklama |
|---|---|
Content-Type | application/json |
X-Tracio-Signature | t=<unix>,v1=<hmac_sha256_hex> — rotasyon penceresinde iki v1= |
X-Tracio-Signature-Ed25519 | Platform imzası, t=<unix>,kid=<id>,v1=<base64> (yalnızca v2 ve v3) |
X-Tracio-Event-Id | Teslimat tanımlayıcısı — idempotency anahtarı |
X-Tracio-Request-Id | Ziyaret tanımlayıcısı, request_id ile eşleşir (yalnızca v2 ve v3). Yalnızca ziyaret olayları için gönderilir — identification, account_takeover ve account_assessment |
X-Tracio-Event-Type | Olay türü (yalnızca v2 ve v3) |
X-Tracio-Delivery-Attempt | 1'den başlayan deneme numarası (yalnızca v2 ve v3) |
X-Tracio-Payload-Version | 3 veya 2 (yalnızca v2 ve v3) |
X-Tracio-Webhook-Id | Bu teslimatı üreten webhook'un tanımlayıcısı |
Teslimatlar yeniden denenebilir ve yeniden deneme aynı X-Tracio-Event-Id'yi taşır.
Tekilleştirmeyi buna göre yapın:
app.post("/webhook/tracio", async (req, res) => { const eventId = req.headers["x-tracio-event-id"] as string
const existing = await db.webhooks.findOne({ eventId }) if (existing) return res.status(200).send("Already processed")
await db.webhooks.insert({ eventId, processedAt: new Date() }) await processWebhookEvent(req.body)
res.status(200).send("OK")})event_id'nin webhook başına değil, olay başına benzersiz olduğuna dikkat edin:
workspace'teki birden fazla webhook aynı olaya aboneyse, her biri aynı tanımlayıcıya
sahip bir teslimat alır. identification için değer <request_id>:<phase> olarak
kurulur; bu yüzden tek bir ziyaretin üç fazı tek bir kayda çökmek yerine birbirinden
bağımsız olarak tekilleştirilir. Ziyareti olmayan olayların kendi biçimleri vardır —
yukarıda her olaya bakın.
2xx ile yanıt verin — bir teslimatın kabul edildiğinin tek işareti budur.
| Yanıt | Ne olur |
|---|---|
2xx | Teslimat tamamlandı |
429 Too Many Requests | Başarısızlık sayılmaz ve bir denemeyi harcamaz; daha uzun bir Retry-After dikkate alınır |
408, 425, 5xx, kopan bağlantı | Artan bir bekleme ile yeniden denenir |
410 Gone | Uç nokta kaldırılmış sayılır — webhook anında devre dışı bırakılır |
Diğer 4xx | Yeniden denenir, ancak arka arkaya beşi webhook'u devre dışı bırakır — 400/401/404 yeniden denemeyle düzelmez |
Yeniden deneme takvimi: 5 sn → 30 sn → 2 dk → 10 dk → 30 dk → 2 sa → 6 sa (8 deneme). İlk denemeler bir dakikaya sığar; bu yüzden servisinizin kısa bir yeniden başlatması size bir bildirime mal olmaz. Her bekleme, yarım değer ile tam değer arasında rastgele seçilir; böylece bir kesintiden sonra yeniden denemeler tek bir yaylım hâlinde tetiklenmez.
Otomatik devre dışı bırakma hem bir eşik (arka arkaya 20 başarısızlık ya da 5 yapılandırma hatası) hem de en az 15 dakika kesintisiz başarısızlık gerektirir — kuyrukta çok sayıda teslimat birikmiş olsa bile kısa bir yeniden başlatma entegrasyonu öldüremez. 15 dakikadan uzun bir boşluk sayımı sıfırlar. Panel; yanıt kodu ve hata metniyle birlikte nedeni ve sayaçları sıfırlayan bir Re-enable düğmesini gösterir.
| Plan | Workspace başına webhook |
|---|---|
| Free | Kullanılamaz |
| Pro | 5 |
| Business | 20 |
| Enterprise | 100 |
Uç noktalar genel bir IP adresine sahip https olmalıdır — özel ve loopback adresleri,
yönlendirme sırasında dahil olmak üzere reddedilir — ve en fazla iki yönlendirme
derinliğinde olmalıdır.
Yalnızca 307 ve 308 yönlendirmeleri izlenir. 301, 302 ve 303 istemciye
GET'e geçmesini ve gövdeyi bırakmasını söyler; bu nedenle teslimat onları izlemez ve
deneme başarısız sayılır. Yük dengeleyiciniz URL'yi normalleştiriyorsa (www veya
sondaki eğik çizgi ekliyorsa), webhook'u doğrudan nihai URL'ye yönlendirin.
Webhook'lar panelden yönetilir. Panel, uygulama sunucusunda (örneğin
https://app.tracio.ai/api/v1) sunulan workspace kapsamlı bir yönetim API'sini sürer;
aşağıdaki uç noktalar da onun çağırdığı uç noktalardır. Tüm webhook uç noktaları
/workspaces/{wsId} altında bulunur.
Burası sunucudan sunucuya bir yüzey değildir. Yönetim API'si yalnızca panel oturumu JWT'nizi kabul eder ve bunu workspace rolünüze karşı denetler (RBAC);
tracio_sk_…biçimindeki bir gizli anahtar burada reddedilir. Bu oturum tarayıcıda yaşadığı ve onunla birlikte sona erdiği için, aşağıdaki çağrıları otomatikleştirilecek bir entegrasyon gibi değil, panelin ne yaptığının bir tarifi gibi ele alın. Kendi arka ucunuzdan programatik erişim için salt okunur Data API'yi kullanın.
curl -X POST https://app.tracio.ai/api/v1/workspaces/{wsId}/webhooks \ -H "Authorization: Bearer <session-jwt>" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-server.com/webhook/tracio", "events": [] }'İmzalama gizli anahtarı TRACIO tarafından üretilir ve oluşturmada (ve rotasyonda)
signingSecret altında bir kez döndürülür. Güvenli biçimde saklayın — imzaları
doğrulamak için kullandığınız anahtar odur.
{ "ok": true, "data": { "id": "b3d4f8a1-2c67-4e9b-8f05-7a1d3c9e2b48", "workspaceEnvironmentId": "b201f2ba-…", "url": "https://your-server.com/webhook/tracio", "events": [], "signingSecret": "f3a9…<hex>", "status": "active", "successRate": 100, "createdAt": "2026-07-30T12:00:00Z" }}Sonraki okumalarda signingSecret maskelenir (null) — yalnızca oluşturma ve gizli
anahtar rotasyonu onu açığa çıkarır.
| Yöntem | Yol | Açıklama |
|---|---|---|
GET | /workspaces/{wsId}/webhooks | Webhook'ları listele |
PATCH | /workspaces/{wsId}/webhooks/{webhookId} | url / events / status güncelle |
DELETE | /workspaces/{wsId}/webhooks/{webhookId} | Webhook sil |
POST | /workspaces/{wsId}/webhooks/{webhookId}/test | İmzalı test teslimatı gönder |
POST | /workspaces/{wsId}/webhooks/{webhookId}/secret/rotate | İmzalama gizli anahtarını rotasyona sok |
GET | /workspaces/{wsId}/webhooks/{webhookId}/deliveries | Son teslimat denemelerini listele |
Zaman aşımlarından kaçınmak için mümkün olduğunca hızlı 2xx döndürün ve payload'ı
asenkron biçimde işleyin:
app.post("/webhook/tracio", async (req, res) => { res.status(200).send("OK") processWebhookEvent(req.body).catch(console.error)})
async function processWebhookEvent(event: WebhookPayload) { await db.events.insert(event)
if (event.decision?.risk_score > 50) { await alertFraudTeam(event) }
if (event.bot?.result === "bot") { await blockVisitor(event.visitor_id) }}Uç noktanıza imzalı bir örnek payload göndermek ve onun erişilebilir olduğunu ve
imzaları doğru doğruladığını teyit etmek için bir webhook üzerindeki Test eylemini
(veya POST .../webhooks/{webhookId}/test) kullanın.
Yerel geliştirme için sunucunuzu ngrok gibi bir tünelle dışarı açın:
ngrok http 3000# Use the generated URL as your webhook endpoint