Met de Data API (hier eerder gedocumenteerd als de Server API) kan jouw backend de identificatiegegevens lezen die TRACIO al voor je workspace heeft verzameld: de geschiedenis van een bezoeker, afzonderlijke sessies en velocity-tellers over korte vensters. Een paar routes schrijven ook — accountrecords, aangepaste velden en lijstvermeldingen — zodat jouw backend kan aanvullen wat TRACIO weet.
Hij vult webhooks aan in plaats van ze te vervangen:
| Webhooks | Data API | |
|---|---|---|
| Richting | TRACIO pusht naar je endpoint | Je backend haalt op wanneer nodig |
| Timing | Zodra elke identificatie plaatsvindt | Op elk moment, binnen je 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/v2Dit 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 je
publieke sleutel, je backend praat met de Data API met je geheime sleutel.
De /v1-routes zijn verwijderd. Gebruik /v2: de routes zijn dezelfde, en elke
JSON-sleutel en query-parameter staat in snake_case (visitor_id, risk_score,
min_risk_score). Sleutels binnen je eigen woordenboeken fields en labels zijn jouw
gegevens en behouden hun oorspronkelijke schrijfwijze. De JavaScript-SDK behoudt zijn
camelCase-interface.
Elk verzoek draagt je geheime sleutel als bearer-token:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"De Data API is uitsluitend server-naar-server. CORS-headers worden bewust niet teruggegeven, zodat een browser hem niet kan aanroepen — precies dat houdt je 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 je sleutels uit
elkaar kunt houden.404, precies zoals voor gegevens die niet bestaan.Bij roteren wordt een nieuwe sleutel uitgegeven terwijl de oude nog 7 dagen blijft werken, zodat je 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 je pagina.
| Methode | Pad | Geeft terug |
|---|---|---|
GET | /v2/visitors/{visitor_id} | Geaggregeerde geschiedenis van één bezoeker, plus diens laatste sessie |
GET | /v2/visitors/{visitor_id}/sessions | Gepagineerde lijst van de sessies van die bezoeker |
GET | /v2/visitors/{visitor_id}/sessions/latest | De enkele meest recente sessie |
GET | /v2/visitors/{visitor_id}/velocity | Activiteitstellers over een kort venster |
GET | /v2/sessions/{request_id} | Eén sessie op basis van zijn request-identificatie |
POST | /v2/accounts/metadata | Weergavenamen en e-mailadressen aan je account-ID's koppelen |
POST | /v2/events/fields | Aangepaste velden na het laden van de pagina aan een bezoek koppelen |
POST | /v2/events/fields/delete | Aangepaste velden van een bezoek wissen — het bezoek zelf blijft onaangeroerd |
GET | /v2/lists | Je workspacelijsten: id, naam, type (de actie), modus, aantal vermeldingen |
POST | /v2/lists/{list_id}/entries | Een waarde aan een lijst toevoegen, optioneel met een TTL |
POST | /v2/lists/{list_id}/entries/delete | Een waarde uit een lijst verwijderen |
GET | /.well-known/webhook-keys | Publieke sleutels voor de platformhandtekening van webhooks (geen auth) |
Dezelfde sleutel en host bedienen ook de beslissings-API's, allemaal in snake_case:
| Methode | Pad | Doel |
|---|---|---|
POST | /v2/transactions | Een synchrone beslissing APPROVE / REVIEW / DECLINE over een zakelijk event — vanaf Business, behalve een affiliateconversie (account_register of deposit met affiliate_id), die op elk abonnement met API-toegang beschikbaar is |
GET | /v2/transactions/{transaction_id} | Een beslissing opnieuw lezen met haar label en effectieve status — vanaf Business, behalve een transactie die aan een affiliate is toegeschreven |
PUT, DELETE | /v2/transaction-labels | Het uitkomstlabel van maximaal 50 transacties instellen of verwijderen — vanaf Business |
GET | /v2/transaction-labels/value-set | De geaccepteerde labelwaarden met hun polariteit — vanaf Business |
POST | /v2/logins/assess | Een login beoordelen: allow / challenge / review / deny met redenen |
POST, GET | /v2/accounts/{user_id}/trusted-devices | Het apparaat van een bezoek na je step-up als vertrouwd markeren voor een account, of de vertrouwde apparaten van het account opsommen |
DELETE | /v2/accounts/{user_id}/trusted-devices/{device_ref} | Het vertrouwen in een apparaat intrekken |
GET | /v2/affiliates/{affiliate_id} | Het kwaliteitsrapport van een affiliate over 90 dagen, met een aanbeveling hold / review |
POST, GET | /v2/self-exclusions | Een zelfuitsluiting voor een account instellen of verlengen, of ze opsommen |
DELETE | /v2/self-exclusions/{user_id} | Een zelfuitsluiting voortijdig opheffen |
Hun uitkomsten bereiken je ook als webhook-events:
transaction_state_changed, login_risk, trusted_device_enrolled,
trusted_device_revoked en affiliate_threshold_crossed.
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 je verzoek letterlijk is ingewilligd.curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/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:
{ "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" }}| Veld | Betekenis |
|---|---|
visits, incognito_visits | Totaal aantal bezoeken in het venster, en hoeveel daarvan in een privévenster waren |
unique_ips, unique_countries | Verschillende adressen en landen die in het venster zijn gezien |
browsers, os, devices | De verschillende omgevingen waarin deze bezoeker is verschenen |
risk.max_risk_score | De hoogste risicoscore die in het venster is vastgelegd, 0..100 |
risk.last_decision | De beslissing die voor het meest recente bezoek is vastgelegd |
risk.avg_bot_score, risk.bot_sessions | 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.proxy_detected_seen | Of ten minste één bezoek in het venster naar buiten kwam via een proxy of VPN vóór de browser — zie network.proxy_detected onder Apparaatfeiten |
network.last_isp | De meest recente ISP — vanaf Business |
network.last_real_ip | Het meest recente adres dat achter een proxy of VPN is waargenomen (address, country, isp) — vanaf Business; ontbreekt wanneer geen enkel bezoek er een meebracht |
last_session | 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 je
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 |
bot.type | Aanwezig wanneer bot.result bot is: ofwel een specifieke tool (playwright, puppeteer, selenium, jsdom, claude_computer_use…), ofwel een geverifieerde AI-agent (ai_agent:<vendor>), ofwel een familie wanneer de tool niet wordt benoemd — automation, headless, antidetect, extension, privacy_browser, impersonation, other |
decision.action | real, fake, suspicious |
bot.score en decision.risk_score 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.
Waarden en schalen komen overeen met de v3-webhookbody voor hetzelfde bezoek, en
guidance wordt volgens dezelfde regels berekend.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions?limit=100&min_risk_score=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 |
bot_result | — | Houd alleen sessies met dit bot-verdict over |
min_risk_score | — | Houd alleen sessies op of boven deze risicoscore over, 0..100 |
Sessies komen terug met de nieuwste eerst:
{ "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" }}Bladeren gaat op basis van een cursor. Er is geen parameter page of offset: geef de
next_cursor die je hebt ontvangen terug als cursor, en ga door zolang has_more
waar is. De laatste pagina bevat next_cursor mogelijk helemaal niet, dus maak dat
veld niet verplicht.
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}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.
Naast de browser en het besturingssysteem uit de User-Agent draagt een sessie wat de browser van de bezoeker over de machine meldt, aan onze kant opgeschoond. Elk veld ontbreekt wanneer het bezoek geen dergelijke gegevens meebracht, dus behandel elk als optioneel.
| Veld | Betekenis |
|---|---|
gpu | Model van de videoadapter zoals de browser die meldt (WebGL), genormaliseerd naar een leesbare naam — Intel Iris Xe Graphics, Apple M1 Pro, Qualcomm Adreno 830; Software renderer betekent geen echte GPU (een virtuele machine of een headless omgeving); Safari meldt Apple GPU |
network.proxy_detected | Het HTTP-verkeer van het bezoek en de rauwe netwerkpaden ervan komen via verschillende netwerken naar buiten — een proxy of VPN vóór de browser; twee adressen van dezelfde provider (carrier-NAT, een tweede uitgang van hetzelfde VPN) tellen niet mee; niet gemeld wanneer de adressen niet te vergelijken zijn (iCloud Private Relay, IPv4 naast IPv6) |
network.real_ip.address, .country, .isp | Het publieke adres dat op het rauwe netwerkpad is waargenomen, dat wil zeggen het adres achter de proxy of VPN, met het bijbehorende land en de ISP — vanaf Business; ontbreekt wanneer zo'n adres niet is waargenomen (country en isp ontbreken wanneer ze niet konden worden herleid) |
device_info.device_id, .cross_browser, .confidence, .linked_browsers | Aanwezig wanneer een apparaatidentiteit is vastgesteld: een stabiele id van het fysieke apparaat over de browsers erop heen, of dit bezoek via een andere browser kwam dan eerder, de betrouwbaarheid van die match en hoeveel verschillende bezoekers (browsers) het apparaat delen — meer dan één betekent één machine onder meerdere browseridentiteiten — vanaf Business |
os_environment | De desktopomgeving die op een Linux-machine is gemeten (Mint 22+, Ubuntu 25.04+, Ubuntu, GNOME, KDE) — vanaf Business; ontbreekt wanneer die niet is vastgesteld |
spoofing | Wat het bezoek beweerde, tegenover wat onafhankelijke controles hebben gemeten (claimed, real, spoofed_axes uit os, gpu, screen, network, browser; anonymous_browser met productnamen) — vanaf Business; alleen aanwezig wanneer er een spoof is gedetecteerd |
screen.width, .height, .color_depth, .pixel_ratio | Schermresolutie, kleurdiepte en device pixel ratio zoals de browser die meldt — vanaf Business |
locale.languages, locale.timezone | De eigen voorkeurstalen en tijdzone van de browser — in tegenstelling tot geo.timezone, dat uit het IP-adres wordt afgeleid; een verschil tussen die twee is een veelvoorkomend teken van een vervalste locatie — vanaf Business |
client_hints.architecture, .bitness, .model, .device_name, .platform_version | User-Agent Client Hints: CPU-architectuur en bitness, apparaatmodelcode (Android, bijv. SM-A556B) met de marketingnaam ervan uit de Google Play-apparaatlijst (device_name, bijv. Samsung Galaxy A55 5G) en de exacte platformversie; alleen Chromium-gebaseerde browsers — vanaf Business |
environment.virtual_machine, environment.hypervisor | Alleen aanwezig wanneer de videoadapter zichzelf als virtueel bekendmaakte; hypervisor is een gesloten woordenboek (vmware, virtualbox, parallels, qemu, hyperv, bochs, intel-gvt, vgpu). Een ontbrekend blok betekent dat er geen dergelijke aanwijzing is — vanaf Business |
extensions somt de browserextensies op die tijdens het bezoek zijn gedetecteerd — vanaf Pro.
Elke vermelding is een object:
| Veld | Betekenis |
|---|---|
slug | Stabiele, machineleesbare identificatie van de extensie, dezelfde waarde die de webhook levert |
name | Voor mensen leesbare naam |
category | Grove klasse — adblock, privacy, automation, wallet, vpn, devtools, other, enzovoort |
risky | true voor extensies die in verband worden gebracht met automatisering, spoofing of diefstal van inloggegevens |
store_url | Link naar de storevermelding van de extensie, wanneer die bekend is |
Een bevinding wordt pas gemeld nadat die onze betrouwbaarheidscontroles heeft doorstaan — een omgeving die op elke test “geïnstalleerd” antwoordt, of een reeks van meer dan twaalf namen, wordt als onbetrouwbaar verworpen. Een lege of ontbrekende lijst betekent daarom “niets wat wij konden bevestigen”, niet “geen extensies geïnstalleerd”. Lees hem als aanwijzing, niet als inventaris.
fields bevat de aangepaste sleutel-waardeparen die jouw integratie aan het bezoek heeft gekoppeld:
een orderreferentie, een abonnementsnaam, de uitkomst van een betaling. Sleutels en waarden zijn
altijd strings: een gekoppeld getal of booleaanse waarde komt terug als tekst. Net als de rest van
de sessie is het beschikbaar op elk abonnement met API-toegang (vanaf Pro) en ontbreekt het wanneer
het bezoek geen velden heeft.
fields wordt bij elk verzoek live gelezen, niet gekopieerd op het moment van het bezoek. Velden
die na het bezoek zijn gekoppeld (zie Velden na het bezoek koppelen)
verschijnen hier ook, dus voor hetzelfde bezoek kan fields meer bevatten dan de webhook heeft
geleverd.
Zet geen persoonsgegevens, zoals namen, e-mailadressen of telefoonnummers, in aangepaste velden: koppel in plaats daarvan een referentie die jouw eigen systemen kunnen herleiden, en stuur wie het account is als accountrecord (hieronder).
account is je record voor het account achter het bezoek — wat je voor die account_id het laatst
hebt gestuurd via POST /v2/accounts/metadata:
{ "account": { "id": "user-42", "email": "ann@example.com", "display_name": "Ann Lee" }}| Veld | Beschrijving |
|---|---|
id | Je account-ID — dezelfde waarde als account_id |
email | Het e-mailadres dat je voor het account hebt gestuurd; ontbreekt als leeg |
display_name | De weergavenaam die je voor het account hebt gestuurd; ontbreekt als leeg |
Het record wordt bij elk verzoek live gelezen, dus een naamswijziging verschijnt ook bij oude bezoeken: het blok beschrijft het account zoals het nu is, niet zoals het was op het moment van het bezoek. Het is beschikbaar op elk abonnement met API-toegang (vanaf Pro). Labels die je met het record hebt gestuurd, worden niet teruggegeven.
Het blok ontbreekt wanneer het bezoek geen gekoppeld account heeft, wanneer er geen record voor bestaat (of je het hebt gewist door lege waarden te sturen), en — zelden — wanneer het record niet kon worden gelezen: de sessie wordt dan toch volledig teruggegeven in plaats van het verzoek te laten mislukken, dus behandel een ontbrekend blok als “onbekend”, niet als “dit account heeft geen e-mailadres”. Webhooks dragen dit blok niet.
De meest recente:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/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 request_id, de identificatie die ook in de webhook-payload verschijnt:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/sessions/9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31?visitor_id=X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"visitor_id is hier optioneel, maar hem meegeven wanneer je hem kent, maakt het opzoeken
merkbaar sneller.
identification.drift_score — de afgevlakte gedragsscore waarop het verdict over accountovername
is gebaseerd, vanaf Business — wordt alleen door deze leesactie van één sessie teruggegeven.
Gedragsdrift wordt tijdens het bezoek gemeten, na de eerste identificatie, dus de routes voor de
lijst en de laatste sessie laten hem weg. Een bezoek waarvan het gedrag nooit is beoordeeld, heeft
geen drift_score. Dezelfde waarde bereikt je via de webhook account_takeover.
Een bezoek kan meer dan eens per webhook worden geleverd: eerst primary, daarna late of
correction naarmate tragere signalen en gedragsbewijs binnenkomen — en een latere fase kan het
eerdere verdict omverwerpen. De Data API antwoordt vanuit het primary-record. Latere fasen
worden er niet in teruggevoegd, dus voor een gecorrigeerd bezoek is de laatste webhook het nieuwere
antwoord. Handel je minuten na het bezoek, geef dan de voorkeur aan de fase die je het laatst hebt
ontvangen boven een verse leesactie hier.
Eén ding werkt andersom: zodra de detector voor accountovername voor een bezoek is afgegaan,
weerspiegelt guidance hier dat, terwijl identification-webhookbody's van hetzelfde bezoek die
as niet dragen — die gaat mee met de aparte levering account_takeover.
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/v2/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, "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 telt de verschillende linkedId-waarden die je voor dit apparaat hebt
gestuurd — zie Accounts koppelen. bot_events is vanaf
Business; op Pro ontbreekt de sleutel.
TRACIO kent je accounts alleen via de ID die jouw site als linkedId doorgeeft — een ondoorzichtige
string zoals usr_8412. Stuur de leesbare labels één keer, en elk dashboardscherm dat dat account
toont, laat de naam of het e-mailadres zien in plaats van de kale ID, en het sessie-object geeft ze
terug in zijn blok account. Niets hiervan beïnvloedt detectie of scoring; het
is een weergavelaag.
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. Een e-mailadres of een
naam die je hier stuurt, leeft alleen in het accountrecord van je workspace: het wordt niet per
bezoek opgeslagen, niet in de pagina geschreven, en één verzending werkt elk bezoek van dat
account bij.400 invalid_request, en één foute vermelding laat
de hele batch weigeren — de fout noemt de positie ervan. Dubbele account-ID's in één batch zijn
geen probleem: de laatste wint.Limieten: 1.000 accounts per verzoek, body van 1 MiB, account_id ≤ 256 tekens,
email ≤ 320, display_name ≤ 256, maximaal 16 labels met sleutels ≤ 64 en waarden
≤ 256 tekens.
De browser kan alleen sturen wat de pagina bij het renderen weet — een order-ID, nooit de uitkomst van een betalingscontrole of iets anders dat later pas vaststaat. Deze route vult dat gat: vind het bezoek aan de hand van een veld dat het al draagt, en koppel er aan de serverkant meer velden aan.
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 vindt het bezoek aan de hand van een veld dat het al heeft, niet op request_id,
binnen de workspace en omgeving van je sleutel.404 not_found — schrijf het veld kort
nadat de uitkomst vaststaat.updated telt verschillende bezoeken. Het komt alleen boven 1 wanneer jouw match meer dan één
bezoek treft — een sleutel-waardepaar dat niet uniek is voor één order of winkelwagen. Een match
die meer dan 100 events treft, wordt geweigerd met 400 invalid_request in plaats van te worden
toegepast op een willekeurige deelverzameling.server, en hebben
voorrang op een waarde met dezelfde sleutel die door de browser is geschreven.404 not_found, geen lege 200.Limieten zijn gelijk aan die van het browserkanaal: 50 velden per aanroep, sleutels ≤ 40 bytes,
waarden ≤ 500 bytes — bytes, geen tekens — tekenset voor sleutels A-Za-z0-9_.:-, body van
1 MiB.
Wist aangepaste velden — nooit het bezoek zelf. Gebruik het voor waarden die je niet langer aan een bezoek gekoppeld wilt hebben, zoals een ordertotaal. Al verzonden webhooks en al gemaakte exports worden niet gewijzigd.
# 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 en match sluiten elkaar uit — beide sturen, of geen van beide, is
400 invalid_request. match gebruikt hetzelfde venster van 24 uur en hetzelfde plafond van
100 events als het koppelen.deleted telt de velden die van het bezoek zijn verwijderd (op request_id) of de bezoeken
waarvan het veld is verwijderd (op match).404 not_found.Dezelfde lijsten die jouw operators in het dashboard beheren, bereikbaar vanuit je eigen backoffice.
Het type van een lijst is de actie ervan op een overeenkomend bezoek — block,
manual_review, challenge, allow — en de modus bepaalt of de actie wordt toegepast:
observe telt alleen overeenkomsten, enforce past haar toe op guidance (de as list). Lijsten
en hun modus worden in het dashboard aangemaakt; de Data API leest lijsten en voegt vermeldingen
toe en verwijdert ze.
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"}Verwijder een vermelding met dezelfde body via POST /v2/lists/{list_id}/entries/delete; het
antwoord is { "removed": true, "propagation": "immediate" }.
value_type is waartegen de waarde wordt vergeleken: linked_id, visitor_id,
device_id, ip, cidr of country. Een waarde die voor haar type niet te parsen is, geeft
400 invalid_request.linked_id →
visitor_id → device_id → ip → cidr → country — en daarbinnen wint de strengste actie.ttl_minutes is optioneel. Weggelaten geldt de standaard-TTL van de lijst; zonder die verloopt
de vermelding nooit (expires_at is null). Een vermelding opnieuw toevoegen verlengt haar.propagation zegt wanneer de wijziging actief is: immediate, of ttl — binnen ongeveer
vijf minuten.200 met removed: false; 404 is
voorbehouden aan een onbekende lijst.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 match_confidence, een schoon bezoek heeft geen
antidetect_score of suspect_score. De ene bewuste uitzondering is bot.score, dat
altijd aanwezig is, zelfs wanneer het nul is. Lees velden defensief.
De payload hangt af van je abonnement. API-toegang begint bij Pro, en Pro krijgt de basissessie
— identificaties, tijdstempel, URL, IP, user agent, browser, besturingssysteem, apparaat, geo,
netwerk, bot, identificatie en beslissing — samen met identification.match_type,
identification.match_confidence, bot.score, bot.type, bot.antidetect_score, gpu,
network.proxy_detected, extensions, fields en account. Business en Enterprise voegen
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 en environment toe. De velden op
persoonsniveau (person_id, reputation, linked_accounts_count, linked_visitors_count) zijn
voorbehouden aan Business en Enterprise en verschijnen zodra de persoonslaag is ingeschakeld —
vandaag draait die in observatiemodus en worden deze velden niet geleverd. 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>", "request_id": "8f14e45fceea167a5a36dedd" }}Deze request_id is niet de identificatie van het bezoek. Twee verschillende
waarden delen de naam: binnen een sessie-payload is request_id 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 je contact opneemt met support — zo vinden wij precies je 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 | Je abonnement bevat geen API-toegang |
| 404 | not_found | Er kwam niets overeen binnen het bewaarvenster, of het hoort bij een andere omgeving |
| 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. Gegevens uit een andere workspace zijn niet te onderscheiden van gegevens
die niet bestaan: ze leveren 404 op, geen 403.
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.
Probeer 429 en 503 opnieuw met een groeiende pauze; andere 4xx opnieuw proberen heeft geen
zin — ze betekenen dat het verzoek zelf moet worden gecorrigeerd.
Responses waarvoor de sleutel is herkend, dragen je huidige stand (401- en 402-responses niet,
en Enterprise, zonder dagelijkse quota, krijgt geen quotaheaders):
| Header | Betekenis |
|---|---|
X-RateLimit-Limit | Je dagelijkse quota; bij een weigering per seconde de limiet per seconde |
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 — houd je eraan: het klopt voor beide limieten |
| 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 |