Mit der Data API (hier früher als Server API dokumentiert) kann Ihr Backend die Identifikationsdaten lesen, die TRACIO für Ihren Workspace bereits erfasst hat: die Historie eines Besuchers, einzelne Sessions und Velocity-Zähler über kurze Fenster. Einige Routen schreiben auch — Kontodatensätze, benutzerdefinierte Felder und Listeneinträge —, damit Ihr Backend das Wissen von TRACIO anreichern kann.
Sie ergänzt Webhooks, statt sie zu ersetzen:
| Webhooks | Data API | |
|---|---|---|
| Richtung | TRACIO sendet an Ihren Endpunkt | Ihr Backend ruft bei Bedarf ab |
| Zeitpunkt | Sobald eine Identifikation stattfindet | Jederzeit, innerhalb Ihres Aufbewahrungsfensters |
| Am besten für | Auf ein Ereignis reagieren | Daten während einer Entscheidung nachschlagen, Nacherfassungen, Untersuchungen |
Beide Schnittstellen sind ab dem Tarif Pro verfügbar.
https://api.tracio.ai/v2Das ist ein anderer Host als der Browser-Endpunkt (edge.tracio.ai) und als das
Dashboard (app.tracio.ai). Alle drei sind getrennt: Der Browser spricht mit dem Edge
über Ihren öffentlichen Schlüssel, Ihr Backend spricht mit der Data API über
Ihren geheimen Schlüssel.
Die Routen unter /v1 wurden entfernt. Verwenden Sie /v2: Die Routen sind dieselben,
und jeder JSON-Schlüssel und jeder Query-Parameter ist in snake_case (visitor_id,
risk_score, min_risk_score). Schlüssel innerhalb Ihrer eigenen Wörterbücher
fields und labels sind Ihre Daten und behalten ihre ursprüngliche Schreibweise.
Das JavaScript-SDK behält seine camelCase-Schnittstelle.
Jede Anfrage trägt Ihren geheimen Schlüssel als Bearer-Token:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Die Data API ist ausschließlich Server-zu-Server. CORS-Header werden bewusst nicht zurückgegeben, sodass ein Browser sie nicht aufrufen kann — genau das hält Ihren geheimen Schlüssel aus clientseitigem Code heraus. Liefern Sie den geheimen Schlüssel niemals an den Browser aus.
Legen Sie ihn im Dashboard unter API Keys an und wählen Sie dabei den Typ secret.
tracio_sk_ gefolgt von 43 Zeichen, insgesamt 53. Das Dashboard listet ihn anhand seiner ersten Zeichen auf, damit Sie Schlüssel
auseinanderhalten können.404, genau wie bei Daten, die nicht
existieren.Beim Rotieren wird ein neuer Schlüssel ausgegeben, während der alte noch 7 Tage funktioniert, sodass Sie ihn ohne Ausfallzeit ausrollen können. Rollen Sie den neuen Schlüssel aus, prüfen Sie, dass der Traffic umgezogen ist, und lassen Sie den alten ablaufen. Öffentliche Schlüssel sind nicht rotierbar — sie sind keine Secrets und stehen bewusst sichtbar im Quelltext Ihrer Seite.
| Methode | Pfad | Liefert |
|---|---|---|
GET | /v2/visitors/{visitor_id} | Aggregierte Historie eines Besuchers plus dessen jüngste Session |
GET | /v2/visitors/{visitor_id}/sessions | Paginierte Liste der Sessions dieses Besuchers |
GET | /v2/visitors/{visitor_id}/sessions/latest | Die einzelne jüngste Session |
GET | /v2/visitors/{visitor_id}/velocity | Aktivitätszähler über ein kurzes Fenster |
GET | /v2/sessions/{request_id} | Eine Session anhand ihrer Request-Kennung |
POST | /v2/accounts/metadata | Anzeigenamen und E-Mail-Adressen an Ihre Konto-IDs hängen |
POST | /v2/events/fields | Benutzerdefinierte Felder nach dem Laden der Seite an einen Besuch hängen |
POST | /v2/events/fields/delete | Benutzerdefinierte Felder von einem Besuch löschen — der Besuch selbst bleibt unberührt |
GET | /v2/lists | Ihre Workspace-Listen: ID, Name, Typ (die Aktion), Modus, Anzahl der Einträge |
POST | /v2/lists/{list_id}/entries | Einen Wert zu einer Liste hinzufügen, optional mit TTL |
POST | /v2/lists/{list_id}/entries/delete | Einen Wert aus einer Liste entfernen |
GET | /.well-known/webhook-keys | Öffentliche Schlüssel für die Plattform-Signatur der Webhooks (ohne Auth) |
Derselbe Schlüssel und derselbe Host bedienen auch die Entscheidungs-APIs, alle in snake_case:
| Methode | Pfad | Zweck |
|---|---|---|
POST | /v2/transactions | Eine synchrone Entscheidung APPROVE / REVIEW / DECLINE zu einem Geschäftsereignis — ab Business, außer bei einer Affiliate-Conversion (account_register oder deposit mit affiliate_id), die in jedem Tarif mit API-Zugang verfügbar ist |
GET | /v2/transactions/{transaction_id} | Eine Entscheidung mit ihrem Label und ihrem effektiven Zustand erneut lesen — ab Business, außer bei einer Transaktion, die einem Affiliate zugeordnet ist |
PUT, DELETE | /v2/transaction-labels | Das Ergebnis-Label von bis zu 50 Transaktionen setzen oder entfernen — ab Business |
GET | /v2/transaction-labels/value-set | Die akzeptierten Label-Werte mit ihrer Polarität — ab Business |
POST | /v2/logins/assess | Einen Login bewerten: allow / challenge / review / deny mit Begründungen |
POST, GET | /v2/accounts/{user_id}/trusted-devices | Dem Gerät eines Besuchs nach Ihrem Step-up für ein Konto vertrauen oder die vertrauenswürdigen Geräte des Kontos auflisten |
DELETE | /v2/accounts/{user_id}/trusted-devices/{device_ref} | Das Vertrauen in ein Gerät widerrufen |
GET | /v2/affiliates/{affiliate_id} | Der Qualitätsbericht eines Affiliates über 90 Tage, mit einer Empfehlung hold / review |
POST, GET | /v2/self-exclusions | Eine Selbstsperre für ein Konto setzen oder verlängern oder die Selbstsperren auflisten |
DELETE | /v2/self-exclusions/{user_id} | Eine Selbstsperre vorzeitig aufheben |
Ihre Ergebnisse erreichen Sie auch als Webhook-Ereignisse:
transaction_state_changed, login_risk, trusted_device_enrolled,
trusted_device_revoked und affiliate_threshold_crossed.
Ein abschließender Schrägstrich wird akzeptiert und ignoriert. Ein unbekannter Pfad oder eine falsche Methode liefert denselben JSON-Fehler-Envelope wie alles andere, niemals eine HTML- oder Klartext-Seite.
Jeder Lesezugriff ist durch ein Zeitfenster begrenzt, gesteuert über zwei optionale Query-Parameter:
| Parameter | Akzeptiert |
|---|---|
from | YYYY-MM-DD oder einen vollständigen RFC-3339-Zeitstempel |
to | YYYY-MM-DD oder einen vollständigen RFC-3339-Zeitstempel |
to schließt den gesamten Tag ein.400 invalid_request und der Meldung
time must be YYYY-MM-DD or RFC3339 abgelehnt.meta
zurückgemeldet — prüfen Sie also meta.from und meta.to, statt anzunehmen, dass
Ihre Anfrage wortwörtlich erfüllt wurde.curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Die Antwort trägt die aggregierte Historie und bettet die jüngste Session ein, sodass der häufige Fall eine statt zwei Anfragen braucht:
{ "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" }}| Feld | Bedeutung |
|---|---|
visits, incognito_visits | Besuche insgesamt im Fenster und wie viele davon in einem privaten Fenster stattfanden |
unique_ips, unique_countries | Unterschiedliche Adressen und Länder, die im Fenster gesehen wurden |
browsers, os, devices | Die unterschiedlichen Umgebungen, in denen dieser Besucher aufgetreten ist |
risk.max_risk_score | Der höchste im Fenster erfasste Risiko-Score, 0..100 |
risk.last_decision | Die für den jüngsten Besuch erfasste Entscheidung |
risk.avg_bot_score, risk.bot_sessions | Durchschnittlicher Bot-Score und die Anzahl der Bot-Sessions — ab Business |
network.*_seen | Ob für diesen Besucher jemals ein VPN, ein Proxy, ein Tor-Exit-Node oder eine Rechenzentrums-Adresse gesehen wurde |
network.proxy_detected_seen | Ob mindestens ein Besuch im Fenster über einen Proxy oder ein VPN vor dem Browser ausgetreten ist — siehe network.proxy_detected unter Gerätefakten |
network.last_isp | Der jüngste ISP — ab Business |
network.last_real_ip | Die jüngste Adresse, die hinter einem Proxy oder VPN beobachtet wurde (address, country, isp) — ab Business; fehlt, wenn kein Besuch eine solche Adresse mitbrachte |
last_session | Das vollständige Session-Objekt des jüngsten Besuchs |
meta | Der Tarif, seine Aufbewahrung in Tagen und das tatsächlich angewandte Fenster |
Ein Besucher ohne Daten innerhalb des Aufbewahrungsfensters liefert 404 not_found mit
der Meldung visitor not found in the retention window — das ist kein Fehler in Ihrer
Integration, es bedeutet, dass der Besucher neu ist oder herausgefallen ist.
Die Session trägt zwei Verdicts, und sie beantworten unterschiedliche Fragen — ob der Client automatisiert war und was die Risiko-Engine insgesamt geschlossen hat:
| Feld | Werte |
|---|---|
bot.result | human, bot, uncertain |
bot.type | Vorhanden, wenn bot.result gleich bot ist: entweder ein konkretes Tool (playwright, puppeteer, selenium, jsdom, claude_computer_use…), ein verifizierter KI-Agent (ai_agent:<vendor>) oder eine Familie, wenn das Tool nicht benannt ist — automation, headless, antidetect, extension, privacy_browser, impersonation, other |
decision.action | real, fake, suspicious |
bot.score und decision.risk_score laufen beide von 0..100. Ab Business macht
guidance daraus Empfehlungen je Szenario auf der Leiter
allow → challenge → review → deny — siehe
Guidance für die Bedeutung jeder Stufe.
Werte und Skalen entsprechen dem v3-Webhook-Body für denselben Besuch, und guidance
wird nach denselben Regeln berechnet.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions?limit=100&min_risk_score=50"| Parameter | Standard | Hinweise |
|---|---|---|
limit | 50 | Bei 500 gedeckelt; ein größerer Wert wird beschnitten, nicht abgelehnt |
from, to | Tarif-Aufbewahrung | Das oben beschriebene gemeinsame Zeitfenster |
cursor | — | Undurchsichtiger Paginierungs-Cursor von der vorherigen Seite |
bot_result | — | Nur Sessions mit diesem Bot-Verdict behalten |
min_risk_score | — | Nur Sessions ab diesem Risiko-Score behalten, 0..100 |
Sessions kommen mit der neuesten zuerst zurück:
{ "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" }}Das Blättern ist cursorbasiert. Es gibt keinen Parameter page oder offset:
Übergeben Sie den erhaltenen next_cursor als cursor und machen Sie weiter, solange
has_more wahr ist. Die letzte Seite enthält next_cursor womöglich gar nicht —
machen Sie dieses Feld also nicht zur Pflicht.
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}Behandeln Sie den Cursor als undurchsichtig — sein Inhalt ist ein
Implementierungsdetail und kann sich ändern. Ein bearbeiteter Cursor wird mit
400 invalid_request und der Meldung malformed cursor abgelehnt.
Neben dem Browser und dem Betriebssystem aus dem User-Agent trägt eine Session das, was der Browser des Besuchers über die Maschine meldet, auf unserer Seite bereinigt. Jedes Feld fehlt, wenn der Besuch keine solchen Daten mitbrachte — behandeln Sie daher jedes als optional.
| Feld | Bedeutung |
|---|---|
gpu | Modell des Grafikadapters, wie es der Browser meldet (WebGL), normalisiert auf einen lesbaren Namen — Intel Iris Xe Graphics, Apple M1 Pro, Qualcomm Adreno 830; Software renderer bedeutet keine echte GPU (eine virtuelle Maschine oder eine Headless-Umgebung); Safari meldet Apple GPU |
network.proxy_detected | Der HTTP-Verkehr des Besuchs und seine rohen Netzwerkpfade treten über verschiedene Netze aus — ein Proxy oder VPN vor dem Browser; zwei Adressen desselben Anbieters (Carrier-NAT, ein zweiter Ausgang desselben VPN) zählen nicht; wird nicht gesetzt, wenn sich die Adressen nicht vergleichen lassen (iCloud Private Relay, IPv4 neben IPv6) |
network.real_ip.address, .country, .isp | Die öffentliche Adresse, die auf dem rohen Netzwerkpfad beobachtet wurde, also die Adresse hinter dem Proxy oder VPN, mit ihrem Land und ihrem ISP — ab Business; fehlt, wenn keine solche Adresse beobachtet wurde (country und isp fehlen, wenn sie nicht aufgelöst werden konnten) |
device_info.device_id, .cross_browser, .confidence, .linked_browsers | Vorhanden, wenn eine Geräteidentität aufgelöst wurde: eine stabile ID des physischen Geräts über die Browser darauf hinweg, ob dieser Besuch über einen anderen Browser als zuvor kam, die Konfidenz dieser Übereinstimmung und wie viele unterschiedliche Besucher (Browser) sich das Gerät teilen — mehr als einer bedeutet eine Maschine unter mehreren Browser-Identitäten — ab Business |
os_environment | Die auf einem Linux-Rechner gemessene Desktop-Umgebung (Mint 22+, Ubuntu 25.04+, Ubuntu, GNOME, KDE) — ab Business; fehlt, wenn nicht bestimmt |
spoofing | Was der Besuch behauptet hat, verglichen mit dem, was unabhängige Prüfungen gemessen haben (claimed, real, spoofed_axes aus os, gpu, screen, network, browser; anonymous_browser mit Produktnamen) — ab Business; nur vorhanden, wenn ein Spoof erkannt wurde |
screen.width, .height, .color_depth, .pixel_ratio | Bildschirmauflösung, Farbtiefe und Device Pixel Ratio, wie sie der Browser meldet — ab Business |
locale.languages, locale.timezone | Die vom Browser selbst bevorzugten Sprachen und die Zeitzone — im Unterschied zu geo.timezone, das aus der IP-Adresse abgeleitet wird; eine Abweichung zwischen beiden ist ein häufiges Anzeichen für einen vorgetäuschten Standort — ab Business |
client_hints.architecture, .bitness, .model, .device_name, .platform_version | User-Agent Client Hints: CPU-Architektur und Bitness, Gerätemodellcode (Android, z. B. SM-A556B) mit seinem Marketingnamen aus der Google-Play-Geräteliste (device_name, z. B. Samsung Galaxy A55 5G) und die genaue Plattformversion; nur Chromium-basierte Browser — ab Business |
environment.virtual_machine, environment.hypervisor | Nur vorhanden, wenn sich der Grafikadapter selbst als virtuell zu erkennen gegeben hat; hypervisor ist ein geschlossenes Wörterbuch (vmware, virtualbox, parallels, qemu, hyperv, bochs, intel-gvt, vgpu). Ein fehlender Block bedeutet, dass es keinen solchen Hinweis gibt — ab Business |
extensions listet die während des Besuchs erkannten Browser-Erweiterungen auf — ab Pro.
Jeder Eintrag ist ein Objekt:
| Feld | Bedeutung |
|---|---|
slug | Stabile maschinenlesbare Kennung der Erweiterung, derselbe Wert, den der Webhook liefert |
name | Menschenlesbarer Name |
category | Grobe Klasse — adblock, privacy, automation, wallet, vpn, devtools, other und so weiter |
risky | true für Erweiterungen, die mit Automatisierung, Spoofing oder dem Diebstahl von Zugangsdaten in Verbindung stehen |
store_url | Link zum Store-Eintrag der Erweiterung, sofern bekannt |
Ein Fund wird erst gemeldet, nachdem er unsere Vertrauensprüfungen bestanden hat — eine Umgebung, die auf jede Sonde mit „installiert“ antwortet, oder ein Stapel von mehr als zwölf Namen wird als unzuverlässig verworfen. Eine leere oder fehlende Liste bedeutet daher „nichts, was wir bestätigen konnten“, nicht „keine Erweiterungen installiert“. Lesen Sie sie als Indiz, nicht als Inventar.
fields enthält die benutzerdefinierten Schlüssel-Wert-Paare, die Ihre Integration dem Besuch angehängt hat — eine Bestellreferenz, einen Tarifnamen, ein Zahlungsergebnis. Schlüssel und Werte sind immer Zeichenketten: Eine angehängte Zahl oder ein boolescher Wert kommt in Textform zurück. Wie der Rest der Session ist das Feld in jedem Tarif mit API-Zugang verfügbar (ab Pro) und fehlt, wenn der Besuch keine Felder trägt.
fields wird bei jeder Anfrage live gelesen und nicht zum Zeitpunkt des Besuchs kopiert. Felder, die nach dem Besuch angehängt wurden (siehe Felder nach dem Besuch anhängen), erscheinen ebenfalls hier, daher kann fields für denselben Besuch mehr enthalten, als der Webhook geliefert hat.
Legen Sie keine personenbezogenen Daten wie Namen, E-Mail-Adressen oder Telefonnummern in benutzerdefinierten Feldern ab — hängen Sie stattdessen eine Referenz an, die Ihre eigenen Systeme auflösen können, und senden Sie, wer hinter dem Konto steht, als Kontodatensatz (siehe unten).
account ist Ihr Datensatz zum Konto hinter dem Besuch — das, was Sie zuletzt für
diese account_id über POST /v2/accounts/metadata gesendet haben:
{ "account": { "id": "user-42", "email": "ann@example.com", "display_name": "Ann Lee" }}| Feld | Beschreibung |
|---|---|
id | Ihre Konto-ID — derselbe Wert wie account_id |
email | Die E-Mail-Adresse, die Sie für das Konto gesendet haben; fehlt, wenn leer |
display_name | Der Anzeigename, den Sie für das Konto gesendet haben; fehlt, wenn leer |
Der Datensatz wird bei jeder Anfrage live gelesen, eine Umbenennung erscheint also auch bei alten Besuchen: Der Block beschreibt das Konto so, wie es jetzt ist, nicht so, wie es zum Zeitpunkt des Besuchs war. Er ist in jedem Tarif mit API-Zugang verfügbar (ab Pro). Labels, die Sie mit dem Datensatz gesendet haben, werden nicht zurückgegeben.
Der Block fehlt, wenn der Besuch kein verknüpftes Konto hat, wenn es keinen Datensatz dafür gibt (oder Sie ihn durch das Senden leerer Werte gelöscht haben) und — selten —, wenn der Datensatz nicht gelesen werden konnte: Die Session wird trotzdem vollständig zurückgegeben, statt die Anfrage scheitern zu lassen. Behandeln Sie einen fehlenden Block daher als „unbekannt“, nicht als „dieses Konto hat keine E-Mail“. Webhooks tragen diesen Block nicht.
Die jüngste:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions/latest"Das liefert ein nacktes Session-Objekt — kein Array und nicht in einen Envelope
verpackt. Ein Besucher ohne Sessions im Fenster liefert 404 not_found mit
no sessions for this visitor in the retention window.
Oder anhand der request_id, der Kennung, die auch im Webhook-Payload auftaucht:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/sessions/9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31?visitor_id=X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"visitor_id ist hier optional, aber sie mitzugeben, wenn Sie sie kennen, macht die
Suche deutlich schneller.
identification.drift_score — der geglättete Verhaltens-Score, auf dem das Verdict zur
Kontoübernahme beruht, ab Business — wird nur von diesem Lesezugriff auf eine einzelne
Session zurückgegeben. Die Verhaltensdrift wird während des Besuchs gemessen, nach der
ersten Identifikation, daher lassen die Routen für Liste und jüngste Session sie weg.
Ein Besuch, dessen Verhalten nie bewertet wurde, hat keinen drift_score. Derselbe
Wert erreicht Sie über den Webhook account_takeover.
Ein Besuch kann per Webhook mehr als einmal zugestellt werden: zuerst primary, dann
late oder correction, sobald langsamere Signale und Verhaltensindizien eintreffen —
und eine spätere Phase kann das frühere Verdict umstoßen. Die Data API antwortet aus
dem Datensatz primary. Spätere Phasen werden nicht in ihn zurückgeführt, für einen
korrigierten Besuch ist daher der letzte Webhook die neuere Antwort. Wenn Sie Minuten
nach dem Besuch handeln, ziehen Sie die zuletzt erhaltene Phase einem frischen
Lesezugriff hier vor.
Eines läuft in die andere Richtung: Sobald der Detektor für Kontoübernahmen bei einem
Besuch angeschlagen hat, spiegelt guidance hier dies wider, während die
identification-Webhook-Bodys desselben Besuchs diese Achse nicht tragen — sie kommt
mit der eigenen Zustellung account_takeover.
Velocity beantwortet die Frage „wie viel hat dieser Besucher in letzter Zeit getan“ — die Form von Credential Stuffing, Card Testing und Massenregistrierungen.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/velocity?window=1h"window akzeptiert 1h, 24h oder 7d und ist standardmäßig 24h. Jeder andere
Wert wird mit 400 invalid_request und window must be one of: 1h, 24h, 7d abgelehnt.
{ "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 zählt die unterschiedlichen linkedId-Werte, die Sie für dieses Gerät
gesendet haben — siehe Account-Verknüpfung. bot_events gibt es
ab Business; im Pro-Tarif fehlt der Schlüssel.
TRACIO kennt Ihre Konten nur über die ID, die Ihre Website als linkedId übergibt — eine
undurchsichtige Zeichenkette wie usr_8412. Senden Sie die menschenlesbaren Angaben
einmal, und jede Dashboard-Ansicht, die dieses Konto zeigt, zeigt statt der rohen ID den
Namen oder die E-Mail-Adresse; das Session-Objekt gibt sie in seinem Block
account zurück. Nichts davon beeinflusst Erkennung oder Scoring;
es ist eine Anzeigeebene.
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. Eine
E-Mail-Adresse oder ein Name, hier gesendet, liegt nur im Kontodatensatz Ihres
Workspace: Sie werden nicht pro Besuch gespeichert, nicht in die Seite geschrieben,
und eine Sendung aktualisiert jeden Besuch dieses Kontos.400 invalid_request, und ein fehlerhafter
Eintrag lehnt den ganzen Batch ab — der Fehler nennt seine Position. Doppelte
Konto-IDs in einem Batch sind kein Problem: Der letzte Eintrag gewinnt.Limits: 1.000 Konten pro Anfrage, 1 MiB Body, account_id ≤ 256 Zeichen,
email ≤ 320, display_name ≤ 256, höchstens 16 Labels mit Schlüsseln ≤ 64 und Werten
≤ 256 Zeichen.
Der Browser kann nur senden, was die Seite zum Zeitpunkt des Renderns weiß — eine Bestell-ID, niemals das Ergebnis einer Zahlungsprüfung oder etwas anderes, das sich später entscheidet. Diese Route schließt diese Lücke: Finden Sie den Besuch über ein Feld, das er bereits trägt, und hängen Sie serverseitig weitere Felder an.
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 findet den Besuch über ein Feld, das er bereits hat, nicht über
request_id, innerhalb des Workspace und der Umgebung Ihres Schlüssels.404 not_found —
schreiben Sie das Feld bald, nachdem sich das Ergebnis entschieden hat.updated zählt unterschiedliche Besuche. Der Wert liegt nur dann über 1, wenn Ihr
match mehr als einen Besuch trifft — ein Schlüssel-Wert-Paar, das nicht nur zu einer
Bestellung oder einem Warenkorb gehört. Ein match, das mehr als 100 Ereignisse
trifft, wird mit 400 invalid_request abgewiesen, statt auf eine beliebige Teilmenge
angewandt zu werden.server und
haben Vorrang vor einem Wert mit demselben Schlüssel, den der Browser geschrieben hat.404 not_found, kein leeres 200.Die Limits entsprechen dem Browser-Kanal: 50 Felder pro Aufruf, Schlüssel ≤ 40 Bytes,
Werte ≤ 500 Bytes — Bytes, nicht Zeichen —, Zeichensatz der Schlüssel
A-Za-z0-9_.:-, 1 MiB Body.
Löscht benutzerdefinierte Felder — niemals den Besuch selbst. Verwenden Sie es für Werte, die Sie nicht mehr an einem Besuch brauchen, etwa eine Bestellsumme. Bereits gesendete Webhooks und bereits erstellte Exporte werden nicht geändert.
# 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 und match schließen sich gegenseitig aus — beide oder keines zu
senden ergibt 400 invalid_request. match verwendet dasselbe 24-Stunden-Fenster und
dieselbe Obergrenze von 100 Ereignissen wie das Anhängen.deleted zählt die vom Besuch entfernten Felder (bei request_id) oder die
Besuche, von denen das Feld entfernt wurde (bei match).404 not_found.Dieselben Listen, die Ihre Operatoren im Dashboard verwalten, erreichbar aus Ihrem
eigenen Backoffice. Der Typ einer Liste ist ihre Aktion bei einem passenden Besuch —
block, manual_review, challenge, allow —, und ihr Modus entscheidet, ob die
Aktion angewandt wird: observe zählt nur Treffer, enforce wendet sie auf guidance
an (die Achse list). Listen und ihr Modus werden im Dashboard angelegt; die Data API
liest Listen und fügt Einträge hinzu oder entfernt sie.
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"}Entfernen Sie einen Eintrag mit demselben Body über POST /v2/lists/{list_id}/entries/delete;
die Antwort lautet { "removed": true, "propagation": "immediate" }.
value_type gibt an, womit der Wert abgeglichen wird: linked_id, visitor_id,
device_id, ip, cidr oder country. Ein Wert, der sich für seinen Typ nicht
parsen lässt, ergibt 400 invalid_request.linked_id →
visitor_id → device_id → ip → cidr → country — und innerhalb davon gewinnt
die strengste Aktion.ttl_minutes ist optional. Fehlt es, gilt die Standard-TTL der Liste; gibt es
keine, läuft der Eintrag nie ab (expires_at ist null). Erneutes Hinzufügen eines
Eintrags verlängert ihn.propagation gibt an, wann die Änderung wirksam ist: immediate oder ttl —
innerhalb von etwa fünf Minuten.200 mit removed: false; 404
ist einer unbekannten Liste vorbehalten.Ein fehlendes Feld bedeutet „keine Daten“, niemals null. Felder ohne Wert werden
vollständig weggelassen statt als 0, "" oder null gesendet: Ein brandneuer
Besucher hat keine match_confidence, ein sauberer Besuch hat keinen antidetect_score
und keinen suspect_score. Die eine bewusste Ausnahme ist bot.score, das immer
vorhanden ist, selbst wenn es null ist. Lesen Sie Felder defensiv.
Der Payload hängt von Ihrem Tarif ab. Der API-Zugang beginnt bei Pro, und Pro erhält die Basis-Session — Kennungen, Zeitstempel, URL, IP, User Agent, Browser, Betriebssystem, Gerät, Geo, Netzwerk, Bot, Identifikation und Entscheidung — zusammen mit identification.match_type, identification.match_confidence, bot.score, bot.type, bot.antidetect_score, gpu, network.proxy_detected, extensions, fields und account. Business und Enterprise ergänzen 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 und environment. Die Felder auf Personenebene (person_id, reputation, linked_accounts_count, linked_visitors_count) sind Business und Enterprise vorbehalten und erscheinen, sobald die Personenebene aktiviert ist — heute läuft sie im Beobachtungsmodus, und diese Felder werden nicht geliefert. Das Fehlen eines Business-Feldes im Pro-Tarif ist kein Fehler.
Interna auf Signalebene werden nie zurückgegeben, in keinem Tarif: einzelne Signalnamen, ihre Gewichte, die Schwellenwerte hinter einem Verdict, rohe Signalwerte und Score-Aufschlüsselungen bleiben auf unserer Seite. Ein Score, der sich auf seine Eingaben zurückrechnen lässt, ist als Absicherung nicht mehr brauchbar.
Jeder Fehlschlag verwendet einen einzigen Envelope:
{ "error": { "code": "unauthorized", "message": "missing Authorization: Bearer <secret key>", "request_id": "8f14e45fceea167a5a36dedd" }}Diese request_id ist nicht die Kennung des Besuchs. Zwei verschiedene Werte teilen
sich den Namen: Innerhalb eines Session-Payloads ist request_id die UUID des Besuchs —
dieselbe, die der Webhook zustellt; innerhalb eines Fehler-Envelopes ist es eine
24-stellige Trace-Kennung, die pro HTTP-Aufruf erzeugt wird. Die Trace-Kennung kommt
außerdem im Header X-Request-Id bei jeder Antwort zurück, erfolgreich oder nicht.
Geben Sie sie an, wenn Sie den Support kontaktieren — so finden wir genau Ihren Aufruf.
| HTTP | code | Bedeutung |
|---|---|---|
| 400 | invalid_request | Ein Parameter fehlt oder ist fehlerhaft |
| 401 | unauthorized | Der Schlüssel fehlt, ist ungültig, widerrufen oder abgelaufen |
| 402 | upgrade_required | Ihr Tarif enthält keinen API-Zugang |
| 404 | not_found | Innerhalb des Aufbewahrungsfensters passte nichts, oder es gehört zu einer anderen Umgebung |
| 405 | method_not_allowed | Die Route existiert, aber nicht für diese Methode |
| 429 | rate_limited | Anfragen pro Sekunde oder das Tageskontingent überschritten |
| 500 | internal | Auf unserer Seite ist etwas fehlgeschlagen |
| 503 | unavailable | Ein zugrunde liegender Speicher ist vorübergehend nicht erreichbar |
Die Prüfungen laufen in fester Reihenfolge — Schlüssel, dann Tarif, dann Limits —,
sodass eine Anfrage mit einem falschen Schlüssel immer zuerst den Schlüssel meldet, nie
ein Kontingentproblem. Daten aus einem anderen Workspace sind von nicht existierenden
Daten nicht zu unterscheiden: Sie ergeben 404, nicht 403.
Zwei 401-Fälle lesen sich bewusst unterschiedlich: missing Authorization: Bearer <secret key>
bedeutet, dass der Header nie ankam, während invalid or revoked API key bedeutet, dass
er ankam und nicht passte. 402 trägt Data API requires the Pro plan or higher.
Wiederholen Sie 429 und 503 mit wachsender Pause; andere 4xx zu wiederholen ist
sinnlos — sie bedeuten, dass die Anfrage selbst korrigiert werden muss.
Antworten, bei denen der Schlüssel erkannt wurde, tragen Ihren aktuellen Stand
(401- und 402-Antworten nicht, und Enterprise ohne Tageskontingent erhält keine
Kontingent-Header):
| Header | Bedeutung |
|---|---|
X-RateLimit-Limit | Ihr Tageskontingent; bei einer Ablehnung pro Sekunde das Limit pro Sekunde |
X-RateLimit-Remaining | Heute verbleibende Aufrufe |
X-RateLimit-Reset | Unix-Zeit des Resets — Mitternacht UTC |
Retry-After | Wartezeit in Sekunden, nur mit einem 429 gesendet — richten Sie sich danach: Er stimmt für beide Limits |
| Tarif | Anfragen pro Sekunde | Anfragen pro Tag | Historientiefe |
|---|---|---|---|
| Free | Kein API-Zugang | — | 7 Tage |
| Pro | 10 | 10.000 | 30 Tage |
| Business | 50 | 100.000 | 90 Tage |
| Enterprise | 200 | Ohne Kontingent | 365 Tage |