Webhooky doručují identifikační události na váš server v reálném čase. Pokaždé, když
je návštěvník identifikován, odešle TRACIO HTTP požadavek POST na vámi nastavenou
URL webhooku. Tělo požadavku je payload události.
Jsou zároveň jediným kanálem, který doručuje pozdní verdikty — ty, u nichž chování návštěvníka prokázalo automatizaci až po načtení stránky.
Nastavte je v dashboardu v sekci Settings → Webhooks. Webhooky vyžadují tarif Pro nebo vyšší.
| Událost | Kdy | Tarif |
|---|---|---|
identification | Při každé návštěvě — fáze primary, late a correction | Všechny |
account_takeover | Chování pod účtem už neodpovídá profilu jeho vlastníka | Business+ |
attack_detected | Nárůst botů na vašem webu | Business+ |
reputation_changed | Reputace osoby stojící za zařízením se změnila | Business+ |
Názvy událostí používají podtržítka, nikdy tečky — žádné visitor.created ani
session.created neexistuje. reputation_changed vyžaduje vrstvu osoby, takže se
spouští jen pro workspacy, kde je zapnuté rozpoznávání identity napříč zařízeními.
Webhook se přihlašuje ke konkrétním typům; samostatná hodnota * znamená „každý typ,
včetně těch přidaných později“. Neznámý typ je při vytvoření nebo úpravě odběru
odmítnut s kódem 400, takže vás překlep nenechá s webhookem, který se mlčky nikdy
nespustí.
identificationJedna návštěva vytvoří až tři doručení, která sdílejí stejné requestId:
primary — počáteční verdikt, při načtení stránky.late — obohacení zhruba o devět sekund později, jakmile dorazí pomalé kontroly.correction — korekce na základě chování (ukazatel, klávesnice, scrollování).Spojujte je podle requestId a rozlišujte podle phase. Pozdější fáze má
přednost: pokud primary řekl human a correction říká bot, správná je ta
druhá.
Nespoléhejte na pořadí doručení. Každá fáze se doručuje nezávisle a podle
vlastního plánu opakování — pokud primary skončil v opakování a late uspěl hned
napoprvé, dorazí vám v opačném pořadí. Přednost určujte podle pole phase, ne podle
času přijetí.
Tyto tři jsou jediné fáze události identification. Dorazí k vám ještě jedna další
hodnota: account_takeover nese phase: "beacon", protože upozornění na převzetí
účtu vzniká výhradně z behaviorálního beaconu.
Všimněte si nesouladu, který tím vzniká, protože se týká idempotence. Produkční
doručení identification má eventId přesně ve tvaru <requestId>:<phase>, ale dvě
doručení tento vzorec porušují. account_takeover má <requestId>:ato — přípona je
literál ato, ne hodnota pole phase. Testovací doručení odeslané z dashboardu má
<requestId>:test, zatímco phase v jeho těle podle schématu 2 stále uvádí
primary — a tělo podle schématu 1 pole phase nemá vůbec, takže přípona je vidět
jedině v hlavičce. Používejte eventId přímo jako klíč idempotence a nikdy jej
neskládejte znovu z requestId a phase. Porovnávejte s hodnotami, které
zpracováváte, a cokoli jiného ignorujte, místo abyste doručení odmítli.
attack_detected je událost na úrovni workspace: nemá requestId, nemá visitorId
ani žádný z bloků browser, geo, bot či decision — ty klíče prostě chybí.
account_takeover vzniká z konkrétní návštěvy a nese celé identifikační tělo pro váš
tarif plus blok accountAlert. Pokud všechny události zpracováváte v jednom handleru,
zkontrolujte event dřív, než sáhnete na pole návštěvy.
| Verze | Pro koho | Jak přepnout |
|---|---|---|
1 | Webhooky vytvořené před vznikem v2 | Zůstává pro ně výchozí |
2 | Nové webhooky | Přepínač na kartě webhooku v dashboardu |
Schéma v1 je zmrazené — žádné jeho pole se nemění, takže stávající integrace fungují dál bez úprav. Vše nové žije ve v2, kterou odesílají nové webhooky.
{ "version": 2, "event": "identification", "eventId": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31:primary", // "<requestId>:<phase>" — the idempotency key "requestId": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31", // visit identifier, shared by all phases "phase": "primary", "visitorId": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "linkedId": "user-42", // your ?lid=, if you passed one "tag": "checkout", "timestamp": "2026-07-30T12:00:00Z", "url": "https://shop.example.com/checkout", "ip": "203.0.113.44", "userAgent": "Mozilla/5.0 …", "browser": { "name": "Chrome", "version": "138" }, "os": { "name": "macOS", "version": "15.5" }, "device": "desktop", "gpu": "Intel Iris Plus Graphics 655", // model grafického adaptéru, normalizovaný; chybí, když není znám "geo": { "country": "DE", "city": "Berlin", "lat": 52.52, "lon": 13.405, "timezone": "Europe/Berlin" }, "network": { "vpn": false, "proxy": true, "tor": false, "datacenter": true, "connectionType": "DCH", "proxyDetected": true // HTTP provoz a surová síťová cesta vycházejí přes různé sítě }, "bot": { "result": "human", "score": 3.2 }, // human | bot | uncertain "identification": { "confidence": 0.97, "incognito": false }, "decision": { "action": "real", "riskScore": 12.2 } // real | fake | suspicious}Nulové a prázdné hodnoty se vynechávají. Řetězcová a číselná pole s nulovou
hodnotou (například bot.type u člověka) v JSON chybí — nedělejte z nich ve svých
schématech povinná pole a vnořené bloky čtěte obezřetně.
bot.score a decision.riskScore jsou desetinná čísla na škále 0..100 s jednou
číslicí za desetinnou čárkou — přesně ta čísla, která pro tutéž návštěvu vykazuje
dashboard. (V zamrzlém schématu v1 mají jiné jednotky: zlomek 0..1, resp. 0..255.)
bot.type je buď název rozpoznaného bota, nebo označení rodiny. Slovník hodnot najdete
v části Typy botů — interní názvy kontrol se
nezveřejňují v žádném tarifu.
| Pole | Typ | Popis |
|---|---|---|
version | number | Verze schématu payloadu (2) |
event | string | Typ události |
eventId | string | Identifikátor doručení — klíč idempotence |
requestId | string | Identifikátor návštěvy (UUID), sdílený všemi jejími fázemi |
phase | string | primary, late, correction; account_takeover nese beacon |
visitorId | string | Stabilní identifikátor návštěvníka |
linkedId | string | Propojený identifikátor dodaný klientem |
tag | string | Vlastní tag dodaný klientem |
timestamp | string | Čas události (RFC 3339) |
url | string | URL stránky, kde byla událost zachycena |
ip | string | IP adresa klienta |
userAgent | string | Surový řetězec user-agent klienta |
browser.name / .version | string | Detekovaný prohlížeč |
os.name / .version | string | Detekovaný operační systém |
device | string | Třída zařízení (např. desktop, mobile) |
gpu | string | Model grafického adaptéru tak, jak jej hlásí prohlížeč (WebGL), normalizovaný na čitelný název (Intel Iris Xe Graphics, Apple M1 Pro); Software renderer pro softwarové rasterizéry; chybí, když není znám |
geo | object | Geolokace podle IP: country, city, lat, lon, timezone |
network | object | vpn, proxy, tor, datacenter (booleany) a connectionType |
network.proxyDetected | boolean | HTTP provoz návštěvy a její surové síťové cesty vycházejí přes různé sítě — před prohlížečem stojí proxy nebo VPN. Dvě adresy téhož poskytovatele (NAT operátora, druhý výstup téže VPN) se nepočítají |
bot.result | string | human, bot nebo uncertain |
bot.type | string | Název bota nebo označení rodiny, když je bot detekován |
bot.score | number | Skóre bota (0–100) |
identification.confidence | number | Spolehlivost identifikace (0.0–1.0) |
identification.incognito | boolean | Anonymní režim prohlížení |
decision.action | string | real, fake nebo suspicious |
decision.riskScore | number | Souhrnné skóre rizika (0–100) |
Pro a vyšší — jak se návštěvník chová v čase:
{ "identification": { "matchType": "exact", // exact | fuzzy | new — how the visitor was recognized "matchConfidence": 0.93, "visits": 42, "incognitoVisits": 3 }, // Present when visitor counters are available at event time (usually primary). // A missing block means "no data", not "zeros". "velocity": { "events5m": 7, "uniqueIps": 2, "uniqueLocations": 1 }, "bot": { "antidetectScore": 0 }, // antidetect indicators, 0..100 "session": { "durationSeconds": 95 } // where the visit duration is already known}Business a vyšší — proč verdikt dopadl tak, jak dopadl:
{ "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 }, "identification": { "driftScore": 0.31 }, // divergence from the account profile "deviceInfo": { "deviceId": "…", // the physical device across browsers on it "crossBrowser": true, "confidence": 0.88, "linkedBrowsers": 3 }, "network": { "isp": "Deutsche Telekom", "asn": 3320, // veřejná adresa pozorovaná na surové síťové cestě, tedy adresa za proxy // nebo VPN; chybí, když žádná taková adresa pozorována nebyla "realIp": { "address": "203.0.113.7", "country": "NL", "isp": "KPN" } }, // Desktopové prostředí ZMĚŘENÉ na linuxovém stroji ("Mint 22+", "Ubuntu", // "GNOME", "KDE"); User-Agent distribuci vyjádřit neumí. Chybí, když // nebylo určeno — u většiny linuxových návštěv a u každé nelinuxové. "osEnvironment": "Mint 22+", // Co návštěva o sobě tvrdila proti tomu, co naměřily nezávislé kontroly. // Přítomné jen tehdy, když byla podvržení skutečně odhalena; prázdné pole // `real` znamená "kontrola mlčela", nikdy "potvrzeno". U osy `gpu` nese // `claimed.gpu` deklarovaný adaptér pod stejným čitelným názvem modelu // jako pole `gpu` nejvyšší úrovně. "spoofing": { "detected": true, "claimed": { "os": "Windows 10", "browser": "Chrome 139.0" }, "real": { "os": "macOS" }, "spoofedAxes": ["os", "screen"], // os | gpu | screen | network | browser "anonymousBrowser": { "detected": true, "names": ["Linken Sphere"] } }, // Fakta o zařízení — co prohlížeč návštěvníka hlásí o stroji, očištěné na // naší straně. screen: rozlišení, barevná hloubka a device pixel ratio. // locale: vlastní preferované jazyky prohlížeče a jeho časové pásmo — na // rozdíl od geo.timezone, které se odvozuje z IP adresy; nesoulad mezi // nimi je běžnou známkou podvržené polohy. clientHints: User-Agent Client // Hints — architektura a bitovost procesoru, model zařízení (Android: kód // modelu v `model`, např. "SM-A556B", a jeho marketingový název ze seznamu // zařízení Google Play v `deviceName`, např. "Samsung Galaxy A55 5G") a // přesná verze platformy; hlásí je jen prohlížeče založené na Chromiu. // Každý blok chybí, když návštěva taková data nepřinesla, proto s každým // počítejte jako s volitelným. "screen": { "width": 2560, "height": 1600, "colorDepth": 30, "pixelRatio": 2 }, "locale": { "languages": ["en-US", "de"], "timezone": "Europe/Berlin" }, "clientHints": { "architecture": "arm", "bitness": "64", "platformVersion": "15.5.0" }, // Přítomné jen tehdy, když se grafický adaptér sám ohlásil jako virtuální; // hypervisor je uzavřený slovník (vmware, virtualbox, parallels, qemu, // hyperv, bochs, intel-gvt, vgpu). Chybějící blok znamená, že takové // doklady nejsou. "environment": { "virtualMachine": true, "hypervisor": "vmware" }, "decision": { "suspectScore": 55 }, "guidance": { "version": 1, "overall": "review" } // see below}Slovník kódů důvodů a význam severity najdete v části
Detekce botů.
guidance nese hotová doporučení „co dělat“ pro každý integrační bod, takže nemusíte
odvozovat politiku ze surových skóre:
{ "guidance": { "version": 1, "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 }}Každý scénář začíná na allow a po žebříčku se pohybuje jen nahoru:
allow → challenge → review → deny. Uvnitř scénáře vítězí nejpřísnější osa,
která se spustila, a overall je nejpřísnější napříč všemi čtyřmi scénáři.
| Doporučení | Platba | Registrace | Přihlášení | Affiliate |
|---|---|---|---|---|
allow | Zpracujte ji | Vytvořte ho | Pusťte je dovnitř | Připište konverzi |
challenge | 3-D Secure / potvrzení | Captcha, potvrzení e-mailem nebo telefonem | Step-up 2FA, opětovné ověření | Označte jako pochybnou, dokud se neprojeví aktivita |
review | Zpracujte, ale zařaďte ke kontrole | Vytvořte s omezeními | Pusťte je dovnitř a vyvolejte upozornění | Zadržte výplatu do prověření |
deny | Transakci nezpracovávejte | Vytvoření účtu odmítněte | Nepouštějte je dovnitř | Konverzi nepřipisujte |
version je verze sady pravidel — zvyšuje se, jak se logika zlepšuje. Guidance je
aditivní: nové scénáře přicházejí jako nové klíče, aniž by porušily kontrakt.
Pozdější fáze vítězí, s výjimkou částečného doporučení: doručení spočítané na
neúplné sadě vstupů je označeno "partial": true a částečné doporučení nepřebíjí
úplné doporučení přijaté dříve pro totéž requestId. V běžném doručení pole partial
zcela chybí.
Přesné prahy se záměrně nedokumentují. Doporučení, které lze zpětně rozklíčovat na skóre, přestává být obranou.
account_takeoverPouze Business a Enterprise. Tělo je celá identifikační obálka pro váš tarif plus blok
accountAlert, doručeno nejvýše jednou za návštěvu:
{ "version": 2, "event": "account_takeover", "eventId": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31:ato", "requestId": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31", "phase": "beacon", // upozornění vzniká z beaconu; jen eventId říká "ato" "accountAlert": { "type": "behavior-drift", "accountId": "user-42", // your linkedId for the account "driftScore": 0.83 } // …the remaining identification fields}Ve v1 tento blok nese type, linkedId a drift; ve v2 jsou dvě pole přejmenována —
linkedId → accountId a drift → driftScore. Až budete přepínat payloadVersion,
aktualizujte svůj handler, jinak vaše logika pro převzetí účtu přestane data mlčky
vidět.
attack_detected{ "version": 2, "event": "attack_detected", "eventId": "c0a8e1f2-…", "timestamp": "2026-07-30T12:00:00Z", "attack": { "kind": "bot_spike", "severity": "critical", // info | warning | critical "windowMinutes": 15, "recentBots": 4210, "recentTotal": 5100, "expected": 180.5 // the baseline expected over a window this size }}Každé doručení obsahuje hlavičku X-Tracio-Signature:
X-Tracio-Signature: t=1710432000,v1=5257a869e7ecebed…t je Unixový časový údaj (v sekundách), kdy byl požadavek podepsán.v1 je HMAC-SHA256 z "<t>.<rawRequestBody>" v hexadecimálním zápisu, klíčovaný
vaším tajným klíčem webhooku.Časový údaj je součástí podepisovaného obsahu, což poskytuje ochranu proti replay.
Dvě věci je třeba udělat správně, jinak ověřování v produkci selže:
v1=. Během rotace tajného klíče nese
hlavička dva podpisy a parser, který si nechá jen jeden z nich, bude po celé
okno rotace odmítat platná doručení.// 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.visitorId}`) console.log(`Bot: ${event.bot?.result}`) // "human" | "bot" | "uncertain"
res.status(200).send("OK")})Doručení podle schématu 2 navíc nesou X-Tracio-Signature-Ed25519
(t=<unix>,kid=<id>,v1=<base64>). HMAC tajný klíč znají obě strany, takže HMAC
dokazuje, že odesílatel klíč zná, ale ne že požadavek vznikl v TRACIO; to dokazuje
asymetrický podpis. Veřejné klíče jsou publikovány na
https://api.tracio.ai/.well-known/webhook-keys a indexovány podle kid.
Testovací doručení odeslaná z dashboardu jsou podepsána pouze HMAC — soukromý klíč
platformy žije na doručovacích uzlech a záměrně není dashboardu dostupný. Ověřovač,
který Ed25519 tvrdě vyžaduje, musí testovací doručení propustit (nesou příponu
:test v eventId), jinak testování z dashboardu selhává, zatímco produkce je zdravá.
Stejná opatrnost platí pro kontroly formátu: testovací doručení nese requestId ve
tvaru test_<hex> a jako visitorId literál test_visitor, takže handler, který je
validuje proti produkčním tvarům, odmítne doručení, které je jinak v pořádku.
Po rotaci zůstávají oba tajné klíče 24 hodin platné a hlavička nese oba podpisy, takže můžete aktualizovat konfiguraci, aniž byste přišli o doručení. Akce Revoke now toto okno zkrátí. Tajný klíč na své straně aktualizujte do 24 hodin: jakmile se okno zavře, starý klíč přestane odpovídat, a pokud váš endpoint odpoví na neplatný podpis kódem 4xx, pět takových odpovědí za sebou webhook vypne.
| Hlavička | Popis |
|---|---|
Content-Type | application/json |
X-Tracio-Signature | t=<unix>,v1=<hmac_sha256_hex> — dvě v1= během okna rotace |
X-Tracio-Signature-Ed25519 | Podpis platformy, t=<unix>,kid=<id>,v1=<base64> (pouze v2) |
X-Tracio-Event-Id | Identifikátor doručení — klíč idempotence |
X-Tracio-Request-Id | Identifikátor návštěvy (v2, pouze události návštěvy) |
X-Tracio-Event-Type | Typ události (pouze v2) |
X-Tracio-Delivery-Attempt | Číslo pokusu, počínaje 1 (pouze v2) |
X-Tracio-Payload-Version | 2 (pouze v2) |
X-Tracio-Webhook-Id | Identifikátor webhooku, který toto doručení vytvořil |
Doručení se mohou opakovat a opakování nese totéž X-Tracio-Event-Id. Deduplikujte
podle něj:
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")})Všimněte si, že eventId je jedinečné na událost, ne na webhook: pokud několik
webhooků ve workspace odebírá tutéž událost, každý dostane doručení se stejným
identifikátorem. Skládá se jako <requestId>:<phase>, a proto se tři fáze jedné
návštěvy deduplikují nezávisle, místo aby splynuly v jednu.
Odpovídejte kódem 2xx — je to jediná známka toho, že doručení bylo přijato.
| Odpověď | Co se stane |
|---|---|
2xx | Doručení dokončeno |
429 Too Many Requests | Nepočítá se jako selhání a nespotřebuje pokus; delší Retry-After je respektován |
408, 425, 5xx, přerušené spojení | Opakuje se s rostoucí pauzou |
410 Gone | Endpoint se považuje za odstraněný — webhook se okamžitě vypne |
Ostatní 4xx | Opakuje se, ale pět za sebou webhook vypne — 400/401/404 opakováním nevyléčíte |
Plán opakování: 5 s → 30 s → 2 min → 10 min → 30 min → 2 h → 6 h (8 pokusů). První opakování se vejdou do minuty, takže krátký restart vaší služby vás nestojí notifikaci. Každá pauza je náhodně rozprostřena mezi polovinou a plnou hodnotou, aby po výpadku opakování nevystřelila v jedné salvě.
Automatické vypnutí vyžaduje zároveň práh (20 selhání za sebou nebo 5 chyb konfigurace) a nejméně 15 minut nepřetržitých selhání — krátký restart integraci nezabije, ani když bylo ve frontě mnoho doručení. Mezera delší než 15 minut počítání restartuje. Dashboard ukazuje důvod včetně kódu odpovědi a textu chyby a tlačítko Re-enable, které čítače vynuluje.
| Tarif | Webhooků na workspace |
|---|---|
| Free | Není k dispozici |
| Pro | 5 |
| Business | 20 |
| Enterprise | 100 |
Endpointy musí být https s veřejnou IP adresou — privátní a loopback adresy jsou
odmítnuty, a to i při přesměrování — a nejvýše dvě přesměrování do hloubky.
Následují se pouze přesměrování 307 a 308. 301, 302 a 303 instruují
klienta, aby přešel na GET a zahodil tělo, takže doručení je nenásleduje a pokus se
počítá jako neúspěšný. Pokud váš load balancer normalizuje URL (přidává www nebo
koncové lomítko), nasměrujte webhook rovnou na finální URL.
Webhooky se spravují v dashboardu. Dashboard pohání management API v rozsahu
workspace, obsluhované na hostu aplikace (například https://app.tracio.ai/api/v1), a
endpointy níže jsou právě ty, které volá. Všechny endpointy webhooků žijí pod
/workspaces/{wsId}.
Není to rozhraní pro komunikaci mezi servery. Management API přijímá pouze JWT vaší relace dashboardu, kontrolované proti vaší roli ve workspace (RBAC); secret key
tracio_sk_…je zde odmítnut. Protože tato relace žije v prohlížeči a spolu s ním vyprší, berte volání níže spíš jako popis toho, co dělá dashboard, než jako integraci k automatizaci. Pro programový přístup z vlastního backendu použijte read-only Data API.
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": [] }'Podpisový tajný klíč generuje TRACIO a vrací jej jednou při vytvoření (a při
rotaci) v poli signingSecret. Uložte jej bezpečně — je to klíč, kterým ověřujete
podpisy.
{ "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" }}Při dalších čteních je signingSecret maskovaný (null) — odhalí jej jen vytvoření
a rotace tajného klíče.
| Metoda | Cesta | Popis |
|---|---|---|
GET | /workspaces/{wsId}/webhooks | Seznam webhooků |
PATCH | /workspaces/{wsId}/webhooks/{webhookId} | Aktualizovat url / events / status |
DELETE | /workspaces/{wsId}/webhooks/{webhookId} | Smazat webhook |
POST | /workspaces/{wsId}/webhooks/{webhookId}/test | Odeslat podepsané testovací doručení |
POST | /workspaces/{wsId}/webhooks/{webhookId}/secret/rotate | Rotovat podpisový tajný klíč |
GET | /workspaces/{wsId}/webhooks/{webhookId}/deliveries | Seznam nedávných pokusů o doručení |
Vraťte 2xx co nejrychleji a payload zpracujte asynchronně, abyste se vyhnuli
timeoutům:
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?.riskScore > 50) { await alertFraudTeam(event) }
if (event.bot?.result === "bot") { await blockVisitor(event.visitorId) }}Použijte na webhooku akci Test (nebo POST .../webhooks/{webhookId}/test) a
odešlete podepsaný vzorový payload na svůj endpoint, abyste ověřili, že je dostupný a
že podpisy kontroluje správně.
Pro lokální vývoj zpřístupněte svůj server tunelem, například přes ngrok:
ngrok http 3000# Use the generated URL as your webhook endpoint