Med 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 | Server 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 Server 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"Server 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 Server 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, "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" }}| 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.lastIsp | Den senaste ISP:n — från Business och uppåt |
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 |
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(`Server 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.
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 och bot.antidetectScore. Business och Enterprise
lägger till geo.isp, network.asn, decision.suspectScore,
identification.driftScore, reasons, behavior, guidance, deviceInfo och fälten
på personnivå (personId, reputation, linkedAccountsCount, linkedVisitorsCount).
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 |