Server API ให้แบ็กเอนด์ของคุณอ่านข้อมูลการระบุตัวตนที่ TRACIO เก็บไว้ให้ workspace ของคุณแล้ว ได้แก่ ประวัติของผู้เข้าชมรายหนึ่ง เซสชันแต่ละครั้ง และตัวนับ velocity ใน ช่วงเวลาสั้น ๆ
มันเสริม Webhooks มากกว่าจะมาแทนที่
| Webhooks | Server API | |
|---|---|---|
| ทิศทาง | TRACIO ส่งไปยังปลายทางของคุณ | แบ็กเอนด์ของคุณดึงเมื่อต้องการ |
| จังหวะเวลา | ทันทีที่การระบุตัวตนแต่ละครั้งเกิดขึ้น | เมื่อใดก็ได้ ภายในช่วงเวลาเก็บรักษาของคุณ |
| เหมาะกับ | การตอบสนองต่อเหตุการณ์ | การค้นข้อมูลระหว่างตัดสินใจ การเติมข้อมูลย้อนหลัง และการสืบสวน |
ทั้งสองพื้นผิวใช้ได้ตั้งแต่แพ็กเกจ Pro ขึ้นไป
https://api.tracio.ai/v1นี่คือโฮสต์คนละตัวกับปลายทางฝั่งเบราว์เซอร์ (edge.tracio.ai) และคนละตัวกับแดชบอร์ด
(app.tracio.ai) ทั้งสามแยกจากกัน เบราว์เซอร์คุยกับ edge ด้วยคีย์ public ของคุณ ส่วน
แบ็กเอนด์ของคุณคุยกับ Server API ด้วยคีย์ secret ของคุณ
ทุกคำขอต้องพา secret key ของคุณไปด้วยในรูปแบบ bearer token
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Server API ใช้ได้เฉพาะแบบเซิร์ฟเวอร์ถึงเซิร์ฟเวอร์ ระบบจงใจไม่คืนเฮดเดอร์ CORS เบราว์เซอร์จึงเรียกมันไม่ได้ — นั่นคือสิ่งที่กัน secret key ของคุณออกจากโค้ดฝั่งไคลเอนต์ อย่าส่ง secret key ไปยังเบราว์เซอร์เด็ดขาด
สร้างได้ในแดชบอร์ดที่ API Keys โดยเลือกชนิด secret
tracio_sk_ ตามด้วยอักขระอีก 43 ตัว รวมทั้งหมด 53 ตัว
แดชบอร์ดจะแสดงรายการด้วยอักขระไม่กี่ตัวแรก คุณจึงแยกแยะคีย์ออกจากกันได้การหมุนเวียนจะออกคีย์ใหม่และให้คีย์เดิมใช้ได้ต่ออีก 7 วัน คุณจึงทยอยนำคีย์ใหม่ออกใช้ ได้โดยไม่มีช่วงหยุดทำงาน ให้ดีพลอยคีย์ใหม่ ยืนยันว่าทราฟฟิกย้ายไปแล้ว แล้วปล่อยให้คีย์เดิม หมดอายุไป ส่วน public key หมุนเวียนไม่ได้ — มันไม่ใช่ความลับและถูกออกแบบให้มองเห็นได้ใน ซอร์สของหน้าเว็บคุณอยู่แล้ว
ทุกเส้นทางเป็น GET ไม่มีการดำเนินการเขียนใน Server API เลย มันอ่านข้อมูลอย่างเดียว ส่วน
การตั้งค่าของคุณอยู่ในแดชบอร์ด
| เมธอด | เส้นทาง | คืนค่าอะไร |
|---|---|---|
GET | /v1/visitors/{visitorId} | ประวัติรวมของผู้เข้าชมหนึ่งราย พร้อมเซสชันล่าสุดของเขา |
GET | /v1/visitors/{visitorId}/sessions | รายการเซสชันของผู้เข้าชมรายนั้นแบบแบ่งหน้า |
GET | /v1/visitors/{visitorId}/sessions/latest | เซสชันล่าสุดเพียงรายการเดียว |
GET | /v1/visitors/{visitorId}/velocity | ตัวนับกิจกรรมในช่วงเวลาสั้น ๆ |
GET | /v1/sessions/{requestId} | เซสชันหนึ่งรายการตามตัวระบุคำขอ |
GET | /.well-known/webhook-keys | คีย์สาธารณะสำหรับลายเซ็นของแพลตฟอร์ม webhook (ไม่ต้องยืนยันตัวตน) |
เครื่องหมายทับปิดท้ายเป็นที่ยอมรับและถูกละไว้ เส้นทางที่ไม่รู้จักหรือเมธอดที่ผิดจะคืนซอง ข้อผิดพลาด JSON แบบเดียวกับทุกกรณี ไม่เคยคืนเป็นหน้า HTML หรือข้อความล้วน
การอ่านทุกครั้งถูกจำกัดด้วยช่วงเวลา ซึ่งควบคุมด้วยพารามิเตอร์ query สองตัวที่ไม่บังคับ
| พารามิเตอร์ | รับค่า |
|---|---|
from | YYYY-MM-DD หรือ timestamp RFC 3339 เต็ม |
to | YYYY-MM-DD หรือ timestamp RFC 3339 เต็ม |
to จะรวมทั้งวันนั้นเข้ามาด้วย400 invalid_request พร้อมข้อความ
time must be YYYY-MM-DD or RFC3339meta เสมอ ให้ตรวจ meta.from และ
meta.to แทนที่จะสันนิษฐานว่าคำขอของคุณถูกใช้ตามตัวอักษรcurl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"การตอบกลับพาประวัติรวมมาให้และฝังเซสชันล่าสุดมาด้วย กรณีทั่วไปจึงใช้คำขอเดียวแทนที่จะ ต้องใช้สองคำขอ
{ "visitorId": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "firstSeenAt": "2026-05-02T10:11:12Z", "lastSeenAt": "2026-07-25T08:00:00Z", "visits": 42, "incognitoVisits": 3, "uniqueIps": 5, "uniqueCountries": 2, "browsers": ["Chrome"], "os": ["macOS"], "devices": ["desktop"], "risk": { "maxRiskScore": 63, "avgBotScore": 12.5, "botSessions": 7, "lastDecision": "real" }, "network": { "vpnSeen": false, "proxySeen": false, "torSeen": false, "datacenterSeen": true, "lastIsp": "Deutsche Telekom" }, "lastSession": { "requestId": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31", "visitorId": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "accountId": "user_8842", "timestamp": "2026-07-25T08:00:00Z", "tag": "checkout", "url": "https://shop.example.com/checkout", "ip": "203.0.113.42", "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", "browser": { "name": "Chrome", "version": "126.0" }, "os": { "name": "macOS", "version": "14.5" }, "device": "desktop", "geo": { "country": "DE", "city": "Berlin", "timezone": "Europe/Berlin", "isp": "Deutsche Telekom" }, "network": { "vpn": false, "proxy": false, "tor": false, "datacenter": false, "asn": 3320 }, "bot": { "result": "human", "score": 4.5, "antidetectScore": 2.1 }, "identification": { "confidence": 0.97, "incognito": false, "matchType": "exact", "matchConfidence": 0.99 }, "decision": { "action": "real", "riskScore": 12 } }, "meta": { "plan": "business", "retentionDays": 90, "from": "2026-04-26T00:00:00Z", "to": "2026-07-25T12:00:00Z" }}| ฟิลด์ | ความหมาย |
|---|---|
visits, incognitoVisits | จำนวนการเข้าชมทั้งหมดในช่วงเวลานั้น และมีกี่ครั้งที่อยู่ในหน้าต่างส่วนตัว |
uniqueIps, uniqueCountries | จำนวนที่อยู่และประเทศที่ต่างกันซึ่งพบในช่วงเวลานั้น |
browsers, os, devices | สภาพแวดล้อมที่ต่างกันซึ่งผู้เข้าชมรายนี้เคยปรากฏตัว |
risk.maxRiskScore | คะแนนความเสี่ยงสูงสุดที่บันทึกไว้ในช่วงเวลานั้น 0..100 |
risk.lastDecision | คำตัดสินที่บันทึกไว้สำหรับการเข้าชมล่าสุด |
risk.avgBotScore, risk.botSessions | ค่าเฉลี่ยคะแนนบอตและจำนวนเซสชันที่เป็นบอต — Business ขึ้นไป |
network.*Seen | เคยพบ VPN, พร็อกซี, โหนดทางออก Tor หรือที่อยู่ดาต้าเซ็นเตอร์กับผู้เข้าชมรายนี้หรือไม่ |
network.lastIsp | ISP ล่าสุด — Business ขึ้นไป |
lastSession | อ็อบเจ็กต์เซสชันเต็มรูปแบบของการเข้าชมล่าสุด |
meta | แพ็กเกจ ระยะเวลาเก็บรักษาเป็นวัน และช่วงเวลาที่ใช้จริง |
ผู้เข้าชมที่ไม่มีข้อมูลอยู่ในช่วงเวลาเก็บรักษาจะคืน 404 not_found พร้อมข้อความ
visitor not found in the retention window — นั่นไม่ใช่ข้อผิดพลาดในการผสานรวมของคุณ
แต่หมายความว่าผู้เข้าชมรายนั้นเป็นรายใหม่หรือข้อมูลหมดอายุไปแล้ว
เซสชันพาคำตัดสินมาสองชุด และทั้งสองตอบคำถามคนละข้อ — ไคลเอนต์เป็นระบบอัตโนมัติหรือไม่ และเครื่องประเมินความเสี่ยงสรุปโดยรวมว่าอย่างไร
| ฟิลด์ | ค่า |
|---|---|
bot.result | human, bot, uncertain |
decision.action | real, fake, suspicious |
ทั้ง bot.score และ decision.riskScore อยู่บนสเกล 0..100 ตั้งแต่ Business ขึ้นไป
guidance จะแปลงค่าเหล่านี้เป็นคำแนะนำรายสถานการณ์บนบันได
allow → challenge → review → deny — ดูความหมายของแต่ละขั้นได้ที่
Guidance
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions?limit=100&minRiskScore=50"| พารามิเตอร์ | ค่าเริ่มต้น | หมายเหตุ |
|---|---|---|
limit | 50 | จำกัดที่ 500 ค่าที่ใหญ่กว่าจะถูกตัดลง ไม่ใช่ถูกปฏิเสธ |
from, to | ระยะเวลาเก็บรักษาแพ็กเกจ | ช่วงเวลาร่วมที่อธิบายไว้ข้างต้น |
cursor | — | เคอร์เซอร์แบ่งหน้าแบบทึบจากหน้าก่อนหน้า |
botResult | — | เก็บเฉพาะเซสชันที่มีคำตัดสินบอตนี้ |
minRiskScore | — | เก็บเฉพาะเซสชันที่มีคะแนนความเสี่ยงเท่านี้ขึ้นไป 0..100 |
เซสชันจะกลับมาโดยเรียงจากใหม่สุดก่อน
{ "items": [ { "requestId": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31", "visitorId": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "timestamp": "2026-07-25T08:00:00Z" } ], "nextCursor": "MTcyMTg5NDQwMDAwMDphYmMxMjM", "hasMore": true, "meta": { "plan": "business", "retentionDays": 90, "from": "2026-04-26T00:00:00Z", "to": "2026-07-25T12:00:00Z" }}การแบ่งหน้าอิงเคอร์เซอร์ ไม่มีพารามิเตอร์ page หรือ offset ให้ส่ง nextCursor ที่
คุณได้รับกลับไปเป็น cursor แล้ววนต่อไปตราบใดที่ hasMore ยังเป็นจริง
async function allSessions(visitorId: string, secretKey: string) { const sessions = [] let cursor: string | undefined
do { const url = new URL(`https://api.tracio.ai/v1/visitors/${visitorId}/sessions`) url.searchParams.set("limit", "500") if (cursor) url.searchParams.set("cursor", cursor)
const res = await fetch(url, { headers: { Authorization: `Bearer ${secretKey}` } }) if (!res.ok) throw new Error(`Server API: ${res.status}`)
const page = await res.json() sessions.push(...page.items) cursor = page.nextCursor } while (cursor)
return sessions}ให้ถือว่าเคอร์เซอร์เป็นค่าทึบ — เนื้อในของมันเป็นรายละเอียดการพัฒนาและอาจเปลี่ยนแปลงได้
เคอร์เซอร์ที่ถูกแก้ไขจะถูกปฏิเสธด้วย 400 invalid_request พร้อมข้อความ malformed cursor
รายการล่าสุด
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions/latest"คำขอนี้คืนอ็อบเจ็กต์เซสชันเปล่า ๆ ไม่ใช่อาร์เรย์ และไม่ได้ห่อไว้ในซองใด ๆ ผู้เข้าชมที่ไม่มี
เซสชันในช่วงเวลานั้นจะคืน 404 not_found พร้อม
no sessions for this visitor in the retention window
หรือค้นด้วย requestId ซึ่งเป็นตัวระบุที่ปรากฏในเพย์โหลดของ webhook ด้วย
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/sessions/9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31?visitorId=X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"ตรงนี้ visitorId ไม่บังคับ แต่การส่งไปด้วยเมื่อคุณรู้ค่าจะทำให้การค้นหาเร็วขึ้นอย่าง
เห็นได้ชัด
Velocity ตอบคำถามว่า "ช่วงหลังนี้ผู้เข้าชมรายนี้ทำอะไรไปมากแค่ไหน" ซึ่งเป็นรูปแบบของการ ยิงชุดข้อมูลรับรอง การทดสอบบัตร และการสมัครสมาชิกจำนวนมาก
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/velocity?window=1h"window รับค่า 1h, 24h หรือ 7d และมีค่าเริ่มต้นเป็น 24h ค่าอื่นใดจะถูกปฏิเสธด้วย
400 invalid_request พร้อม window must be one of: 1h, 24h, 7d
{ "window": "1h", "events": 37, "uniqueIps": 9, "uniqueCountries": 3, "uniqueAccounts": 12, "botEvents": 4, "meta": { "plan": "business", "retentionDays": 90, "from": "2026-07-25T11:00:00Z", "to": "2026-07-25T12:00:00Z" }}uniqueAccounts นับจำนวนค่า linkedId ที่ต่างกันซึ่งคุณส่งมาให้อุปกรณ์เครื่องนี้ — ดู
การเชื่อมโยงบัญชี ส่วน botEvents มีตั้งแต่ Business ขึ้นไป
ฟิลด์ที่หายไปหมายถึง "ไม่มีข้อมูล" ไม่ใช่ศูนย์ ฟิลด์ที่ไม่มีค่าจะถูกตัดออกทั้งหมด
แทนที่จะส่งมาเป็น 0, "" หรือ null ผู้เข้าชมที่เพิ่งมาใหม่เอี่ยมย่อมไม่มี
matchConfidence การเข้าชมที่สะอาดย่อมไม่มี antidetectScore หรือ suspectScore
ข้อยกเว้นเดียวที่จงใจไว้คือ bot.score ซึ่งมีอยู่เสมอแม้ค่าจะเป็นศูนย์ ให้อ่านฟิลด์อย่าง
ระมัดระวัง
เพย์โหลดขึ้นอยู่กับแพ็กเกจของคุณ ทุกแพ็กเกจที่เข้าถึง API ได้จะได้เซสชันพื้นฐาน คือ
ตัวระบุ timestamp URL IP user agent เบราว์เซอร์ OS อุปกรณ์ geo network bot
identification และ decision แพ็กเกจ Pro เพิ่ม identification.matchType,
identification.matchConfidence และ bot.antidetectScore ส่วน Business และ Enterprise
เพิ่ม geo.isp, network.asn, decision.suspectScore, identification.driftScore,
reasons, behavior, guidance, deviceInfo และฟิลด์ระดับบุคคล (personId,
reputation, linkedAccountsCount, linkedVisitorsCount) การที่ฟิลด์ของ Business ไม่
ปรากฏบนแพ็กเกจ Pro ไม่ใช่ข้อผิดพลาด
รายละเอียดภายในระดับสัญญาณจะไม่ถูกคืนกลับมาเลย ไม่ว่าจะแพ็กเกจใด ทั้งชื่อสัญญาณแต่ละ ตัว น้ำหนักของมัน เกณฑ์ที่อยู่เบื้องหลังคำตัดสิน ค่าดิบของสัญญาณ และการแจกแจงคะแนน ล้วน อยู่ฝั่งเราเท่านั้น คะแนนที่ถูกย้อนรอยกลับไปเป็นข้อมูลนำเข้าได้ ย่อมหมดประโยชน์ในฐานะ เครื่องป้องกัน
ความล้มเหลวทุกกรณีใช้ซองเดียวกัน
{ "error": { "code": "unauthorized", "message": "missing Authorization: Bearer <secret key>", "requestId": "8f14e45fceea167a5a36dedd" }}requestId ตัวนี้ไม่ใช่ตัวระบุการเข้าชม มีสองค่าที่ต่างกันแต่ใช้ชื่อเดียวกัน ภายใน
เพย์โหลดของเซสชัน requestId คือ UUID ของการเข้าชม ค่าเดียวกับที่ webhook ส่งมา ส่วน
ภายในซองข้อผิดพลาด มันคือตัวระบุการติดตามความยาว 24 อักขระที่สร้างขึ้นต่อหนึ่งการเรียก
HTTP ตัวระบุการติดตามนี้ยังกลับมาในเฮดเดอร์ X-Request-Id ของทุกการตอบกลับ ไม่ว่าจะสำเร็จ
หรือไม่ก็ตาม ให้แนบค่านี้มาด้วยเมื่อติดต่อฝ่ายสนับสนุน — เราใช้มันหาการเรียกของคุณได้ตรงตัว
| HTTP | code | ความหมาย |
|---|---|---|
| 400 | invalid_request | พารามิเตอร์ขาดหายหรือรูปแบบไม่ถูกต้อง |
| 401 | unauthorized | คีย์ไม่มี ไม่ถูกต้อง ถูกเพิกถอน หรือหมดอายุ |
| 402 | upgrade_required | แพ็กเกจของคุณไม่รวมสิทธิ์เข้าถึง API |
| 404 | not_found | ไม่มีอะไรตรงกันภายในช่วงเวลาเก็บรักษา |
| 405 | method_not_allowed | เส้นทางมีอยู่จริง แต่ไม่รองรับเมธอดนั้น |
| 429 | rate_limited | เกินจำนวนคำขอต่อวินาที หรือเกินโควตารายวัน |
| 500 | internal | มีบางอย่างล้มเหลวฝั่งเรา |
| 503 | unavailable | ที่เก็บข้อมูลเบื้องหลังเข้าถึงไม่ได้ชั่วคราว |
การตรวจสอบทำงานตามลำดับที่ตายตัว — คีย์ก่อน แล้วแพ็กเกจ แล้วจึงขีดจำกัด คำขอที่ใช้คีย์ผิด จึงรายงานเรื่องคีย์ก่อนเสมอ ไม่เคยรายงานเป็นปัญหาโควตา
401 สองกรณีอ่านต่างกันโดยตั้งใจ missing Authorization: Bearer <secret key> หมายความว่า
เฮดเดอร์ไม่เคยมาถึง ส่วน invalid or revoked API key หมายความว่ามันมาถึงแล้วแต่ไม่ตรงกัน
ส่วน 402 พา Data API requires the Pro plan or higher มาด้วย
การตอบกลับที่ผ่านการยืนยันตัวตนทุกครั้งจะพาสถานะปัจจุบันของคุณมาด้วย
| เฮดเดอร์ | ความหมาย |
|---|---|
X-RateLimit-Limit | โควตารายวันของคุณ |
X-RateLimit-Remaining | จำนวนการเรียกที่เหลือของวันนี้ |
X-RateLimit-Reset | เวลา Unix ที่จะรีเซ็ต — เที่ยงคืน UTC |
Retry-After | จำนวนวินาทีที่ต้องรอ ส่งมาเฉพาะกับ 429 |
| แพ็กเกจ | คำขอต่อวินาที | คำขอต่อวัน | ความลึกของประวัติ |
|---|---|---|---|
| Free | ไม่มีสิทธิ์เข้าถึง API | — | 7 วัน |
| Pro | 10 | 10,000 | 30 วัน |
| Business | 50 | 100,000 | 90 วัน |
| Enterprise | 200 | ไม่มีการนับโควตา | 365 วัน |