Met de Server API kan uw backend de identificatiegegevens lezen die TRACIO al voor uw workspace heeft verzameld: de geschiedenis van een bezoeker, afzonderlijke sessies en velocity-tellers over korte vensters.
Hij vult webhooks aan in plaats van ze te vervangen:
| Webhooks | Server API | |
|---|---|---|
| Richting | TRACIO pusht naar uw endpoint | Uw backend haalt op wanneer nodig |
| Timing | Zodra elke identificatie plaatsvindt | Op elk moment, binnen uw bewaarvenster |
| Het best voor | Reageren op een event | Gegevens opzoeken tijdens een beslissing, backfills, onderzoeken |
Beide interfaces zijn beschikbaar vanaf het Pro-abonnement en hoger.
https://api.tracio.ai/v1Dit is een andere host dan het browser-endpoint (edge.tracio.ai) en dan het dashboard
(app.tracio.ai). Alle drie staan los van elkaar: de browser praat met de edge met uw
publieke sleutel, uw backend praat met de Server API met uw geheime sleutel.
Elk verzoek draagt uw geheime sleutel als bearer-token:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"De Server API is uitsluitend server-naar-server. CORS-headers worden bewust niet teruggegeven, zodat een browser hem niet kan aanroepen — precies dat houdt uw geheime sleutel buiten client-side code. Lever de geheime sleutel nooit uit aan de browser.
Maak hem aan in het dashboard onder API Keys en kies daarbij het type secret.
tracio_sk_ gevolgd door 43 tekens, 53 in totaal.
Het dashboard toont hem aan de hand van zijn eerste tekens, zodat u sleutels uit
elkaar kunt houden.Bij roteren wordt een nieuwe sleutel uitgegeven terwijl de oude nog 7 dagen blijft werken, zodat u hem zonder downtime kunt uitrollen. Rol de nieuwe sleutel uit, controleer dat het verkeer is verhuisd, en laat de oude verlopen. Publieke sleutels kunnen niet worden geroteerd — het zijn geen geheimen en ze staan met opzet zichtbaar in de broncode van uw pagina.
Elke route is een GET. Er zijn geen schrijfoperaties in de Server API: hij leest
gegevens, en uw configuratie leeft in het dashboard.
| Methode | Pad | Geeft terug |
|---|---|---|
GET | /v1/visitors/{visitorId} | Geaggregeerde geschiedenis van één bezoeker, plus diens laatste sessie |
GET | /v1/visitors/{visitorId}/sessions | Gepagineerde lijst van de sessies van die bezoeker |
GET | /v1/visitors/{visitorId}/sessions/latest | De enkele meest recente sessie |
GET | /v1/visitors/{visitorId}/velocity | Activiteitstellers over een kort venster |
GET | /v1/sessions/{requestId} | Eén sessie op basis van zijn request-identificatie |
GET | /.well-known/webhook-keys | Publieke sleutels voor de platformhandtekening van webhooks (geen auth) |
Een afsluitende slash wordt geaccepteerd en genegeerd. Een onbekend pad of een verkeerde methode geeft dezelfde JSON-foutenvelop terug als al het andere, nooit een HTML- of platte-tekstpagina.
Elke leesactie wordt begrensd door een tijdvenster, gestuurd door twee optionele query-parameters:
| Parameter | Accepteert |
|---|---|
from | YYYY-MM-DD of een volledige RFC 3339-tijdstempel |
to | YYYY-MM-DD of een volledige RFC 3339-tijdstempel |
to omvat die hele dag.400 invalid_request en het bericht
time must be YYYY-MM-DD or RFC3339.meta, dus controleer meta.from en meta.to in plaats van
aan te nemen dat uw verzoek letterlijk is ingewilligd.curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"De response draagt de geaggregeerde geschiedenis en bevat de laatste sessie, zodat het gangbare geval één verzoek nodig heeft in plaats van twee:
{ "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" }}| Veld | Betekenis |
|---|---|
visits, incognitoVisits | Totaal aantal bezoeken in het venster, en hoeveel daarvan in een privévenster waren |
uniqueIps, uniqueCountries | Verschillende adressen en landen die in het venster zijn gezien |
browsers, os, devices | De verschillende omgevingen waarin deze bezoeker is verschenen |
risk.maxRiskScore | De hoogste risicoscore die in het venster is vastgelegd, 0..100 |
risk.lastDecision | De beslissing die voor het meest recente bezoek is vastgelegd |
risk.avgBotScore, risk.botSessions | Gemiddelde bot-score en het aantal bot-sessies — vanaf Business |
network.*Seen | Of er voor deze bezoeker ooit een VPN, proxy, Tor-exitnode of datacenteradres is gezien |
network.lastIsp | De meest recente ISP — vanaf Business |
lastSession | Het volledige sessie-object van het meest recente bezoek |
meta | Het abonnement, de bewaartermijn in dagen en het venster dat daadwerkelijk is toegepast |
Een bezoeker zonder gegevens binnen het bewaarvenster geeft 404 not_found met het
bericht visitor not found in the retention window — dat is geen fout in uw
integratie, het betekent dat de bezoeker nieuw is of buiten de termijn is gevallen.
De sessie draagt twee verdicts, en die beantwoorden verschillende vragen — of de client geautomatiseerd was, en wat de risico-engine in het geheel concludeerde:
| Veld | Waarden |
|---|---|
bot.result | human, bot, uncertain |
decision.action | real, fake, suspicious |
bot.score en decision.riskScore lopen allebei van 0..100. Vanaf Business zet
guidance ze om in advies per scenario op de ladder
allow → challenge → review → deny — zie
Guidance voor wat elke trede betekent.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions?limit=100&minRiskScore=50"| Parameter | Standaard | Opmerkingen |
|---|---|---|
limit | 50 | Gemaximeerd op 500; een grotere waarde wordt ingekort, niet geweigerd |
from, to | Bewaartermijn van abonnement | Het gedeelde tijdvenster dat hierboven is beschreven |
cursor | — | Ondoorzichtige paginatiecursor van de vorige pagina |
botResult | — | Houd alleen sessies met dit bot-verdict over |
minRiskScore | — | Houd alleen sessies op of boven deze risicoscore over, 0..100 |
Sessies komen terug met de nieuwste eerst:
{ "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" }}Bladeren gaat op basis van een cursor. Er is geen parameter page of offset: geef de
nextCursor die u hebt ontvangen terug als cursor, en ga door zolang hasMore waar
is.
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}Behandel de cursor als ondoorzichtig — de inhoud ervan is een implementatiedetail en
kan veranderen. Een cursor die is bewerkt, wordt geweigerd met 400 invalid_request en
het bericht malformed cursor.
De meest recente:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions/latest"Dit geeft een kaal sessie-object terug — geen array, en niet verpakt in een envelop.
Een bezoeker zonder sessies in het venster geeft 404 not_found met
no sessions for this visitor in the retention window.
Of op requestId, de identificatie die ook in de webhook-payload verschijnt:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/sessions/9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31?visitorId=X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"visitorId is hier optioneel, maar hem meegeven wanneer u hem kent, maakt het opzoeken
merkbaar sneller.
Velocity beantwoordt de vraag “hoeveel heeft deze bezoeker de laatste tijd gedaan” — de vorm van credential stuffing, card testing en registraties in bulk.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v1/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/velocity?window=1h"window accepteert 1h, 24h of 7d en is standaard 24h. Elke andere waarde wordt
geweigerd met 400 invalid_request en 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 telt de verschillende linkedId-waarden die u voor dit apparaat hebt
gestuurd — zie Accounts koppelen. botEvents is vanaf
Business.
Een ontbrekend veld betekent “geen gegevens”, nooit nul. Velden zonder waarde
worden volledig weggelaten in plaats van verstuurd als 0, "" of null: een
gloednieuwe bezoeker heeft geen matchConfidence, een schoon bezoek heeft geen
antidetectScore of suspectScore. De ene bewuste uitzondering is bot.score, dat
altijd aanwezig is, zelfs wanneer het nul is. Lees velden defensief.
De payload hangt af van uw abonnement. Elk abonnement met API-toegang krijgt de
basissessie — identificaties, tijdstempel, URL, IP, user agent, browser,
besturingssysteem, apparaat, geo, netwerk, bot, identificatie en beslissing. Pro voegt
identification.matchType, identification.matchConfidence en bot.antidetectScore
toe. Business en Enterprise voegen geo.isp, network.asn, decision.suspectScore,
identification.driftScore, reasons, behavior, guidance, deviceInfo en de
velden op persoonsniveau toe (personId, reputation, linkedAccountsCount,
linkedVisitorsCount). Het ontbreken van een Business-veld op een Pro-abonnement is
geen fout.
Interne details op signaalniveau worden nooit teruggegeven, op geen enkel abonnement: afzonderlijke signaalnamen, hun gewichten, de drempels achter een verdict, ruwe signaalwaarden en de opbouw van scores blijven aan onze kant. Een score die via reverse engineering tot zijn invoer te herleiden is, houdt op nuttig te zijn als verdediging.
Elke mislukking gebruikt één envelop:
{ "error": { "code": "unauthorized", "message": "missing Authorization: Bearer <secret key>", "requestId": "8f14e45fceea167a5a36dedd" }}Deze requestId is niet de identificatie van het bezoek. Twee verschillende
waarden delen de naam: binnen een sessie-payload is requestId de UUID van het bezoek,
dezelfde die de webhook levert; binnen een foutenvelop is het een trace-identificatie
van 24 tekens die per HTTP-aanroep wordt aangemaakt. De trace-identificatie komt ook
terug in de header X-Request-Id bij elke response, geslaagd of niet. Vermeld hem
wanneer u contact opneemt met support — zo vinden wij precies uw aanroep.
| HTTP | code | Betekenis |
|---|---|---|
| 400 | invalid_request | Een parameter ontbreekt of is misvormd |
| 401 | unauthorized | De sleutel ontbreekt, is ongeldig, ingetrokken of verlopen |
| 402 | upgrade_required | Uw abonnement bevat geen API-toegang |
| 404 | not_found | Er kwam niets overeen binnen het bewaarvenster |
| 405 | method_not_allowed | De route bestaat, maar niet voor die methode |
| 429 | rate_limited | Verzoeken per seconde, of de dagelijkse quota, overschreden |
| 500 | internal | Er is iets misgegaan aan onze kant |
| 503 | unavailable | Een onderliggende opslag is tijdelijk onbereikbaar |
De controles lopen in een vaste volgorde — sleutel, dan abonnement, dan limieten — zodat een verzoek met een verkeerde sleutel altijd eerst de sleutel meldt, nooit een quotaprobleem.
Twee 401-gevallen lezen met opzet anders: missing Authorization: Bearer <secret key>
betekent dat de header nooit is aangekomen, terwijl invalid or revoked API key
betekent dat hij is aangekomen en niet overeenkwam. 402 draagt
Data API requires the Pro plan or higher.
Elke geauthenticeerde response draagt uw huidige stand:
| Header | Betekenis |
|---|---|
X-RateLimit-Limit | Uw dagelijkse quota |
X-RateLimit-Remaining | Aanroepen die vandaag nog over zijn |
X-RateLimit-Reset | Unix-tijd van de reset — middernacht UTC |
Retry-After | Aantal seconden wachten, alleen verstuurd bij een 429 |
| Abonnement | Verzoeken per seconde | Verzoeken per dag | Diepte van de geschiedenis |
|---|---|---|---|
| Free | Geen API-toegang | — | 7 dagen |
| Pro | 10 | 10.000 | 30 dagen |
| Business | 50 | 100.000 | 90 dagen |
| Enterprise | 200 | Zonder quotum | 365 dagen |