Med Data API (tidigare dokumenterat här som Server API) kan din backend läsa de identifieringsdata som TRACIO redan har samlat in för ditt workspace: en besökares historik, enskilda sessioner och velocity-räknare över korta fönster.
Det kompletterar webhooks i stället för att ersätta dem:
| Webhooks | Data API | |
|---|---|---|
| Riktning | TRACIO pushar till din endpoint | Din backend hämtar vid behov |
| Tidpunkt | Så snart en identifiering sker | När som helst, inom ditt lagringsfönster |
| Bäst för | Att reagera på en händelse | Att slå upp data under ett beslut, efterhämtningar, utredningar |
Båda gränssnitten är tillgängliga från prisplanen Pro och uppåt.
https://api.tracio.ai/v1Det här är en annan värd än browser-endpointen (edge.tracio.ai) och än dashboarden
(app.tracio.ai). Alla tre är separata: webbläsaren pratar med edge med din publika
nyckel, din backend pratar med Data API med din hemliga nyckel.
Varje begäran bär din hemliga nyckel som en bearer-token:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Data API är enbart server-till-server. CORS-headers returneras avsiktligt inte, så en webbläsare kan inte anropa det — det är just det som håller din hemliga nyckel utanför klientkoden. Leverera aldrig den hemliga nyckeln till webbläsaren.
Skapa den i dashboarden under API Keys och välj typen secret.
tracio_sk_ följt av 43 tecken, 53 totalt. Dashboarden
listar den utifrån dess första tecken så att du kan skilja nycklar åt.Vid rotation utfärdas en ny nyckel medan den gamla fortsätter att fungera i 7 dagar, så att du kan rulla ut den utan avbrott. Rulla ut den nya nyckeln, bekräfta att trafiken har flyttat över, och låt den gamla löpa ut. Publika nycklar går inte att rotera — de är inga hemligheter och syns avsiktligt i sidans källkod.
Varje route är ett GET. Det finns inga skrivoperationer i Data API: det läser data,
och din konfiguration lever i dashboarden.
| Metod | Sökväg | Returnerar |
|---|---|---|
GET | /v1/visitors/{visitorId} | Aggregerad historik för en besökare, plus dennes senaste session |
GET | /v1/visitors/{visitorId}/sessions | Paginerad lista över den besökarens sessioner |
GET | /v1/visitors/{visitorId}/sessions/latest | Den enskilt senaste sessionen |
GET | /v1/visitors/{visitorId}/velocity | Aktivitetsräknare över ett kort fönster |
GET | /v1/sessions/{requestId} | En session utifrån dess request-identifierare |
GET | /.well-known/webhook-keys | Publika nycklar för webhookarnas plattformssignatur (ingen auth) |
Ett avslutande snedstreck accepteras och ignoreras. En okänd sökväg eller fel metod returnerar samma JSON-felkuvert som allt annat, aldrig en HTML- eller klartextsida.
Varje läsning avgränsas av ett tidsfönster, styrt av två valfria query-parametrar:
| Parameter | Godtar |
|---|---|
from | YYYY-MM-DD eller en fullständig RFC 3339-tidsstämpel |
to | YYYY-MM-DD eller en fullständig RFC 3339-tidsstämpel |
to inkluderar hela det dygnet.400 invalid_request och meddelandet
time must be YYYY-MM-DD or RFC3339.meta, så kontrollera meta.from och meta.to i stället för att anta att din
begäran uppfylldes ordagrant.curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Svaret bär den aggregerade historiken och bäddar in den senaste sessionen, så att det vanliga fallet kräver en begäran i stället för två:
{ "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" }}| Fält | Betydelse |
|---|---|
visits, incognitoVisits | Totalt antal besök i fönstret, och hur många av dem som skedde i ett privat fönster |
uniqueIps, uniqueCountries | Distinkta adresser och länder som setts i fönstret |
browsers, os, devices | De distinkta miljöer den här besökaren har dykt upp i |
risk.maxRiskScore | Den högsta riskpoäng som registrerats i fönstret, 0..100 |
risk.lastDecision | Det beslut som registrerats för det senaste besöket |
risk.avgBotScore, risk.botSessions | Genomsnittlig botpoäng och antalet bot-sessioner — från Business och uppåt |
network.*Seen | Om ett VPN, en proxy, en Tor-exitnod eller en datacenteradress någonsin setts för den här besökaren |
network.proxyDetectedSeen | Om minst ett besök i fönstret gick ut genom en proxy eller ett VPN framför webbläsaren — se network.proxyDetected under ”Enhetsfakta” |
network.lastIsp | Den senaste ISP:n — från Business och uppåt |
network.lastRealIp | Den senaste adress som observerats bakom en proxy eller ett VPN — från Business och uppåt; saknas när ingen sådan observerats |
lastSession | Hela session-objektet för det senaste besöket |
meta | Prisplanen, dess lagring i dagar och det fönster som faktiskt tillämpades |
En besökare utan data inom lagringsfönstret ger 404 not_found med meddelandet
visitor not found in the retention window — det är inte ett fel i din integration,
det betyder att besökaren är ny eller har fallit ur lagringstiden.
Sessionen bär två verdikt, och de svarar på olika frågor — om klienten var automatiserad och vad riskmotorn kom fram till på det hela taget:
| Fält | Värden |
|---|---|
bot.result | human, bot, uncertain |
bot.type | Finns när bot.result är bot: antingen ett specifikt verktyg (playwright, puppeteer, selenium, jsdom, claude_computer_use…) eller en familj när verktyget inte namnges — automation, headless, antidetect, extension, privacy_browser, other |
decision.action | real, fake, suspicious |
bot.score och decision.riskScore löper båda 0..100. Från Business och uppåt gör
guidance om dem till råd per scenario på stegen
allow → challenge → review → deny — se
Guidance för vad varje steg betyder.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions?limit=100&minRiskScore=50"| Parameter | Standard | Anmärkningar |
|---|---|---|
limit | 50 | Taket är 500; ett större värde kapas, avvisas inte |
from, to | Prisplanens lagring | Det gemensamma tidsfönstret som beskrivs ovan |
cursor | — | Ogenomskinlig pagineringscursor från föregående sida |
botResult | — | Behåll endast sessioner med detta bot-verdikt |
minRiskScore | — | Behåll endast sessioner på eller över denna riskpoäng, 0..100 |
Sessionerna kommer tillbaka med den nyaste först:
{ "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" }}Bläddringen är cursorbaserad. Det finns ingen parameter page eller offset: skicka
tillbaka den nextCursor du fick som cursor, och fortsätt så länge hasMore är sant.
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}Behandla cursorn som ogenomskinlig — dess innehåll är en implementationsdetalj och kan
ändras. En cursor som har redigerats avvisas med 400 invalid_request och meddelandet
malformed cursor.
Vid sidan av webbläsaren och operativsystemet som hämtas från User-Agent bär en session det som besökarens webbläsare rapporterar om maskinen, sanerat på vår sida. Varje fält saknas när besöket inte bar med sig sådana data, så behandla vart och ett som valfritt.
| Fält | Innebörd |
|---|---|
gpu | Grafikkortets modell så som webbläsaren rapporterar den (WebGL), normaliserad till ett läsbart namn — Intel Iris Xe Graphics, Apple M1 Pro, Qualcomm Adreno 830; Software renderer betyder ingen riktig GPU (en virtuell maskin eller en headless-miljö); Safari rapporterar Apple GPU |
network.proxyDetected | Besökets HTTP-trafik och dess råa nätverksvägar går ut genom olika nätverk — en proxy eller ett VPN framför webbläsaren; två adresser hos samma leverantör (carrier-NAT, en andra utgång i samma VPN) räknas inte |
network.realIp.address, .country, .isp | Den publika adress som observerats på den råa nätverksvägen, det vill säga adressen bakom proxyn eller VPN:et, med dess land och ISP — från Business och uppåt; saknas när ingen sådan adress observerats (country och isp saknas när de inte gick att fastställa) |
deviceInfo.deviceId, .crossBrowser, .confidence, .linkedBrowsers | Finns när en enhetsidentitet kunde fastställas: ett stabilt id för den fysiska enheten gemensamt för webbläsarna på den, om det här besöket kom via en annan webbläsare än tidigare, konfidensen för den matchningen och hur många distinkta besökare (webbläsare) som delar enheten — fler än en betyder en maskin under flera webbläsaridentiteter — från Business och uppåt |
osEnvironment | Skrivbordsmiljön som mätts på en Linux-maskin (Mint 22+, Ubuntu, GNOME, KDE) — från Business och uppåt; saknas när den inte har fastställts |
spoofing | Vad besöket påstod jämfört med vad oberoende kontroller mätte (claimed, real, spoofedAxes av os, gpu, screen, network, browser; anonymousBrowser med produktnamn) — från Business och uppåt; finns endast när en förfalskning upptäckts |
screen.width, .height, .colorDepth, .pixelRatio | Skärmupplösning, färgdjup och device pixel ratio så som webbläsaren rapporterar dem — från Business och uppåt |
locale.languages, locale.timezone | Webbläsarens egna föredragna språk och tidszon — till skillnad från geo.timezone, som härleds från IP-adressen; en avvikelse mellan de två är ett vanligt tecken på en förfalskad plats — från Business och uppåt |
clientHints.architecture, .bitness, .model, .deviceName, .platformVersion | User-Agent Client Hints: CPU-arkitektur och bitness, enhetens modellkod (Android, t.ex. SM-A556B) med dess marknadsnamn från Google Plays enhetslista (deviceName, t.ex. Samsung Galaxy A55 5G) och den exakta plattformsversionen; endast Chromium-baserade webbläsare — från Business och uppåt |
environment.virtualMachine, environment.hypervisor | Finns endast när grafikkortet angav sig självt som virtuellt; hypervisor är en sluten ordlista (vmware, virtualbox, parallels, qemu, hyperv, bochs, intel-gvt, vgpu). Ett block som saknas betyder att inget sådant belägg finns — från Business och uppåt |
extensions listar de webbläsartillägg som upptäckts under besöket — från Business och uppåt. Varje post är ett objekt:
| Fält | Betydelse |
|---|---|
slug | Stabil maskinidentifierare för tillägget, samma värde som webhooken levererar |
name | Läsbart namn för människor |
category | Grov klass — adblock, privacy, automation, wallet, vpn, devtools, other och så vidare |
risky | true för tillägg som förknippas med automatisering, förfalskning eller stöld av inloggningsuppgifter |
storeUrl | Länk till tilläggets sida i butiken, när den är känd |
Ett fynd rapporteras först när det har klarat våra tillförlitlighetskontroller — en miljö som svarar ”installerat” på varje sondering, eller en batch längre än tolv namn, förkastas som opålitlig. En tom eller saknad lista betyder därför ”inget vi kunde bekräfta”, inte ”inga tillägg installerade”. Läs den som ett indicium, inte som en inventering.
Den senaste:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions/latest"Detta returnerar ett naket session-objekt — ingen array, och inte inslaget i ett kuvert.
En besökare utan sessioner i fönstret ger 404 not_found med
no sessions for this visitor in the retention window.
Eller via requestId, den identifierare som också dyker upp i webhook-payloaden:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/sessions/9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31?visitorId=X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"visitorId är valfri här, men att skicka med den när du känner till den gör
uppslagningen märkbart snabbare.
Velocity svarar på ”hur mycket har den här besökaren gjort på sistone” — formen på credential stuffing, card testing och massregistreringar.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/velocity?window=1h"window godtar 1h, 24h eller 7d och är som standard 24h. Varje annat värde
avvisas med 400 invalid_request och 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 räknar de distinkta linkedId-värden du skickat för den här enheten —
se Kontokoppling. botEvents finns från Business och uppåt.
Ett fält som saknas betyder ”inga data”, aldrig noll. Fält utan värde utelämnas helt
i stället för att skickas som 0, "" eller null: en helt ny besökare har ingen
matchConfidence, ett rent besök har ingen antidetectScore eller suspectScore. Det
enda avsiktliga undantaget är bot.score, som alltid finns med även när den är noll.
Läs fälten defensivt.
Payloaden beror på din prisplan. Varje prisplan med API-åtkomst får bassessionen — identifierare, tidsstämpel, URL, IP, user agent, webbläsare, operativsystem, enhet, geo, nätverk, bot, identifiering och beslut. Pro lägger till identification.matchType, identification.matchConfidence, bot.type, bot.antidetectScore, gpu och network.proxyDetected. Business och Enterprise lägger till extensions, geo.isp, network.asn, network.realIp, decision.suspectScore, identification.driftScore, reasons, behavior, guidance, deviceInfo, spoofing, osEnvironment, screen, locale, clientHints och environment. Fälten på personnivå (personId, reputation, linkedAccountsCount, linkedVisitorsCount) är reserverade för Business och Enterprise och dyker upp när personlagret slås på — i dag körs det i observationsläge och dessa fält levereras inte. Att ett Business-fält saknas på en Pro-plan är inte ett fel.
Interna detaljer på signalnivå returneras aldrig, i ingen prisplan: enskilda signalnamn, deras vikter, trösklarna bakom ett verdikt, råa signalvärden och uppdelningar av poäng stannar på vår sida. En poäng som kan bakåtkompileras till sina indata upphör att vara användbar som skydd.
Varje misslyckande använder ett och samma kuvert:
{ "error": { "code": "unauthorized", "message": "missing Authorization: Bearer <secret key>", "requestId": "8f14e45fceea167a5a36dedd" }}Den här requestId är inte besökets identifierare. Två olika värden delar namn:
inuti en session-payload är requestId besökets UUID, samma som webhooken levererar;
inuti ett felkuvert är det en trace-identifierare på 24 tecken som präglas per
HTTP-anrop. Trace-identifieraren kommer också tillbaka i headern X-Request-Id i varje
svar, lyckat eller inte. Ta med den när du kontaktar supporten — det är så vi hittar
just ditt anrop.
| HTTP | code | Betydelse |
|---|---|---|
| 400 | invalid_request | En parameter saknas eller är felformad |
| 401 | unauthorized | Nyckeln saknas, är ogiltig, återkallad eller utgången |
| 402 | upgrade_required | Din prisplan innehåller inte API-åtkomst |
| 404 | not_found | Inget matchade inom lagringsfönstret |
| 405 | method_not_allowed | Routen finns, men inte för den metoden |
| 429 | rate_limited | Antal begäranden per sekund, eller dygnskvoten, överskridet |
| 500 | internal | Något gick fel på vår sida |
| 503 | unavailable | En underliggande lagring är tillfälligt onåbar |
Kontrollerna körs i en fast ordning — nyckel, sedan prisplan, sedan gränser — så en begäran med fel nyckel rapporterar alltid nyckeln först, aldrig ett kvotproblem.
Två 401-fall läses olika med flit: missing Authorization: Bearer <secret key> betyder
att headern aldrig kom fram, medan invalid or revoked API key betyder att den kom fram
och inte matchade. 402 bär Data API requires the Pro plan or higher.
Varje autentiserat svar bär din aktuella ställning:
| Header | Betydelse |
|---|---|
X-RateLimit-Limit | Din dygnskvot |
X-RateLimit-Remaining | Anrop kvar i dag |
X-RateLimit-Reset | Unix-tid för nollställningen — midnatt UTC |
Retry-After | Sekunder att vänta, skickas endast med ett 429 |
| Prisplan | Begäranden per sekund | Begäranden per dygn | Historikdjup |
|---|---|---|---|
| Free | Ingen API-åtkomst | — | 7 dagar |
| Pro | 10 | 10 000 | 30 dagar |
| Business | 50 | 100 000 | 90 dagar |
| Enterprise | 200 | Utan kvot | 365 dagar |