Server API дозволяє вашому бекенду читати дані ідентифікації, які TRACIO вже зібрав для вашого workspace: історію відвідувача, окремі сесії та лічильники активності за коротке вікно.
Він доповнює Webhooks, а не замінює їх:
| Webhooks | Server API | |
|---|---|---|
| Напрямок | TRACIO надсилає на вашу кінцеву точку | Ваш бекенд запитує сам, коли потрібно |
| Момент | У момент кожної ідентифікації | Будь-коли, у межах вашого вікна зберігання |
| Краще для | Реакції на подію | Пошуку даних у момент рішення, дозавантажень, розбору інцидентів |
Обидві поверхні доступні з тарифу Pro і вище.
https://api.tracio.ai/v1Це окремий хост — не той, що у браузерної кінцевої точки (edge.tracio.ai), і не
той, що у дашборда (app.tracio.ai). Усі три різні: браузер спілкується з edge вашим
публічним ключем, ваш бекенд спілкується з Server API вашим секретним ключем.
Кожен запит несе ваш секретний ключ як bearer-токен:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Server API працює лише в режимі server-to-server. Заголовки CORS навмисно не повертаються, тож браузер не може його викликати — саме це утримує ваш секретний ключ поза клієнтським кодом. Ніколи не віддавайте секретний ключ у браузер.
Створіть його в дашборді, у розділі API Keys, обравши тип secret.
tracio_sk_ плюс 43 символи, разом 53. Дашборд показує
його за першими кількома символами, щоб ви могли відрізняти ключі один від одного.Ротація випускає новий ключ і залишає старий робочим ще 7 днів, тож ви можете викотити заміну без простою. Задеплойте новий ключ, переконайтеся, що трафік перейшов на нього, і дайте старому спливти. Публічні ключі не ротуються — вони не є секретами й за задумом видимі у вихідному коді вашої сторінки.
Усі маршрути — 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 | Публічні ключі для підпису платформи у вебхуків (без автентифікації) |
Завершальна скісна риска приймається й ігнорується. Невідомий шлях або хибний метод повертають той самий 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, "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
дорівнює 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(`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 — ідентифікатором, який трапляється й у 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.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 — не ідентифікатор візиту. Ім’я ділять два різні значення:
всередині 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 днів |