La Data API (in precedenza documentata qui come Server API) consente al suo backend di leggere i dati di identificazione che TRACIO ha già raccolto per il suo workspace: la cronologia di un visitatore, le singole sessioni e i contatori di velocity su finestre brevi. Alcune rotte permettono anche di scrivere — record degli account, campi personalizzati e voci delle liste — così il suo backend può arricchire ciò che TRACIO sa.
Integra i Webhook invece di sostituirli:
| Webhook | Data API | |
|---|---|---|
| Direzione | TRACIO invia al suo endpoint | Il suo backend interroga su richiesta |
| Tempistica | Nel momento di ogni identificazione | In qualsiasi momento, entro la sua finestra di conservazione |
| Ideale per | Reagire a un evento | Consultare i dati durante una decisione, backfill, indagini |
Entrambe le superfici sono disponibili dal piano Pro in su.
https://api.tracio.ai/v2Si tratta di un host diverso da quello dell'endpoint del browser (edge.tracio.ai) e
dalla dashboard (app.tracio.ai). Tutti e tre sono separati: il browser parla con
l'edge usando la sua chiave pubblica, il suo backend parla con la Data API usando
la sua chiave segreta.
Le rotte /v1 sono state rimosse. Usi /v2: le rotte sono le stesse, e ogni chiave
JSON e ogni parametro di query è in snake_case (visitor_id, risk_score,
min_risk_score). Le chiavi all'interno dei suoi dizionari fields e labels sono
dati suoi e mantengono la grafia originale. L'SDK JavaScript mantiene la sua interfaccia
in camelCase.
Ogni richiesta porta la sua chiave segreta come bearer token:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"La Data API è solo server-to-server. Gli header CORS non vengono deliberatamente restituiti, quindi un browser non può chiamarla — è questo che tiene la sua chiave segreta fuori dal codice lato client. Non spedisca mai la chiave segreta al browser.
La crei nella dashboard, sotto API Keys, scegliendo il tipo secret.
tracio_sk_ seguito da 43 caratteri, 53 in totale. La
dashboard la elenca con i suoi primi caratteri, così può distinguere le chiavi fra
loro.404, esattamente come per dati che non esistono.La rotazione emette una nuova chiave e mantiene funzionante la vecchia per 7 giorni, così può distribuirla senza interruzioni di servizio. Distribuisca la nuova chiave, verifichi che il traffico si sia spostato e lasci scadere la vecchia. Le chiavi pubbliche non sono ruotabili — non sono segreti e sono visibili nel sorgente della sua pagina per scelta progettuale.
| Metodo | Percorso | Restituisce |
|---|---|---|
GET | /v2/visitors/{visitor_id} | Cronologia aggregata di un visitatore, più la sua ultima sessione |
GET | /v2/visitors/{visitor_id}/sessions | Elenco paginato delle sessioni di quel visitatore |
GET | /v2/visitors/{visitor_id}/sessions/latest | La singola sessione più recente |
GET | /v2/visitors/{visitor_id}/velocity | Contatori di attività su una finestra breve |
GET | /v2/sessions/{request_id} | Una sessione tramite il suo identificatore di richiesta |
POST | /v2/accounts/metadata | Associa nomi visualizzati ed e-mail ai suoi ID account |
POST | /v2/events/fields | Associa campi personalizzati a una visita dopo il caricamento della pagina |
POST | /v2/events/fields/delete | Cancella i campi personalizzati di una visita — la visita stessa non viene toccata |
GET | /v2/lists | Le liste del suo workspace: id, nome, tipo (l'azione), modalità, numero di voci |
POST | /v2/lists/{list_id}/entries | Aggiunge un valore a una lista, facoltativamente con un TTL |
POST | /v2/lists/{list_id}/entries/delete | Rimuove un valore da una lista |
GET | /.well-known/webhook-keys | Chiavi pubbliche per la firma di piattaforma dei webhook (senza autenticazione) |
La stessa chiave e lo stesso host servono anche le API decisionali, tutte in snake_case:
| Metodo | Percorso | Scopo |
|---|---|---|
POST | /v2/transactions | Una decisione sincrona APPROVE / REVIEW / DECLINE su un evento di business — da Business in su, tranne una conversione di affiliazione (account_register o deposit con affiliate_id), disponibile su ogni piano con accesso all'API |
GET | /v2/transactions/{transaction_id} | Rilegge una decisione con la sua etichetta e il suo stato effettivo — da Business in su, tranne una transazione attribuita a un affiliato |
PUT, DELETE | /v2/transaction-labels | Imposta o rimuove l'etichetta di esito di un massimo di 50 transazioni — da Business in su |
GET | /v2/transaction-labels/value-set | I valori di etichetta accettati con la loro polarità — da Business in su |
POST | /v2/logins/assess | Valuta un login: allow / challenge / review / deny con le motivazioni |
POST, GET | /v2/accounts/{user_id}/trusted-devices | Rende attendibile il dispositivo di una visita per un account dopo la sua verifica aggiuntiva, oppure elenca i dispositivi attendibili dell'account |
DELETE | /v2/accounts/{user_id}/trusted-devices/{device_ref} | Revoca l'attendibilità di un dispositivo |
GET | /v2/affiliates/{affiliate_id} | Il rapporto sulla qualità di un affiliato negli ultimi 90 giorni, con una raccomandazione hold / review |
POST, GET | /v2/self-exclusions | Imposta o estende un'autoesclusione su un account, oppure le elenca |
DELETE | /v2/self-exclusions/{user_id} | Revoca anticipatamente un'autoesclusione |
I loro esiti le arrivano anche come eventi webhook:
transaction_state_changed, login_risk, trusted_device_enrolled,
trusted_device_revoked e affiliate_threshold_crossed.
Una barra finale viene accettata e ignorata. Un percorso sconosciuto o un metodo errato restituisce lo stesso envelope JSON di errore di tutto il resto, mai una pagina HTML o di testo semplice.
Ogni lettura è delimitata da una finestra temporale, controllata da due parametri di query facoltativi:
| Parametro | Accetta |
|---|---|
from | YYYY-MM-DD oppure un timestamp RFC 3339 completo |
to | YYYY-MM-DD oppure un timestamp RFC 3339 completo |
to include l'intera giornata.400 invalid_request e il messaggio
time must be YYYY-MM-DD or RFC3339.meta, quindi controlli meta.from e meta.to invece di dare per
scontato che la sua richiesta sia stata rispettata alla lettera.curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"La risposta porta la cronologia aggregata e incorpora l'ultima sessione, così il caso comune richiede una richiesta invece di due:
{ "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" }}| Campo | Significato |
|---|---|
visits, incognito_visits | Visite totali nella finestra e quante di esse in una finestra privata |
unique_ips, unique_countries | Indirizzi e paesi distinti visti nella finestra |
browsers, os, devices | Gli ambienti distinti in cui questo visitatore è comparso |
risk.max_risk_score | Il punteggio di rischio più alto registrato nella finestra, 0..100 |
risk.last_decision | La decisione registrata per la visita più recente |
risk.avg_bot_score, risk.bot_sessions | Media del punteggio di bot e numero di sessioni bot — da Business in su |
network.*_seen | Se per questo visitatore siano mai stati visti una VPN, un proxy, un nodo di uscita Tor o un indirizzo di datacenter |
network.proxy_detected_seen | Se almeno una visita nella finestra è uscita attraverso un proxy o una VPN davanti al browser — veda network.proxy_detected in Dati del dispositivo |
network.last_isp | L'ISP più recente — da Business in su |
network.last_real_ip | L'indirizzo più recente osservato dietro un proxy o una VPN (address, country, isp) — da Business in su; assente quando nessuna visita ne ha portato uno |
last_session | L'oggetto sessione completo della visita più recente |
meta | Il piano, la sua conservazione in giorni e la finestra effettivamente applicata |
Un visitatore senza dati all'interno della finestra di conservazione restituisce
404 not_found con il messaggio visitor not found in the retention window — non è un
errore della sua integrazione, significa che il visitatore è nuovo oppure è uscito dalla
finestra per anzianità.
La sessione porta due verdetti, che rispondono a domande diverse — se il client fosse automatizzato e che cosa abbia concluso complessivamente il motore di rischio:
| Campo | Valori |
|---|---|
bot.result | human, bot, uncertain |
bot.type | Presente quando bot.result è bot: o uno strumento specifico (playwright, puppeteer, selenium, jsdom, claude_computer_use…), un agente IA verificato (ai_agent:<vendor>), oppure una famiglia quando lo strumento non è identificato — automation, headless, antidetect, extension, privacy_browser, impersonation, other |
decision.action | real, fake, suspicious |
bot.score e decision.risk_score vanno entrambi da 0..100. Da Business in su,
guidance li trasforma in indicazioni per singolo scenario sulla scala
allow → challenge → review → deny — veda
Guidance per il significato di ciascun
gradino. Valori e scale coincidono con il corpo del webhook v3 per la stessa visita, e
guidance viene calcolato con le stesse regole.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions?limit=100&min_risk_score=50"| Parametro | Predefinito | Note |
|---|---|---|
limit | 50 | Limitato a 500; un valore maggiore viene ridotto, non rifiutato |
from, to | Conservazione del piano | La finestra temporale condivisa descritta sopra |
cursor | — | Cursore di paginazione opaco della pagina precedente |
bot_result | — | Mantiene solo le sessioni con questo verdetto di bot |
min_risk_score | — | Mantiene solo le sessioni con punteggio di rischio pari o superiore, 0..100 |
Le sessioni tornano dalla più recente:
{ "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" }}La paginazione è basata su cursore. Non esiste un parametro page o offset: rimandi
il next_cursor ricevuto come cursor e prosegua finché has_more è true.
L'ultima pagina può non includere affatto next_cursor, quindi non renda obbligatorio
quel campo.
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}Tratti il cursore come opaco — il suo contenuto è un dettaglio implementativo e può
cambiare. Un cursore che è stato modificato viene rifiutato con 400 invalid_request e
il messaggio malformed cursor.
Accanto al browser e al sistema operativo ricavati dallo User-Agent, una sessione porta ciò che il browser del visitatore riporta sulla macchina, ripulito dalla nostra parte. Ogni campo è assente quando la visita non portava tali dati, quindi consideri ciascuno facoltativo.
| Campo | Significato |
|---|---|
gpu | Modello della scheda video così come lo riporta il browser (WebGL), normalizzato in un nome leggibile — Intel Iris Xe Graphics, Apple M1 Pro, Qualcomm Adreno 830; Software renderer significa nessuna GPU reale (una macchina virtuale o un ambiente headless); Safari riporta Apple GPU |
network.proxy_detected | Il traffico HTTP della visita e i suoi percorsi di rete grezzi escono da reti diverse — un proxy o una VPN davanti al browser; due indirizzi dello stesso operatore (NAT dell'operatore, una seconda uscita della stessa VPN) non contano; non viene segnalato quando gli indirizzi non sono confrontabili (iCloud Private Relay, IPv4 accanto a IPv6) |
network.real_ip.address, .country, .isp | L'indirizzo pubblico osservato sul percorso di rete grezzo, ossia l'indirizzo dietro il proxy o la VPN, con il suo paese e il suo ISP — da Business in su; assente quando non è stato osservato alcun indirizzo del genere (country e isp sono assenti quando non è stato possibile risolverli) |
device_info.device_id, .cross_browser, .confidence, .linked_browsers | Presente quando è stata risolta un'identità del dispositivo: un id stabile del dispositivo fisico comune ai browser presenti su di esso, se questa visita sia arrivata da un browser diverso da prima, la confidenza di tale corrispondenza e quanti visitatori (browser) distinti condividono il dispositivo — più di uno significa una sola macchina sotto diverse identità di browser — da Business in su |
os_environment | L'ambiente desktop misurato su una macchina Linux (Mint 22+, Ubuntu 25.04+, Ubuntu, GNOME, KDE) — da Business in su; assente quando non è determinato |
spoofing | Ciò che la visita ha dichiarato rispetto a ciò che hanno misurato controlli indipendenti (claimed, real, spoofed_axes fra os, gpu, screen, network, browser; anonymous_browser con i nomi dei prodotti) — da Business in su; presente solo quando è stata rilevata una contraffazione |
screen.width, .height, .color_depth, .pixel_ratio | Risoluzione dello schermo, profondità di colore e device pixel ratio così come li riporta il browser — da Business in su |
locale.languages, locale.timezone | Le lingue preferite e il fuso orario del browser stesso — a differenza di geo.timezone, derivato dall'indirizzo IP; una discordanza fra i due è un segno frequente di posizione falsificata — da Business in su |
client_hints.architecture, .bitness, .model, .device_name, .platform_version | User-Agent Client Hints: architettura e bitness della CPU, codice del modello del dispositivo (Android, ad es. SM-A556B) con il suo nome commerciale dall'elenco dei dispositivi Google Play (device_name, ad es. Samsung Galaxy A55 5G) e la versione esatta della piattaforma; solo browser basati su Chromium — da Business in su |
environment.virtual_machine, environment.hypervisor | Presente solo quando la scheda video si è dichiarata virtuale; hypervisor è un dizionario chiuso (vmware, virtualbox, parallels, qemu, hyperv, bochs, intel-gvt, vgpu). Un blocco assente significa che non c'è alcun indizio del genere — da Business in su |
extensions elenca le estensioni del browser rilevate durante la visita — da Pro in su.
Ogni voce è un oggetto:
| Campo | Significato |
|---|---|
slug | Identificatore stabile e leggibile dalla macchina dell'estensione, lo stesso valore che consegna il webhook |
name | Nome leggibile dalle persone |
category | Classe generale — adblock, privacy, automation, wallet, vpn, devtools, other, e così via |
risky | true per le estensioni associate ad automazione, contraffazione o furto di credenziali |
store_url | Link alla scheda dell'estensione nello store, quando è noto |
Un rilevamento viene riportato solo dopo aver superato i nostri controlli di affidabilità — un ambiente che risponde «installata» a ogni sonda, oppure un lotto di più di dodici nomi, viene scartato come inattendibile. Una lista vuota o assente significa quindi «nulla che abbiamo potuto confermare», non «nessuna estensione installata». La legga come indizio, non come inventario.
fields contiene le coppie chiave-valore personalizzate che la sua integrazione ha associato alla visita: un riferimento d'ordine, il nome di un piano, l'esito di un pagamento. Chiavi e valori sono sempre stringhe: un numero o un booleano associato torna in forma di testo. Come il resto della sessione, è disponibile su ogni piano con accesso all'API (da Pro in su) ed è assente quando la visita non ha campi.
fields viene letto in tempo reale a ogni richiesta, non copiato al momento della visita. Anche i campi associati dopo la visita (veda Associare campi dopo la visita) compaiono qui, quindi per la stessa visita fields può contenere più di quanto ha consegnato il webhook.
Non inserisca dati personali, come nomi, indirizzi e-mail o numeri di telefono, nei campi personalizzati: associ invece un riferimento che i suoi sistemi sono in grado di risolvere, e invii chi è l'account come record dell'account (veda più avanti).
account è il suo record per l'account dietro la visita — ciò che ha inviato per ultimo
per quell'account_id tramite POST /v2/accounts/metadata:
{ "account": { "id": "user-42", "email": "ann@example.com", "display_name": "Ann Lee" }}| Campo | Descrizione |
|---|---|
id | Il suo ID account — lo stesso valore di account_id |
email | L'indirizzo e-mail inviato per l'account; assente se vuoto |
display_name | Il nome visualizzato inviato per l'account; assente se vuoto |
Il record viene letto in tempo reale a ogni richiesta, quindi una ridenominazione compare anche sulle visite passate: il blocco descrive l'account com'è adesso, non com'era al momento della visita. È disponibile su ogni piano con accesso all'API (da Pro in su). Le etichette inviate con il record non vengono restituite.
Il blocco è assente quando la visita non ha un account collegato, quando non esiste un record per esso (o lo ha svuotato inviando valori vuoti) e — raramente — quando il record non è stato leggibile: la sessione viene comunque restituita per intero anziché far fallire la richiesta, quindi consideri un blocco assente come «sconosciuto», non come «questo account non ha un'e-mail». I webhook non portano questo blocco.
La più recente:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions/latest"Restituisce un oggetto sessione nudo — non un array e non avvolto in un envelope. Un
visitatore senza sessioni nella finestra restituisce 404 not_found con
no sessions for this visitor in the retention window.
Oppure tramite request_id, l'identificatore che compare anche nel payload del webhook:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/sessions/9c1f6a2e-3b7d-4c58-a1e2-6f0d8b4a7c31?visitor_id=X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"Qui visitor_id è facoltativo, ma passarlo quando lo conosce rende la ricerca nettamente
più veloce.
identification.drift_score — il punteggio di comportamento livellato su cui è stato
emesso il verdetto di furto di account, da Business in su — viene restituito solo da
questa lettura della singola sessione. La deriva del comportamento viene misurata durante
la visita, dopo l'identificazione iniziale, perciò le rotte dell'elenco e dell'ultima
sessione lo omettono. Una visita il cui comportamento non è mai stato valutato non ha
drift_score. Lo stesso valore le arriva tramite il webhook account_takeover.
Una visita può essere consegnata più di una volta via webhook: prima primary, poi
late o correction man mano che arrivano i segnali più lenti e le prove
comportamentali — e una fase successiva può ribaltare il verdetto precedente. La Data
API risponde dal record primary. Le fasi successive non vengono riunite in esso,
quindi per una visita corretta l'ultimo webhook è la risposta più recente. Se agisce a
pochi minuti dalla visita, preferisca la fase ricevuta per ultima a una nuova lettura
qui.
Una cosa va nella direzione opposta: una volta che il rilevatore di furto di account è
scattato per una visita, guidance qui ne tiene conto, mentre i corpi dei webhook
identification della stessa visita non portano quell'asse — viaggia con la consegna
dedicata account_takeover.
Velocity risponde alla domanda «quanto ha fatto ultimamente questo visitatore» — la forma del credential stuffing, del card testing e delle registrazioni di massa.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/velocity?window=1h"window accetta 1h, 24h o 7d e il valore predefinito è 24h. Qualsiasi altro
valore viene rifiutato con 400 invalid_request e
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 conta i valori distinti di linkedId che ha inviato per questo
dispositivo — veda Collegamento degli account. bot_events è da
Business in su; su Pro la chiave è assente.
TRACIO conosce i suoi account solo tramite l'ID che il suo sito passa come linkedId —
una stringa opaca come usr_8412. Invii una volta le etichette leggibili, e ogni
schermata della dashboard che mostra quell'account mostra il nome o l'e-mail al posto
dell'ID grezzo, e l'oggetto sessione li restituisce nel suo blocco
account. Nulla di tutto questo influisce sul rilevamento o sul
punteggio; è un livello di visualizzazione.
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. Un'e-mail o
un nome inviati qui vivono solo nel record dell'account del suo workspace: non vengono
memorizzati per visita, non vengono scritti nella pagina, e un solo invio aggiorna
ogni visita di quell'account.400 invalid_request, e una sola voce
errata fa rifiutare l'intero lotto — l'errore ne indica la posizione. ID account
duplicati nello stesso lotto vanno bene: vince l'ultimo.Limiti: 1.000 account per richiesta, corpo di 1 MiB, account_id ≤ 256 caratteri,
email ≤ 320, display_name ≤ 256, al massimo 16 etichette con chiavi ≤ 64 e valori
≤ 256 caratteri.
Il browser può inviare solo ciò che la pagina conosce al momento del rendering — un ID d'ordine, mai l'esito di un controllo di pagamento o qualsiasi altra cosa che si risolve dopo. Questa rotta colma la lacuna: trova la visita tramite un campo che già porta e le associa altri campi lato server.
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 trova la visita tramite un campo che già possiede, non tramite
request_id, all'interno del workspace e dell'ambiente della sua chiave.404 not_found — scriva il campo poco dopo che l'esito si è risolto.updated conta le visite distinte. Supera 1 solo quando il suo match colpisce
più di una visita — una coppia chiave/valore che non è univoca per un solo ordine o
carrello. Un match che colpisce più di 100 eventi viene rifiutato con
400 invalid_request anziché applicato a un sottoinsieme arbitrario.server, e hanno la
precedenza su un valore con la stessa chiave scritto dal browser.404 not_found, non un 200 vuoto.I limiti coincidono con il canale del browser: 50 campi per chiamata, chiavi ≤ 40 byte,
valori ≤ 500 byte — byte, non caratteri — set di caratteri delle chiavi
A-Za-z0-9_.:-, corpo di 1 MiB.
Cancella i campi personalizzati — mai la visita stessa. La usi per valori che non ha più bisogno di tenere associati a una visita, come il totale di un ordine. I webhook già inviati e le esportazioni già effettuate non vengono modificati.
# 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 e match si escludono a vicenda — inviarli entrambi, o nessuno dei
due, è 400 invalid_request. match usa la stessa finestra di 24 ore e lo stesso
tetto di 100 eventi dell'associazione.deleted conta i campi rimossi dalla visita (tramite request_id) oppure le
visite da cui il campo è stato rimosso (tramite match).404 not_found.Le stesse liste che i suoi operatori gestiscono nella dashboard, raggiungibili dal suo
back office. Il tipo di una lista è la sua azione su una visita corrispondente —
block, manual_review, challenge, allow — e la sua modalità decide se
l'azione viene applicata: observe si limita a contare le corrispondenze, enforce la
applica a guidance (l'asse list). Le liste e la loro modalità si creano nella
dashboard; la Data API legge le liste e aggiunge e rimuove le voci.
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"}Rimuova una voce con lo stesso corpo su POST /v2/lists/{list_id}/entries/delete; la
risposta è { "removed": true, "propagation": "immediate" }.
value_type è ciò con cui viene confrontato il valore: linked_id, visitor_id,
device_id, ip, cidr o country. Un valore non interpretabile per il suo tipo è
400 invalid_request.linked_id →
visitor_id → device_id → ip → cidr → country — e al suo interno vince
l'azione più severa.ttl_minutes è facoltativo. Se omesso, si applica il TTL predefinito della lista;
se non ce n'è uno, la voce non scade mai (expires_at è null). Aggiungere di nuovo
una voce la rinnova.propagation indica quando la modifica è attiva: immediate, oppure ttl —
entro circa cinque minuti.200 con removed: false; 404 è riservato a
una lista sconosciuta.Un campo assente significa «nessun dato», mai zero. I campi senza valore vengono
omessi del tutto invece di essere inviati come 0, "" o null: un visitatore
nuovissimo non ha match_confidence, una visita pulita non ha antidetect_score né
suspect_score. L'unica eccezione deliberata è bot.score, sempre presente anche quando
vale zero. Legga i campi in modo difensivo.
Il payload dipende dal suo piano. L'accesso all'API parte da Pro, e Pro riceve la sessione di base — identificatori, timestamp, URL, IP, user agent, browser, sistema operativo, dispositivo, geo, rete, bot, identificazione e decisione — insieme a identification.match_type, identification.match_confidence, bot.score, bot.type, bot.antidetect_score, gpu, network.proxy_detected, extensions, fields e account. Business ed Enterprise aggiungono 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 ed environment. I campi a livello di persona (person_id, reputation, linked_accounts_count, linked_visitors_count) sono riservati a Business ed Enterprise e compariranno una volta attivato il livello persona — oggi funziona in modalità di osservazione e questi campi non vengono consegnati. L'assenza di un campo Business su un piano Pro non è un errore.
Gli interni a livello di segnale non vengono mai restituiti, su nessun piano: i nomi dei singoli segnali, i loro pesi, le soglie dietro un verdetto, i valori grezzi dei segnali e la scomposizione dei punteggi restano dalla nostra parte. Un punteggio che può essere sottoposto a reverse engineering fino ai suoi input smette di essere utile come difesa.
Ogni errore usa un unico envelope:
{ "error": { "code": "unauthorized", "message": "missing Authorization: Bearer <secret key>", "request_id": "8f14e45fceea167a5a36dedd" }}Questo request_id non è l'identificatore della visita. Due valori diversi
condividono il nome: dentro il payload di una sessione request_id è l'UUID della
visita, lo stesso che recapita il webhook; dentro un envelope di errore è un
identificatore di traccia di 24 caratteri, generato per ogni chiamata HTTP.
L'identificatore di traccia torna anche nell'header X-Request-Id di ogni risposta,
riuscita o meno. Lo includa quando contatta il supporto — è così che troviamo la sua
chiamata esatta.
| HTTP | code | Significato |
|---|---|---|
| 400 | invalid_request | Un parametro manca o è malformato |
| 401 | unauthorized | La chiave è assente, non valida, revocata o scaduta |
| 402 | upgrade_required | Il suo piano non include l'accesso all'API |
| 404 | not_found | Nulla ha trovato corrispondenza dentro la finestra di conservazione, oppure appartiene a un altro ambiente |
| 405 | method_not_allowed | La rotta esiste, ma non per quel metodo |
| 429 | rate_limited | Superate le richieste al secondo o la quota giornaliera |
| 500 | internal | Qualcosa è fallito dalla nostra parte |
| 503 | unavailable | Uno store di supporto è temporaneamente irraggiungibile |
I controlli avvengono in un ordine fisso — chiave, poi piano, poi limiti — così una
richiesta con una chiave errata segnala sempre prima la chiave, mai un problema di
quota. I dati di un altro workspace sono indistinguibili da dati che non esistono:
producono 404, non 403.
Due casi di 401 si leggono in modo diverso di proposito:
missing Authorization: Bearer <secret key> significa che l'header non è mai arrivato,
mentre invalid or revoked API key significa che è arrivato e non ha trovato
corrispondenza. 402 porta Data API requires the Pro plan or higher.
Ripeta 429 e 503 con una pausa crescente; ripetere gli altri 4xx è inutile —
significano che è la richiesta stessa a dover essere corretta.
Le risposte per cui la chiave è stata riconosciuta portano la sua situazione corrente
(le risposte 401 e 402 no, ed Enterprise, senza quota giornaliera, non riceve header
di quota):
| Header | Significato |
|---|---|
X-RateLimit-Limit | La sua quota giornaliera; in caso di rifiuto al secondo, il limite al secondo |
X-RateLimit-Remaining | Chiamate rimaste oggi |
X-RateLimit-Reset | Orario Unix del reset — mezzanotte UTC |
Retry-After | Secondi da attendere, inviato solo con un 429 — si regoli su questo: è corretto per entrambi i limiti |
| Piano | Richieste al secondo | Richieste al giorno | Profondità della cronologia |
|---|---|---|---|
| Free | Nessun accesso API | — | 7 giorni |
| Pro | 10 | 10.000 | 30 giorni |
| Business | 50 | 100.000 | 90 giorni |
| Enterprise | 200 | Illimitate | 365 giorni |