Data API (documentat aici anterior drept Server API) permite backend-ului tău să citească datele de identificare pe care TRACIO le-a colectat deja pentru workspace-ul tău: istoricul unui vizitator, sesiunile individuale și contoarele de velocity pe ferestre scurte. Câteva rute și scriu — înregistrări de cont, câmpuri personalizate și intrări în liste — pentru ca backend-ul tău să poată îmbogăți ceea ce știe TRACIO.
Completează Webhooks, fără să le înlocuiască:
| Webhooks | Data API | |
|---|---|---|
| Direcție | TRACIO trimite către endpoint-ul tău | Backend-ul tău interoghează la cerere |
| Moment | Pe măsură ce se produce fiecare identificare | Oricând, în cadrul ferestrei tale de retenție |
| Potrivit pentru | Reacția la un eveniment | Consultarea datelor în timpul unei decizii, backfill-uri, investigații |
Ambele suprafețe sunt disponibile începând cu planul Pro.
https://api.tracio.ai/v2Acesta este un host diferit de endpoint-ul din browser (edge.tracio.ai) și de
dashboard (app.tracio.ai). Toate trei sunt separate: browserul vorbește cu edge-ul
folosind cheia ta publică, iar backend-ul tău vorbește cu
Data API folosind cheia secretă.
Rutele /v1 au fost eliminate. Folosește /v2: rutele sunt aceleași, iar fiecare cheie
JSON și fiecare parametru de query sunt în snake_case (visitor_id, risk_score,
min_risk_score). Cheile din propriile tale dicționare fields și labels
sunt datele tale și își păstrează scrierea originală. SDK-ul JavaScript își
păstrează interfața în camelCase.
Fiecare cerere poartă cheia ta secretă ca bearer token:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Data API este exclusiv server-to-server. Antetele CORS nu sunt returnate în mod deliberat, așa că un browser nu o poate apela — tocmai asta ține cheia ta secretă în afara codului de pe client. Nu trimite niciodată cheia secretă în browser.
Creeaz-o în dashboard, la API Keys, alegând tipul secret.
tracio_sk_ urmat de 43 de caractere, 53 în total.
Dashboard-ul o listează după primele câteva caractere, ca să poți deosebi cheile
între ele.404, exact ca pentru datele care nu există.Rotirea emite o cheie nouă și o menține pe cea veche funcțională timp de 7 zile, ca să o poți desfășura fără întreruperi. Desfășoară cheia nouă, confirmă că traficul s-a mutat și las-o pe cea veche să expire. Cheile publice nu se pot roti — nu sunt secrete și sunt vizibile prin design în sursa paginii tale.
| Metodă | Cale | Returnează |
|---|---|---|
GET | /v2/visitors/{visitor_id} | Istoric agregat pentru un vizitator, plus ultima lui sesiune |
GET | /v2/visitors/{visitor_id}/sessions | Listă paginată a sesiunilor acelui vizitator |
GET | /v2/visitors/{visitor_id}/sessions/latest | Singura cea mai recentă sesiune |
GET | /v2/visitors/{visitor_id}/velocity | Contoare de activitate pe o fereastră scurtă |
GET | /v2/sessions/{request_id} | O sesiune, după identificatorul cererii ei |
POST | /v2/accounts/metadata | Atașează nume afișate și adrese de e-mail ID-urilor tale de cont |
POST | /v2/events/fields | Atașează câmpuri personalizate unei vizite după încărcarea paginii |
POST | /v2/events/fields/delete | Șterge câmpurile personalizate ale unei vizite — vizita însăși nu este atinsă |
GET | /v2/lists | Listele workspace-ului: id, nume, tip (acțiunea), mod, număr de intrări |
POST | /v2/lists/{list_id}/entries | Adaugă o valoare într-o listă, opțional cu un TTL |
POST | /v2/lists/{list_id}/entries/delete | Elimină o valoare dintr-o listă |
GET | /.well-known/webhook-keys | Chei publice pentru semnătura de platformă a webhook-urilor (fără autentificare) |
Aceeași cheie și același host servesc și API-urile de decizie, toate în snake_case:
| Metodă | Cale | Scop |
|---|---|---|
POST | /v2/transactions | O decizie sincronă APPROVE / REVIEW / DECLINE asupra unui eveniment de business — Business și peste, cu excepția unei conversii de afiliat (account_register sau deposit cu affiliate_id), disponibilă în orice plan cu acces la API |
GET | /v2/transactions/{transaction_id} | Recitirea unei decizii, cu eticheta și starea ei efectivă — Business și peste, cu excepția unei tranzacții atribuite unui afiliat |
PUT, DELETE | /v2/transaction-labels | Setarea sau eliminarea etichetei de rezultat pentru până la 50 de tranzacții — Business și peste |
GET | /v2/transaction-labels/value-set | Valorile de etichetă acceptate, cu polaritatea lor — Business și peste |
POST | /v2/logins/assess | Evaluarea unei autentificări: allow / challenge / review / deny, cu motive |
POST, GET | /v2/accounts/{user_id}/trusted-devices | Marcarea ca de încredere a dispozitivului unei vizite pentru un cont, după step-up-ul tău, sau listarea dispozitivelor de încredere ale contului |
DELETE | /v2/accounts/{user_id}/trusted-devices/{device_ref} | Revocarea încrederii într-un dispozitiv |
GET | /v2/affiliates/{affiliate_id} | Raportul de calitate al unui afiliat pe 90 de zile, cu o recomandare hold / review |
POST, GET | /v2/self-exclusions | Setarea sau prelungirea unei autoexcluderi pentru un cont, sau listarea lor |
DELETE | /v2/self-exclusions/{user_id} | Ridicarea anticipată a unei autoexcluderi |
Rezultatele lor ajung la tine și ca evenimente webhook:
transaction_state_changed, login_risk, trusted_device_enrolled,
trusted_device_revoked și affiliate_threshold_crossed.
O bară finală este acceptată și ignorată. O cale necunoscută sau o metodă greșită returnează același plic JSON de eroare ca tot restul, niciodată o pagină HTML sau de text simplu.
Fiecare citire este delimitată de o fereastră temporală, controlată prin doi parametri de query opționali:
| Parametru | Acceptă |
|---|---|
from | YYYY-MM-DD sau un timestamp RFC 3339 complet |
to | YYYY-MM-DD sau un timestamp RFC 3339 complet |
to include întreaga zi respectivă.400 invalid_request și mesajul
time must be YYYY-MM-DD or RFC3339.meta, așa că verifică meta.from și meta.to în loc să
presupui că cererea ta a fost onorată întocmai.curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Răspunsul poartă istoricul agregat și include ultima sesiune, așa că în cazul obișnuit este nevoie de o singură cerere, nu de două:
{ "visitor_id": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "first_seen_at": "2026-05-02T10:11:12Z", "last_seen_at": "2026-07-25T08:00:00Z", "visits": 42, "incognito_visits": 3, "unique_ips": 5, "unique_countries": 2, "browsers": ["Chrome"], "os": ["macOS"], "devices": ["desktop"], "risk": { "max_risk_score": 63, "avg_bot_score": 12.5, "bot_sessions": 7, "last_decision": "real" }, "network": { "vpn_seen": false, "proxy_seen": false, "tor_seen": false, "datacenter_seen": true, "proxy_detected_seen": true, "last_isp": "Deutsche Telekom", "last_real_ip": { "address": "203.0.113.7", "country": "NL", "isp": "KPN" } }, "last_session": { "request_id": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31", "visitor_id": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "account_id": "user_8842", "account": { "id": "user_8842", "email": "ann@example.com", "display_name": "Ann Lee" }, "timestamp": "2026-07-25T08:00:00Z", "tag": "checkout", "fields": { "order_ref": "A-1029" }, "url": "https://shop.example.com/checkout", "ip": "203.0.113.42", "user_agent": "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, "connection_type": "residential", "proxy_detected": true, "real_ip": { "address": "203.0.113.7", "country": "NL", "isp": "KPN" }, "asn": 3320 }, "screen": { "width": 2560, "height": 1600, "color_depth": 30, "pixel_ratio": 2 }, "locale": { "languages": ["en-US", "de"], "timezone": "Europe/Berlin" }, "client_hints": { "architecture": "arm", "bitness": "64", "platform_version": "14.5.0" }, "extensions": [ { "slug": "ublock-origin", "name": "uBlock Origin", "category": "adblock", "risky": false, "store_url": "https://chromewebstore.google.com/detail/cjpalhdlnbpafiamejdnhcphjbkeiagm" } ], "bot": { "result": "human", "score": 4.5, "antidetect_score": 2.1 }, "identification": { "confidence": 0.97, "incognito": false, "match_type": "exact", "match_confidence": 0.99 }, "device_info": { "device_id": "d_4f9c2e", "cross_browser": true, "confidence": 0.88, "linked_browsers": 2 }, "decision": { "action": "real", "risk_score": 12, "suspect_score": 3 } }, "meta": { "plan": "business", "retention_days": 90, "from": "2026-04-26T00:00:00Z", "to": "2026-07-25T12:00:00Z" }}| Câmp | Semnificație |
|---|---|
visits, incognito_visits | Vizite totale în fereastră și câte dintre ele au fost într-o fereastră privată |
unique_ips, unique_countries | Adrese și țări distincte văzute în fereastră |
browsers, os, devices | Mediile distincte în care a apărut acest vizitator |
risk.max_risk_score | Cel mai mare scor de risc înregistrat în fereastră, 0..100 |
risk.last_decision | Decizia înregistrată pentru cea mai recentă vizită |
risk.avg_bot_score, risk.bot_sessions | Media scorului de bot și numărul sesiunilor de bot — Business și peste |
network.*_seen | Dacă pentru acest vizitator au fost văzute vreodată VPN, proxy, nod de ieșire Tor sau adresă de datacenter |
network.proxy_detected_seen | Dacă cel puțin o vizită din fereastră a ieșit printr-un proxy sau un VPN aflat în fața browserului — vezi network.proxy_detected în Fapte despre dispozitiv |
network.last_isp | Cel mai recent ISP — Business și peste |
network.last_real_ip | Cea mai recentă adresă observată în spatele unui proxy sau VPN (address, country, isp) — Business și peste; absentă când nicio vizită nu a adus una |
last_session | Obiectul sesiune complet pentru cea mai recentă vizită |
meta | Planul, retenția lui în zile și fereastra aplicată efectiv |
Un vizitator fără date în fereastra de retenție returnează 404 not_found cu mesajul
visitor not found in the retention window — nu este o eroare în integrarea
ta, ci înseamnă că vizitatorul este nou sau a ieșit din fereastră odată cu
trecerea timpului.
Sesiunea poartă două verdicte, iar ele răspund la întrebări diferite — dacă clientul a fost automatizat și ce a concluzionat în ansamblu motorul de risc:
| Câmp | Valori |
|---|---|
bot.result | human, bot, uncertain |
bot.type | Prezent când bot.result este bot: fie un instrument anume (playwright, puppeteer, selenium, jsdom, claude_computer_use…), fie un agent AI verificat (ai_agent:<vendor>), fie o familie când instrumentul nu este numit — automation, headless, antidetect, extension, privacy_browser, impersonation, other |
decision.action | real, fake, suspicious |
bot.score și decision.risk_score merg amândouă pe 0..100. Pe Business și peste,
guidance le transformă în recomandări per scenariu, pe scara
allow → challenge → review → deny — vezi
Guidance pentru ce înseamnă fiecare
treaptă. Valorile și scalele coincid cu corpul webhook-ului v3 pentru aceeași vizită,
iar guidance este calculat după aceleași reguli.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions?limit=100&min_risk_score=50"| Parametru | Implicit | Note |
|---|---|---|
limit | 50 | Plafonat la 500; o valoare mai mare este redusă, nu respinsă |
from, to | Retenția planului | Fereastra temporală comună descrisă mai sus |
cursor | — | Cursor opac de paginare, din pagina anterioară |
bot_result | — | Păstrează doar sesiunile cu acest verdict de bot |
min_risk_score | — | Păstrează doar sesiunile cu scor de risc egal sau mai mare, 0..100 |
Sesiunile vin cu cele mai noi primele:
{ "items": [ { "request_id": "9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31", "visitor_id": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "timestamp": "2026-07-25T08:00:00Z" } ], "next_cursor": "MTcyMTg5NDQwMDAwMDphYmMxMjM", "has_more": true, "meta": { "plan": "business", "retention_days": 90, "from": "2026-04-26T00:00:00Z", "to": "2026-07-25T12:00:00Z" }}Paginarea se face pe bază de cursor. Nu există parametru page sau offset: trimite
înapoi drept cursor valoarea next_cursor primită și continuă cât timp has_more
este true. Ultima pagină poate să nu conțină deloc next_cursor, așa că nu face
acest câmp obligatoriu.
async function allSessions(visitorId: string, secretKey: string) { const sessions = [] let cursor: string | undefined
do { const url = new URL(`https://api.tracio.ai/v2/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.has_more ? page.next_cursor : undefined } while (cursor)
return sessions}Tratează cursorul ca opac — conținutul lui este un detaliu de implementare și se poate
schimba. Un cursor care a fost modificat este respins cu 400 invalid_request și
mesajul malformed cursor.
Pe lângă browserul și sistemul de operare luate din User-Agent, o sesiune poartă ceea ce browserul vizitatorului raportează despre mașină, curățat de partea noastră. Fiecare câmp lipsește când vizita nu a purtat astfel de date, așa că tratează-l pe fiecare drept opțional.
| Câmp | Semnificație |
|---|---|
gpu | Modelul plăcii video așa cum îl raportează browserul (WebGL), normalizat la un nume lizibil — Intel Iris Xe Graphics, Apple M1 Pro, Qualcomm Adreno 830; Software renderer înseamnă că nu există un GPU real (o mașină virtuală sau un mediu headless); Safari raportează Apple GPU |
network.proxy_detected | Traficul HTTP al vizitei și traseele ei de rețea brute ies prin rețele diferite — un proxy sau un VPN în fața browserului; două adrese ale aceluiași furnizor (NAT de operator, o a doua ieșire a aceluiași VPN) nu se pun la socoteală; nu este ridicat când adresele nu pot fi comparate (iCloud Private Relay, IPv4 alături de IPv6) |
network.real_ip.address, .country, .isp | Adresa publică observată pe traseul de rețea brut, adică adresa din spatele proxy-ului sau al VPN-ului, împreună cu țara și ISP-ul ei — Business și peste; absentă când nu a fost observată nicio astfel de adresă (country și isp lipsesc când nu au putut fi determinate) |
device_info.device_id, .cross_browser, .confidence, .linked_browsers | Prezent când identitatea dispozitivului a putut fi determinată: un identificator stabil al dispozitivului fizic, comun browserelor de pe el, dacă această vizită a venit printr-un browser diferit față de înainte, încrederea în această potrivire și câți vizitatori distincți (browsere) împart dispozitivul — peste unu înseamnă o singură mașină sub mai multe identități de browser — Business și peste |
os_environment | Mediul desktop măsurat pe o mașină Linux (Mint 22+, Ubuntu 25.04+, Ubuntu, GNOME, KDE) — Business și peste; absent când nu este determinat |
spoofing | Ce a pretins vizita față de ce au măsurat verificări independente (claimed, real, spoofed_axes dintre os, gpu, screen, network, browser; anonymous_browser cu numele produselor) — Business și peste; prezent doar când a fost detectată o falsificare |
screen.width, .height, .color_depth, .pixel_ratio | Rezoluția ecranului, adâncimea de culoare și device pixel ratio așa cum le raportează browserul — Business și peste |
locale.languages, locale.timezone | Limbile preferate și fusul orar ale browserului însuși — spre deosebire de geo.timezone, derivat din adresa IP; o nepotrivire între cele două este un semn frecvent al unei locații falsificate — Business și peste |
client_hints.architecture, .bitness, .model, .device_name, .platform_version | User-Agent Client Hints: arhitectura și bitness-ul procesorului, codul de model al dispozitivului (Android, de ex. SM-A556B) împreună cu numele său comercial din lista de dispozitive Google Play (device_name, de ex. Samsung Galaxy A55 5G) și versiunea exactă a platformei; doar browsere bazate pe Chromium — Business și peste |
environment.virtual_machine, environment.hypervisor | Prezent doar când placa video s-a declarat ea însăși virtuală; hypervisor este un dicționar închis (vmware, virtualbox, parallels, qemu, hyperv, bochs, intel-gvt, vgpu). Un bloc lipsă înseamnă că nu există un astfel de indiciu — Business și peste |
extensions enumeră extensiile de browser detectate în timpul vizitei — Pro și peste.
Fiecare intrare este un obiect:
| Câmp | Semnificație |
|---|---|
slug | Identificator stabil, de mașină, al extensiei — aceeași valoare pe care o livrează webhook-ul |
name | Nume lizibil pentru om |
category | Clasă generală — adblock, privacy, automation, wallet, vpn, devtools, other și așa mai departe |
risky | true pentru extensiile asociate cu automatizarea, falsificarea sau furtul de credențiale |
store_url | Link către pagina extensiei din magazin, când este cunoscut |
O constatare este raportată abia după ce a trecut de verificările noastre de încredere — un mediu care răspunde „instalat” la fiecare sondare sau un lot mai lung de douăsprezece nume este eliminat ca nesigur. Prin urmare, o listă goală sau lipsă înseamnă „nimic ce am putut confirma”, nu „nu există extensii instalate”. Citește-o ca pe o dovadă, nu ca pe un inventar.
fields conține perechile cheie-valoare personalizate pe care integrarea ta le-a atașat vizitei — o referință de comandă, numele unui plan, rezultatul unei plăți. Cheile și valorile sunt întotdeauna șiruri: un număr sau o valoare booleană atașată revine sub formă de text. Ca restul sesiunii, câmpul este disponibil în orice plan cu acces la API (Pro și peste) și lipsește atunci când vizita nu are câmpuri.
fields este citit în timp real la fiecare cerere, nu copiat în momentul vizitei. Câmpurile atașate după vizită (vezi Atașarea câmpurilor după vizită) apar și ele aici, așa că pentru aceeași vizită fields poate conține mai mult decât a livrat webhook-ul.
Nu pune date personale, precum nume, adrese de e-mail sau numere de telefon, în câmpurile personalizate — atașează în schimb o referință pe care propriile tale sisteme o pot rezolva, iar cine este titularul contului trimite ca înregistrare de cont (mai jos).
account este înregistrarea ta pentru contul din spatele vizitei — ceea ce ai
trimis ultima dată pentru acel account_id prin POST /v2/accounts/metadata:
{ "account": { "id": "user-42", "email": "ann@example.com", "display_name": "Ann Lee" }}| Câmp | Descriere |
|---|---|
id | ID-ul contului tău — aceeași valoare ca account_id |
email | Adresa de e-mail trimisă pentru cont; absentă când este goală |
display_name | Numele afișat trimis pentru cont; absent când este gol |
Înregistrarea este citită în timp real la fiecare cerere, așa că o redenumire apare și pe vizitele vechi: blocul descrie contul așa cum este acum, nu cum era în momentul vizitei. Este disponibilă în orice plan cu acces la API (Pro și peste). Etichetele trimise împreună cu înregistrarea nu sunt returnate.
Blocul lipsește când vizita nu are un cont asociat, când nu există o înregistrare pentru el (sau ai golit-o trimițând valori goale) și — rar — când înregistrarea nu a putut fi citită: sesiunea este totuși returnată integral, în loc ca cererea să eșueze, așa că tratează un bloc lipsă ca „necunoscut”, nu ca „acest cont nu are e-mail”. Webhook-urile nu poartă acest bloc.
Cea mai recentă:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions/latest"Aceasta returnează un obiect sesiune simplu — nu un array și nu împachetat într-un plic.
Un vizitator fără sesiuni în fereastră returnează 404 not_found cu
no sessions for this visitor in the retention window.
Sau după request_id, identificatorul care apare și în payload-ul webhook-ului:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/sessions/9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31?visitor_id=X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"visitor_id este opțional aici, dar transmiterea lui, atunci când îl cunoști, face
căutarea vizibil mai rapidă.
identification.drift_score — scorul de comportament netezit pe baza căruia a fost dat
verdictul de preluare a contului, Business și peste — este returnat doar de această
citire a unei singure sesiuni. Deriva comportamentului se măsoară în timpul vizitei,
după identificarea inițială, așa că rutele de listare și de ultimă sesiune îl omit. O
vizită al cărei comportament nu a fost evaluat nu are drift_score. Aceeași valoare
ajunge la tine prin webhook-ul account_takeover.
O vizită poate fi livrată prin webhook de mai multe ori: întâi primary, apoi late
sau correction, pe măsură ce sosesc semnalele mai lente și dovezile comportamentale
— iar o fază ulterioară poate răsturna verdictul anterior. Data API răspunde din
înregistrarea primary. Fazele ulterioare nu sunt contopite înapoi în ea, așa că
pentru o vizită corectată ultimul webhook este răspunsul mai nou. Dacă acționezi la
câteva minute după vizită, preferă faza primită ultima unei citiri proaspete de aici.
Un lucru merge în sens invers: odată ce detectorul de preluare a conturilor s-a
declanșat pentru o vizită, guidance de aici reflectă acest lucru, în timp ce corpurile
webhook identification ale aceleiași vizite nu poartă acea axă — ea vine prin
livrarea dedicată account_takeover.
Velocity răspunde la întrebarea „cât de mult a făcut acest vizitator în ultima vreme” — forma pe care o au credential stuffing-ul, testarea de carduri și înregistrările în masă.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/velocity?window=1h"window acceptă 1h, 24h sau 7d și are implicit 24h. Orice altă valoare este
respinsă cu 400 invalid_request și window must be one of: 1h, 24h, 7d.
{ "window": "1h", "events": 37, "unique_ips": 9, "unique_countries": 3, "unique_accounts": 12, "bot_events": 4, "meta": { "plan": "business", "retention_days": 90, "from": "2026-07-25T11:00:00Z", "to": "2026-07-25T12:00:00Z" }}unique_accounts numără valorile linkedId distincte pe care le-ai trimis pentru acest
dispozitiv — vezi Asocierea conturilor. bot_events este
Business și peste; pe Pro cheia lipsește.
TRACIO îți cunoaște conturile doar după ID-ul pe care site-ul tău îl transmite
ca linkedId — un șir opac precum usr_8412. Trimite o dată etichetele lizibile și
fiecare ecran din dashboard care arată acel cont va afișa numele sau adresa de e-mail în
locul ID-ului brut, iar obiectul sesiune le returnează în blocul său
account. Nimic de aici nu afectează detectarea sau scorarea; este
un strat de afișare.
curl -s -X POST "https://api.tracio.ai/v2/accounts/metadata" \ -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ -H "Content-Type: application/json" \ -d '{"accounts":[ {"account_id":"usr_8412","email":"ann@example.com","display_name":"Ann Lee","labels":{"tier":"vip"}}, {"account_id":"usr_9130","display_name":"Bob Ray"} ]}'{ "updated": 2 }fields. O adresă
de e-mail sau un nume trimis aici trăiește doar în înregistrarea de cont a
workspace-ului tău: nu este stocat per vizită, nu este scris în pagină, iar
o singură trimitere actualizează fiecare vizită a acelui cont.400 invalid_request, iar o singură
intrare greșită respinge întregul lot — eroarea îi indică poziția. ID-urile de cont
duplicate într-un lot sunt în regulă: câștigă ultimul.Limite: 1.000 de conturi per cerere, corp de 1 MiB, account_id ≤ 256 de caractere,
email ≤ 320, display_name ≤ 256, cel mult 16 etichete, cu chei ≤ 64 și valori
≤ 256 de caractere.
Browserul poate trimite doar ceea ce pagina știe la randare — un ID de comandă, niciodată rezultatul unei verificări de plată sau orice altceva care se rezolvă mai târziu. Această rută acoperă golul: găsește vizita după un câmp pe care îl poartă deja și atașează-i mai multe câmpuri pe partea de server.
curl -s -X POST "https://api.tracio.ai/v2/events/fields" \ -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ -H "Content-Type: application/json" \ -d '{"match":{"key":"order_ref","value":"A-1029"},"fields":{"amount":"120.00"}}'{ "updated": 1 }match găsește vizita după un câmp pe care îl are deja, nu după request_id, în
cadrul workspace-ului și mediului cheii tale.404 not_found — scrie câmpul la scurt timp după ce rezultatul se rezolvă.updated numără vizitele distincte. Trece de 1 doar când match atinge mai
multe vizite — o pereche cheie/valoare care nu este unică pentru o comandă sau un
coș. Un match care atinge mai mult de 100 de evenimente este refuzat cu
400 invalid_request, în loc să fie aplicat unui subset arbitrar.server și au prioritate față
de o valoare cu aceeași cheie scrisă de browser.404 not_found, nu un 200 gol.Limitele sunt aceleași ca pentru canalul din browser: 50 de câmpuri per apel, chei
≤ 40 de octeți, valori ≤ 500 de octeți — octeți, nu caractere — setul de caractere
al cheii A-Za-z0-9_.:-, corp de 1 MiB.
Șterge câmpuri personalizate — niciodată vizita însăși. Folosește-o pentru valori pe care nu mai ai nevoie să le ții atașate unei vizite, cum ar fi totalul unei comenzi. Webhook-urile deja trimise și exporturile deja făcute nu se modifică.
# by request_id — clears every field on this one visitcurl -s -X POST "https://api.tracio.ai/v2/events/fields/delete" \ -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ -H "Content-Type: application/json" \ -d '{"request_id":"9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31"}'
# by match — clears "order_ref" from every visit currently holding "A-1029"curl -s -X POST "https://api.tracio.ai/v2/events/fields/delete" \ -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ -H "Content-Type: application/json" \ -d '{"match":{"key":"order_ref","value":"A-1029"}}'{ "deleted": 1 }request_id și match se exclud reciproc — trimiterea amândurora sau a niciunuia
este 400 invalid_request. match folosește aceeași fereastră de 24 de ore și
același plafon de 100 de evenimente ca atașarea.deleted numără câmpurile eliminate din vizită (după request_id) sau vizitele
din care a fost eliminat câmpul (după match).404 not_found.Aceleași liste pe care operatorii tăi le gestionează în dashboard, accesibile
din propriul back office. Tipul unei liste este acțiunea ei asupra unei vizite
care se potrivește — block, manual_review, challenge, allow — iar modul ei
decide dacă acțiunea se aplică: observe doar numără potrivirile, enforce o aplică în
guidance (axa list). Listele și modul lor se creează în dashboard; Data API citește
listele și adaugă și elimină intrări.
curl -s "https://api.tracio.ai/v2/lists" \ -H "Authorization: Bearer tracio_sk_XXXX...XXXX"[ { "id": "7f3a9d2e-4c1b-4e8f-9a6d-1b2c3d4e5f60", "name": "Chargeback accounts", "type": "block", "mode": "enforce", "entries_count": 128 }]# ban an account for 30 dayscurl -s -X POST "https://api.tracio.ai/v2/lists/7f3a9d2e-4c1b-4e8f-9a6d-1b2c3d4e5f60/entries" \ -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ -H "Content-Type: application/json" \ -d '{"value":"usr_8412","value_type":"linked_id","ttl_minutes":43200}'{ "id": "02b4c8d1-6e7f-4a90-b1c2-d3e4f5a6b7c8", "value": "usr_8412", "value_type": "linked_id", "expires_at": "2026-10-19T12:00:00Z", "propagation": "immediate"}Elimină o intrare cu același corp la POST /v2/lists/{list_id}/entries/delete;
răspunsul este { "removed": true, "propagation": "immediate" }.
value_type este ceea ce se compară cu valoarea: linked_id, visitor_id,
device_id, ip, cidr sau country. O valoare care nu se poate interpreta pentru
tipul ei este 400 invalid_request.linked_id →
visitor_id → device_id → ip → cidr → country — iar în cadrul lui câștigă
acțiunea cea mai strictă.ttl_minutes este opțional. Dacă lipsește, se aplică TTL-ul implicit al listei;
dacă nici acesta nu există, intrarea nu expiră niciodată (expires_at este null).
Adăugarea din nou a unei intrări o reînnoiește.propagation spune când modificarea intră în vigoare: immediate sau ttl — în
aproximativ cinci minute.200 cu removed: false; 404 este
rezervat pentru o listă necunoscută.Un câmp lipsă înseamnă „fără date”, niciodată zero. Câmpurile fără valoare sunt
omise complet, în loc să fie trimise ca 0, "" sau null: un vizitator nou-nouț nu
are match_confidence, o vizită curată nu are antidetect_score sau suspect_score.
Singura excepție deliberată este bot.score, care este întotdeauna prezent, chiar și
când este zero. Citește câmpurile defensiv.
Payload-ul depinde de planul tău. Accesul la API începe de la Pro, iar Pro
primește sesiunea de bază — identificatori, timestamp, URL, IP, user agent, browser,
sistem de operare, dispozitiv, geo, rețea, bot, identificare și decizie — împreună cu
identification.match_type, identification.match_confidence, bot.score,
bot.type, bot.antidetect_score, gpu, network.proxy_detected, extensions,
fields și account. Business și Enterprise adaugă geo.isp, network.asn, network.real_ip, decision.suspect_score,
identification.drift_score, reasons, behavior, guidance, device_info,
spoofing, os_environment, screen, locale, client_hints și environment.
Câmpurile la nivel de persoană (person_id, reputation, linked_accounts_count,
linked_visitors_count) sunt rezervate pentru Business și Enterprise și vor apărea odată
ce stratul de persoane va fi activat — astăzi acesta rulează în mod de observare, iar
aceste câmpuri nu sunt livrate. Absența unui câmp Business pe un plan Pro nu este o eroare.
Detaliile interne la nivel de semnal nu sunt returnate niciodată, la niciun plan: numele semnalelor individuale, ponderile lor, pragurile din spatele unui verdict, valorile brute ale semnalelor și descompunerea scorurilor rămân de partea noastră. Un scor care poate fi supus ingineriei inverse până la intrările sale încetează să mai fie util ca apărare.
Fiecare eșec folosește un singur plic:
{ "error": { "code": "unauthorized", "message": "missing Authorization: Bearer <secret key>", "request_id": "8f14e45fceea167a5a36dedd" }}Acest request_id nu este identificatorul vizitei. Două valori diferite poartă
același nume: în payload-ul unei sesiuni, request_id este UUID-ul vizitei, același pe
care îl livrează webhook-ul; în plicul unei erori, este un identificator de urmărire de
24 de caractere, generat pentru fiecare apel HTTP. Identificatorul de urmărire se
întoarce și în antetul X-Request-Id la fiecare răspuns, reușit sau nu. Include-l
când contactezi suportul — așa îți găsim apelul exact.
| HTTP | code | Semnificație |
|---|---|---|
| 400 | invalid_request | Un parametru lipsește sau este malformat |
| 401 | unauthorized | Cheia lipsește, este invalidă, revocată sau expirată |
| 402 | upgrade_required | Planul tău nu include acces la API |
| 404 | not_found | Nimic nu s-a potrivit în fereastra de retenție sau aparține altui mediu |
| 405 | method_not_allowed | Ruta există, dar nu pentru acea metodă |
| 429 | rate_limited | S-au depășit cererile pe secundă sau cota zilnică |
| 500 | internal | Ceva a eșuat de partea noastră |
| 503 | unavailable | Un depozit de date suport este temporar inaccesibil |
Verificările se fac într-o ordine fixă — cheia, apoi planul, apoi limitele — așa că o
cerere cu o cheie greșită raportează întotdeauna mai întâi cheia, niciodată o problemă
de cotă. Datele din alt workspace nu se pot deosebi de datele care nu există: ele dau
404, nu 403.
Două cazuri de 401 se citesc diferit în mod intenționat:
missing Authorization: Bearer <secret key> înseamnă că antetul nu a sosit niciodată,
în timp ce invalid or revoked API key înseamnă că a sosit și nu s-a potrivit. 402
poartă Data API requires the Pro plan or higher.
Reîncearcă 429 și 503 cu o pauză tot mai mare; reîncercarea altor 4xx nu are
rost — ele înseamnă că cererea însăși trebuie corectată.
Răspunsurile pentru care cheia a fost recunoscută poartă situația ta curentă
(răspunsurile 401 și 402 nu o poartă, iar Enterprise, fără cotă zilnică, nu primește
antete de cotă):
| Antet | Semnificație |
|---|---|
X-RateLimit-Limit | Cota ta zilnică; la un refuz pe secundă, limita pe secundă |
X-RateLimit-Remaining | Apeluri rămase astăzi |
X-RateLimit-Reset | Timpul Unix al resetării — miezul nopții UTC |
Retry-After | Secunde de așteptat, trimis doar cu un 429 — ghidează-te după el: e corect pentru ambele limite |
| Plan | Cereri pe secundă | Cereri pe zi | Adâncimea istoricului |
|---|---|---|---|
| Free | Fără acces la API | — | 7 zile |
| Pro | 10 | 10.000 | 30 de zile |
| Business | 50 | 100.000 | 90 de zile |
| Enterprise | 200 | Nelimitat | 365 de zile |