Webhooks पहचान (identification) इवेंट रियल-टाइम में आपके सर्वर तक पहुँचाते हैं। हर बार
जब किसी विज़िटर की पहचान होती है, TRACIO आपके कॉन्फ़िगर किए गए webhook URL पर एक HTTP
POST अनुरोध भेजता है। अनुरोध का body ही इवेंट payload है — इसके चारों ओर कोई
लपेटने वाला envelope नहीं होता।
Body एक फ़्लैट, camelCase JSON दस्तावेज़ है। यह आंतरिक इवेंट का एक सुव्यवस्थित
सार्वजनिक उपसमुच्चय है — इसमें कोई fingerprint hash या आंतरिक डिटेक्शन मार्कर नहीं होते।
{ "requestId": "1710432000_abc123def", "phase": "primary", "visitorId": "X7fh2Hg9LkMn3pQr", "linkedId": "user_12345", "tag": "login", "timestamp": "2024-03-12T16:00:00Z", "url": "https://your-app.com/login", "ip": "94.142.239.124", "userAgent": "Mozilla/5.0 …", "browser": { "name": "Chrome", "version": "120.0" }, "os": { "name": "macOS", "version": "14.3" }, "device": "desktop", "geo": { "country": "CZ", "city": "Prague", "lat": 50.05, "lon": 14.4, "timezone": "Europe/Prague", "isp": "Example ISP" }, "network": { "vpn": false, "proxy": false, "tor": false, "datacenter": false, "connectionType": "residential" }, "bot": { "result": "human", "type": "", "score": 0.02 }, "identification": { "confidence": 0.95, "incognito": false, "visitType": "returning" }, "decision": { "action": "allow", "riskScore": 4, "suspectScore": 0.08 }}| फ़ील्ड | प्रकार | विवरण |
|---|---|---|
requestId | string | विशिष्ट इवेंट पहचानकर्ता (साथ ही एक idempotency key) |
phase | string | primary या late — नीचे देखें |
visitorId | string | स्थिर विज़िटर पहचानकर्ता |
linkedId | string | क्लाइंट द्वारा दिया गया लिंक किया हुआ पहचानकर्ता |
tag | string | क्लाइंट द्वारा दिया गया कस्टम tag |
timestamp | string | इवेंट का समय (RFC 3339) |
url | string | वह पेज URL जहाँ इवेंट कैप्चर हुआ |
ip | string | क्लाइंट IP पता |
userAgent | string | कच्चा क्लाइंट user-agent स्ट्रिंग |
browser.name / .version | string | पहचाना गया browser |
os.name / .version | string | पहचाना गया ऑपरेटिंग सिस्टम |
device | string | डिवाइस श्रेणी (जैसे desktop, mobile) |
geo | object | IP जियोलोकेशन: country, city, lat, lon, timezone, isp |
network | object | vpn, proxy, tor, datacenter (booleans) और connectionType |
bot.result | string | human, bot, या uncertain |
bot.type | string | बॉट का पता चलने पर मुक्त-रूप automation लेबल |
bot.score | number | बॉट संभावना स्कोर |
identification.confidence | number | मॉडल कॉन्फ़िडेंस (0.0–1.0) |
identification.incognito | boolean | निजी/incognito ब्राउज़िंग संदर्भ |
identification.visitType | string | विज़िट वर्गीकरण |
decision.action | string | अनुशंसित कार्रवाई |
decision.riskScore | number | समग्र जोखिम स्कोर (0–100) |
decision.suspectScore | number | सूक्ष्म-स्तरीय संदेह स्कोर |
phase दो डिलीवरी में अंतर करता है जो समान requestId साझा करती हैं:
primary — विज़िटर की पहचान होते ही तुरंत भेजी जाती है।late — एक अनुवर्ती संवर्धन इवेंट (एक परिष्कृत बॉट निर्णय और थोड़ा बाद में
कैप्चर किए गए व्यवहारिक संकेत)।दोनों को requestId द्वारा सहसंबद्ध करें और phase द्वारा उनमें अंतर करें।
हर डिलीवरी में एक X-Tracio-Signature हेडर शामिल होता है:
X-Tracio-Signature: t=1710432000,v1=5257a869e7ecebed...t वह Unix टाइमस्टैम्प (सेकंड) है जब अनुरोध पर हस्ताक्षर किए गए थे।v1 आपके webhook secret को key के रूप में उपयोग करते हुए "<t>.<rawRequestBody>" का
hex-एन्कोडेड HMAC-SHA256 है।टाइमस्टैम्प हस्ताक्षरित सामग्री का हिस्सा है, जो replay सुरक्षा देता है —
कच्चे अनुरोध body Buffer के विरुद्ध सत्यापन करें (पार्स किए गए/पुनः
सीरियलाइज़ किए गए JSON का उपयोग न करें, अन्यथा हस्ताक्षर मेल नहीं खाएगा)। हस्ताक्षरित
सामग्री को bytes के रूप में बनाएँ: "<t>." उपसर्ग को कच्चे body buffer के साथ जोड़ें,
फिर उस पर HMAC लगाएँ।
// Express.js exampleimport express from "express"import crypto from "crypto"
const app = express()
// Capture the raw body so we can verify the signature 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 { // Parse "t=...,v1=..." const parts = Object.fromEntries(header.split(",").map((kv) => kv.split("=") as [string, string])) const t = parts["t"] const v1 = parts["v1"] if (!t || !v1) return false
// Sign the raw bytes: "<t>." prefix + the raw request body buffer. const signed = Buffer.concat([Buffer.from(`${t}.`, "utf8"), rawBody]) const expected = crypto.createHmac("sha256", secret).update(signed).digest("hex")
const a = Buffer.from(v1, "hex") const b = Buffer.from(expected, "hex") return a.length === b.length && crypto.timingSafeEqual(a, b)}
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")})अतिरिक्त replay सुरक्षा के रूप में आप उन डिलीवरी को भी अस्वीकार करना चाह सकते हैं जिनका
t वर्तमान समय से बहुत दूर है (उदाहरण के लिए, पाँच मिनट से अधिक का अंतर)।
| हेडर | विवरण |
|---|---|
Content-Type | application/json |
X-Tracio-Signature | "<t>.<rawBody>" पर t=<unix>,v1=<hmac_sha256_hex> |
X-Tracio-Event-Id | इवेंट का requestId — इसे idempotency key के रूप में उपयोग करें |
X-Tracio-Webhook-Id | उस webhook का पहचानकर्ता जिसने यह डिलीवरी उत्पन्न की |
Webhooks को प्रबंधित करने का सबसे सरल तरीका दृश्य रूप से dashboard में है। इन्हें
workspace-स्कोप्ड management API के माध्यम से प्रोग्रामेटिक रूप से भी प्रबंधित किया जा
सकता है — वही API जिसका उपयोग dashboard करता है। यह एप्लिकेशन होस्ट पर सर्व की जाती है
(उदाहरण के लिए https://app.tracio.ai/api/v1) और आपके dashboard सत्र (Clerk) JWT
के साथ प्रमाणित होती है; हर अनुरोध की अतिरिक्त रूप से आपकी workspace भूमिका (RBAC) के
विरुद्ध जाँच की जाती है। कोई स्वतंत्र API secret नहीं है। सभी webhook endpoint
/workspaces/{workspaceId} के अंतर्गत रहते हैं।
curl -X POST https://app.tracio.ai/api/v1/workspaces/{workspaceId}/webhooks \ -H "Authorization: Bearer <clerk-session-jwt>" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-server.com/webhook/tracio", "events": [] }'Signing secret TRACIO द्वारा जनरेट किया जाता है और निर्माण पर (और rotate पर) एक बार
signingSecret के अंतर्गत लौटाया जाता है। इसे सुरक्षित रूप से संग्रहीत करें — यही वह key
है जिसका उपयोग आप हस्ताक्षरों को सत्यापित करने के लिए करते हैं।
{ "ok": true, "data": { "id": "wh_abc123", "workspaceEnvironmentId": "b201f2ba-…", "url": "https://your-server.com/webhook/tracio", "events": [], "signingSecret": "f3a9…<hex>", "status": "active", "successRate": 100, "createdAt": "2024-03-12T16:00:00Z" }}बाद के रीड में signingSecret मास्क किया हुआ (null) होता है — यह केवल निर्माण और
secret-rotate द्वारा प्रकट किया जाता है।
| मेथड | पथ | विवरण |
|---|---|---|
GET | /workspaces/{workspaceId}/webhooks | Webhooks की सूची बनाएँ |
PATCH | /workspaces/{workspaceId}/webhooks/{webhookId} | url / events / status अपडेट करें |
DELETE | /workspaces/{workspaceId}/webhooks/{webhookId} | एक webhook हटाएँ |
POST | /workspaces/{workspaceId}/webhooks/{webhookId}/test | एक हस्ताक्षरित परीक्षण डिलीवरी भेजें |
POST | /workspaces/{workspaceId}/webhooks/{webhookId}/secret/rotate | Signing secret को rotate करें |
GET | /workspaces/{workspaceId}/webhooks/{webhookId}/deliveries | हाल के डिलीवरी प्रयासों की सूची बनाएँ |
GET | /workspaces/{workspaceId}/webhooks/{webhookId}/deliveries | हाल के डिलीवरी प्रयासों की सूची बनाएँ |
डिलीवरी को पुनः प्रयास किया जा सकता है, इसलिए आपका handler idempotent होना चाहिए।
X-Tracio-Event-Id हेडर (जो requestId है) पर डीडुप्लिकेट करें:
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")})जितनी जल्दी हो सके 2xx प्रतिक्रिया लौटाएँ और timeout से बचने के लिए payload को
अतुल्यकालिक (asynchronous) रूप से प्रोसेस करें। गैर-2xx प्रतिक्रियाएँ (और कनेक्शन
त्रुटियाँ) पुनः प्रयास की जाती हैं; बार-बार विफलताएँ webhook को स्वतः निष्क्रिय कर सकती
हैं।
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) }}किसी webhook पर Test क्रिया (या POST .../webhooks/:webhookId/test) का उपयोग करके
अपने endpoint पर एक हस्ताक्षरित नमूना payload भेजें और पुष्टि करें कि वह पहुँच योग्य है
और हस्ताक्षरों को सही ढंग से सत्यापित कर रहा है।
स्थानीय विकास के लिए, अपने सर्वर को ngrok जैसे tunnel के साथ उजागर करें:
ngrok http 3000# Use the generated URL as your webhook endpoint