Data API (раніше описаний тут як Server API) дозволяє вашому бекенду читати дані ідентифікації, які TRACIO вже зібрав для вашого workspace: історію відвідувача, окремі сесії та лічильники активності за коротке вікно.
Він доповнює Webhooks, а не замінює їх:
| Webhooks | Data API | |
|---|---|---|
| Напрямок | TRACIO надсилає на вашу кінцеву точку | Ваш бекенд запитує сам, коли потрібно |
| Момент | У момент кожної ідентифікації | Будь-коли, у межах вашого вікна зберігання |
| Краще для | Реакції на подію | Пошуку даних у момент рішення, дозавантажень, розбору інцидентів |
Обидві поверхні доступні з тарифу Pro і вище.
https://api.tracio.ai/v1Це окремий хост — не той, що у браузерної кінцевої точки (edge.tracio.ai), і не
той, що у дашборда (app.tracio.ai). Усі три різні: браузер спілкується з edge вашим
публічним ключем, ваш бекенд спілкується з Data API вашим секретним ключем.
Кожен запит несе ваш секретний ключ як bearer-токен:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Data API працює лише в режимі server-to-server. Заголовки CORS навмисно не повертаються, тож браузер не може його викликати — саме це утримує ваш секретний ключ поза клієнтським кодом. Ніколи не віддавайте секретний ключ у браузер.
Створіть його в дашборді, у розділі API Keys, обравши тип secret.
tracio_sk_ плюс 43 символи, разом 53. Дашборд показує
його за першими кількома символами, щоб ви могли відрізняти ключі один від одного.Ротація випускає новий ключ і залишає старий робочим ще 7 днів, тож ви можете викотити заміну без простою. Задеплойте новий ключ, переконайтеся, що трафік перейшов на нього, і дайте старому спливти. Публічні ключі не ротуються — вони не є секретами й за задумом видимі у вихідному коді вашої сторінки.
Усі маршрути — GET. Операцій запису в Data 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 | Публічні ключі для підпису платформи у вебхуків (без автентифікації) |
Завершальна скісна риска приймається й ігнорується. Невідомий шлях або хибний метод повертають той самий JSON-конверт помилки, що й усе інше, — ніколи не HTML- і не текстову сторінку.
Будь-яке читання обмежене часовим вікном, яким керують два необов’язкові параметри запиту:
| Параметр | Приймає |
|---|---|
from | YYYY-MM-DD або повний таймстамп RFC 3339 |
to | YYYY-MM-DD або повний таймстамп RFC 3339 |
to включає весь цей день цілком.400 invalid_request і повідомленням
time must be YYYY-MM-DD or RFC3339.meta, тож
перевіряйте 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, "proxyDetectedSeen": true, "lastIsp": "Deutsche Telekom", "lastRealIp": "203.0.113.7" }, "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", "gpu": "Apple M2", "geo": { "country": "DE", "city": "Berlin", "timezone": "Europe/Berlin", "isp": "Deutsche Telekom" }, "network": { "vpn": false, "proxy": false, "tor": false, "datacenter": false, "proxyDetected": true, "realIp": { "address": "203.0.113.7", "country": "NL", "isp": "KPN" }, "asn": 3320 }, "screen": { "width": 2560, "height": 1600, "colorDepth": 30, "pixelRatio": 2 }, "locale": { "languages": ["en-US", "de"], "timezone": "Europe/Berlin" }, "clientHints": { "architecture": "arm", "bitness": "64", "platformVersion": "14.5.0" }, "extensions": [ { "slug": "ublock-origin", "name": "uBlock Origin", "category": "adblock", "risky": false, "storeUrl": "https://chromewebstore.google.com/detail/cjpalhdlnbpafiamejdnhcphjbkeiagm" } ], "bot": { "result": "human", "score": 4.5, "antidetectScore": 2.1 }, "identification": { "confidence": 0.97, "incognito": false, "matchType": "exact", "matchConfidence": 0.99 }, "deviceInfo": { "deviceId": "d_4f9c2e", "crossBrowser": true, "confidence": 0.88, "linkedBrowsers": 2 }, "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.proxyDetectedSeen | Чи виходив хоча б один візит у вікні через проксі або VPN перед браузером — див. network.proxyDetected у розділі «Факти про пристрій» |
network.lastIsp | Найсвіжіший ISP — Business і вище |
network.lastRealIp | Найсвіжіша адреса, яку спостерігали за проксі або VPN, — Business і вище; відсутня, коли такої адреси не спостерігали |
lastSession | Повний об’єкт сесії для найсвіжішого візиту |
meta | Тариф, його строк зберігання у днях і фактично застосоване вікно |
Відвідувач, щодо якого немає даних усередині вікна зберігання, віддає 404 not_found
з повідомленням visitor not found in the retention window — це не помилка вашої
інтеграції, а ознака того, що відвідувач новий або вже вийшов за строк зберігання.
Сесія несе два вердикти, і вони відповідають на різні питання — чи був клієнт автоматизованим і до якого загального висновку дійшов рушій ризику:
| Поле | Значення |
|---|---|
bot.result | human, bot, uncertain |
bot.type | Присутнє, коли bot.result дорівнює bot: або конкретний інструмент (playwright, puppeteer, selenium, jsdom, claude_computer_use…), або сімейство, коли інструмент не названо, — automation, headless, antidetect, extension, privacy_browser, other |
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
дорівнює true.
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(`Data API: ${res.status}`)
const page = await res.json() sessions.push(...page.items) cursor = page.nextCursor } while (cursor)
return sessions}Вважайте курсор непрозорим — його вміст є деталлю реалізації і може змінитися.
Відредагований курсор відхиляється з 400 invalid_request і повідомленням
malformed cursor.
Окрім браузера та ОС, узятих із User-Agent, сесія несе те, що браузер відвідувача повідомляє про машину, очищене на нашому боці. Кожне поле відсутнє, коли візит таких даних не приніс, тож вважайте будь-яке з них необов'язковим.
| Поле | Значення |
|---|---|
gpu | Модель відеоадаптера, як її повідомляє браузер (WebGL), нормалізована до читабельного імені — Intel Iris Xe Graphics, Apple M1 Pro, Qualcomm Adreno 830; Software renderer означає, що справжнього GPU немає (віртуальна машина або headless-середовище); Safari повідомляє Apple GPU |
network.proxyDetected | HTTP-трафік візиту та його сирі мережеві шляхи виходять через різні мережі — перед браузером стоїть проксі або VPN; дві адреси того самого провайдера (NAT оператора, другий вихід того самого VPN) не рахуються |
network.realIp.address, .country, .isp | Публічна адреса, яку спостерігали на сирому мережевому шляху, тобто адреса за проксі або VPN, разом із її країною та ISP — Business і вище; відсутня, коли такої адреси не спостерігали (country та isp відсутні, коли їх не вдалося визначити) |
deviceInfo.deviceId, .crossBrowser, .confidence, .linkedBrowsers | Присутнє, коли ідентичність пристрою вдалося визначити: стабільний ідентифікатор фізичного пристрою, спільний для браузерів на ньому, чи прийшов цей візит через інший браузер, ніж раніше, впевненість цього збігу та скільки різних відвідувачів (браузерів) ділять пристрій — більше одиниці означає одну машину під кількома браузерними ідентичностями — Business і вище |
osEnvironment | Середовище робочого столу, виміряне на машині з Linux (Mint 22+, Ubuntu, GNOME, KDE) — Business і вище; відсутнє, коли не визначене |
spoofing | Що візит заявив проти того, що виміряли незалежні перевірки (claimed, real, spoofedAxes із os, gpu, screen, network, browser; anonymousBrowser з назвами продуктів) — Business і вище; присутнє лише тоді, коли підміну виявлено |
screen.width, .height, .colorDepth, .pixelRatio | Роздільна здатність екрана, глибина кольору та device pixel ratio, як їх повідомляє браузер — Business і вище |
locale.languages, locale.timezone | Власні бажані мови браузера та його часовий пояс — на відміну від geo.timezone, який виводиться з IP-адреси; розбіжність між ними — часта ознака підміненого розташування — Business і вище |
clientHints.architecture, .bitness, .model, .deviceName, .platformVersion | User-Agent Client Hints: архітектура та розрядність процесора, код моделі пристрою (Android, наприклад SM-A556B) разом із її маркетинговою назвою зі списку пристроїв Google Play (deviceName, наприклад Samsung Galaxy A55 5G) і точна версія платформи; лише браузери на Chromium — Business і вище |
environment.virtualMachine, environment.hypervisor | Присутнє лише тоді, коли відеоадаптер сам відрекомендувався віртуальним; hypervisor — закритий словник (vmware, virtualbox, parallels, qemu, hyperv, bochs, intel-gvt, vgpu). Відсутність блока означає, що таких свідчень немає — Business і вище |
extensions перелічує розширення браузера, виявлені під час візиту, — Business і вище. Кожен елемент — об’єкт:
| Поле | Значення |
|---|---|
slug | Стабільний машинний ідентифікатор розширення, те саме значення, яке доставляє вебхук |
name | Зрозуміла людині назва |
category | Укрупнений клас — adblock, privacy, automation, wallet, vpn, devtools, other і так далі |
risky | true для розширень, пов’язаних з автоматизацією, підміною або крадіжкою облікових даних |
storeUrl | Посилання на картку розширення в магазині, коли воно відоме |
Знахідка повідомляється лише після того, як пройшла наші перевірки довіри, — середовище, яке відповідає «встановлено» на будь-яку пробу, або партія довша за дванадцять імен відбраковуються як ненадійні. Тому порожній або відсутній список означає «нічого, що ми змогли підтвердити», а не «розширень не встановлено». Читайте його як свідчення, а не як інвентарний перелік.
Найсвіжіша:
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 — ідентифікатором, який трапляється й у payload вебхука:
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: воно присутнє завжди, навіть коли дорівнює нулю.
Читайте поля захисно.
Payload залежить від вашого тарифу. Будь-який тариф із доступом до API отримує базову сесію — ідентифікатори, таймстамп, URL, IP, user agent, браузер, ОС, пристрій, гео, мережа, бот, ідентифікація та рішення. Pro додає identification.matchType, identification.matchConfidence, bot.type, bot.antidetectScore, gpu і network.proxyDetected. Business та Enterprise додають extensions, geo.isp, network.asn, network.realIp, decision.suspectScore, identification.driftScore, reasons, behavior, guidance, deviceInfo, spoofing, osEnvironment, screen, locale, clientHints та environment. Поля рівня персони (personId, reputation, linkedAccountsCount, linkedVisitorsCount) зарезервовані за Business та Enterprise і з’являться, коли буде увімкнено шар персон, — сьогодні він працює в режимі спостереження, і ці поля не віддаються. Відсутність поля рівня Business на тарифі Pro — не помилка.
Внутрішнє на рівні сигналів не повертається ніколи, на жодному тарифі: імена окремих сигналів, їхні ваги, пороги за вердиктом, сирі значення сигналів і розкладка оцінок залишаються на нашому боці. Оцінка, яку можна зворотною розробкою звести до її вхідних даних, перестає бути захистом.
Будь-який збій використовує один конверт:
{ "error": { "code": "unauthorized", "message": "missing Authorization: Bearer <secret key>", "requestId": "8f14e45fceea167a5a36dedd" }}Цей requestId — не ідентифікатор візиту. Ім’я ділять два різні значення:
всередині payload сесії requestId — це UUID візиту, той самий, який доставляє
вебхук; у конверті помилки це 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 | Сховище за API тимчасово недоступне |
Перевірки йдуть у фіксованому порядку — ключ, потім тариф, потім ліміти, — тож запит із поганим ключем завжди повідомляє спершу про ключ, а не про проблему з квотою.
Два випадки 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 днів |