La Data API (documentada aquí anteriormente como Server API) permite que su backend lea los datos de identificación que TRACIO ya ha recogido para su workspace: el historial de un visitante, las sesiones individuales y los contadores de velocity de ventana corta. Algunas rutas también escriben —registros de cuenta, campos personalizados y entradas de listas— para que su backend pueda enriquecer lo que TRACIO sabe.
Complementa a los webhooks en lugar de sustituirlos:
| Webhooks | Data API | |
|---|---|---|
| Dirección | TRACIO envía a su endpoint | Su backend consulta cuando lo necesita |
| Momento | A medida que ocurre cada identificación | En cualquier momento, dentro de su ventana de retención |
| Ideal para | Reaccionar a un evento | Consultar datos durante una decisión, rellenar históricos, investigaciones |
Ambas superficies están disponibles a partir del plan Pro.
https://api.tracio.ai/v2Es un host distinto del endpoint del navegador (edge.tracio.ai) y del panel
(app.tracio.ai). Los tres están separados: el navegador habla con el edge usando su
clave pública, y su backend habla con la Data API usando su clave secreta.
Las rutas /v1 se han retirado. Use /v2: las rutas son las mismas, y todas las
claves JSON y los parámetros de consulta están en snake_case (visitor_id,
risk_score, min_risk_score). Las claves dentro de sus propios diccionarios
fields y labels son datos suyos y conservan su grafía original. El SDK de
JavaScript mantiene su interfaz en camelCase.
Cada petición lleva su clave secreta como bearer token:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"La Data API es exclusivamente de servidor a servidor. Las cabeceras CORS deliberadamente no se devuelven, de modo que un navegador no puede llamarla: eso es lo que mantiene su clave secreta fuera del código de cliente. No envíe nunca la clave secreta al navegador.
Créela en el panel, en API Keys, eligiendo el tipo secret.
tracio_sk_ seguido de 43 caracteres, 53 en
total. El panel la lista por sus primeros caracteres para que pueda distinguir unas
claves de otras.404, exactamente igual que para datos que no existen.La rotación emite una clave nueva y mantiene la antigua en funcionamiento durante 7 días, de modo que pueda desplegarla sin caídas. Despliegue la clave nueva, confirme que el tráfico se ha movido y deje que la antigua expire. Las claves públicas no son rotables: no son secretos y están visibles en el código fuente de sus páginas por diseño.
| Método | Ruta | Devuelve |
|---|---|---|
GET | /v2/visitors/{visitor_id} | Historial agregado de un visitante, más su sesión más reciente |
GET | /v2/visitors/{visitor_id}/sessions | Lista paginada de las sesiones de ese visitante |
GET | /v2/visitors/{visitor_id}/sessions/latest | La única sesión más reciente |
GET | /v2/visitors/{visitor_id}/velocity | Contadores de actividad en una ventana corta |
GET | /v2/sessions/{request_id} | Una sesión, por su identificador de petición |
POST | /v2/accounts/metadata | Asociar nombres visibles y correos electrónicos a sus ID de cuenta |
POST | /v2/events/fields | Adjuntar campos personalizados a una visita después de cargar la página |
POST | /v2/events/fields/delete | Borrar campos personalizados de una visita; la visita en sí no se toca |
GET | /v2/lists | Las listas de su workspace: id, nombre, tipo (la acción), modo, nº de entradas |
POST | /v2/lists/{list_id}/entries | Añadir un valor a una lista, opcionalmente con un TTL |
POST | /v2/lists/{list_id}/entries/delete | Quitar un valor de una lista |
GET | /.well-known/webhook-keys | Claves públicas de la firma de plataforma de webhooks (sin autenticación) |
La misma clave y el mismo host sirven también las API de decisión, todas en snake_case:
| Método | Ruta | Propósito |
|---|---|---|
POST | /v2/transactions | Una decisión síncrona APPROVE / REVIEW / DECLINE sobre un evento de negocio — Business y superiores, salvo una conversión de afiliado (account_register o deposit con affiliate_id), disponible en cualquier plan con acceso a la API |
GET | /v2/transactions/{transaction_id} | Volver a leer una decisión con su etiqueta y su estado efectivo — Business y superiores, salvo una transacción atribuida a un afiliado |
PUT, DELETE | /v2/transaction-labels | Fijar o quitar la etiqueta de resultado de hasta 50 transacciones — Business y superiores |
GET | /v2/transaction-labels/value-set | Los valores de etiqueta aceptados con su polaridad — Business y superiores |
POST | /v2/logins/assess | Evaluar un inicio de sesión: allow / challenge / review / deny con motivos |
POST, GET | /v2/accounts/{user_id}/trusted-devices | Marcar como de confianza el dispositivo de una visita para una cuenta tras su verificación adicional, o listar los dispositivos de confianza de la cuenta |
DELETE | /v2/accounts/{user_id}/trusted-devices/{device_ref} | Revocar la confianza de un dispositivo |
GET | /v2/affiliates/{affiliate_id} | El informe de calidad de un afiliado a lo largo de 90 días, con una recomendación hold / review |
POST, GET | /v2/self-exclusions | Establecer o prolongar una autoexclusión en una cuenta, o listarlas |
DELETE | /v2/self-exclusions/{user_id} | Levantar una autoexclusión antes de tiempo |
Sus resultados también le llegan como eventos de webhook:
transaction_state_changed, login_risk, trusted_device_enrolled,
trusted_device_revoked y affiliate_threshold_crossed.
Una barra final se acepta y se ignora. Una ruta desconocida o un método equivocado devuelven el mismo sobre de error JSON que todo lo demás, nunca una página HTML o de texto plano.
Toda lectura está acotada por una ventana temporal, controlada por dos parámetros de consulta opcionales:
| Parámetro | Acepta |
|---|---|
from | YYYY-MM-DD o una marca de tiempo RFC 3339 completa |
to | YYYY-MM-DD o una marca de tiempo RFC 3339 completa |
to incluye ese día entero.400 invalid_request y el mensaje
time must be YYYY-MM-DD or RFC3339.meta, así que compruebe meta.from y meta.to en lugar de dar por hecho que su
petición se respetó al pie de la letra.curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y"La respuesta lleva el historial agregado e incrusta la sesión más reciente, así que el caso habitual necesita una petición y no dos:
{ "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 | Significado |
|---|---|
visits, incognito_visits | Visitas totales en la ventana, y cuántas fueron en una ventana privada |
unique_ips, unique_countries | Direcciones y países distintos observados en la ventana |
browsers, os, devices | Los entornos distintos en los que ha aparecido este visitante |
risk.max_risk_score | La puntuación de riesgo más alta registrada en la ventana, 0..100 |
risk.last_decision | La decisión registrada para la visita más reciente |
risk.avg_bot_score, risk.bot_sessions | Media de la puntuación de bot y número de sesiones de bot — Business y superiores |
network.*_seen | Si alguna vez se vio un VPN, un proxy, un nodo de salida Tor o una dirección de datacenter para este visitante |
network.proxy_detected_seen | Si al menos una visita de la ventana salió a través de un proxy o una VPN por delante del navegador — consulte network.proxy_detected en Datos del dispositivo |
network.last_isp | El ISP más reciente — Business y superiores |
network.last_real_ip | La dirección más reciente observada detrás de un proxy o una VPN (address, country, isp) — Business y superiores; ausente cuando ninguna visita trajo una |
last_session | El objeto de sesión completo de la visita más reciente |
meta | El plan, su retención en días y la ventana realmente aplicada |
Un visitante sin datos dentro de la ventana de retención devuelve 404 not_found con
el mensaje visitor not found in the retention window: eso no es un error de su
integración, significa que el visitante es nuevo o que ha quedado fuera por antigüedad.
La sesión lleva dos veredictos y responden a preguntas distintas: si el cliente estaba automatizado y qué concluyó el motor de riesgo en conjunto:
| Campo | Valores |
|---|---|
bot.result | human, bot, uncertain |
bot.type | Presente cuando bot.result es bot: o bien una herramienta concreta (playwright, puppeteer, selenium, jsdom, claude_computer_use…), o bien un agente de IA verificado (ai_agent:<vendor>), o bien una familia cuando la herramienta no se identifica — automation, headless, antidetect, extension, privacy_browser, impersonation, other |
decision.action | real, fake, suspicious |
bot.score y decision.risk_score van ambos de 0..100. En Business y superiores,
guidance los convierte en recomendaciones por escenario sobre la escala
allow → challenge → review → deny; consulte
Guidance para saber qué significa cada
peldaño. Los valores y las escalas coinciden con el cuerpo del webhook v3 de la misma
visita, y guidance se calcula con las mismas reglas.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions?limit=100&min_risk_score=50"| Parámetro | Por defecto | Notas |
|---|---|---|
limit | 50 | Con tope en 500; un valor mayor se recorta, no se rechaza |
from, to | Retención del plan | La ventana temporal compartida descrita más arriba |
cursor | — | Cursor de paginación opaco de la página anterior |
bot_result | — | Conservar solo las sesiones con este veredicto de bot |
min_risk_score | — | Conservar solo las sesiones con esta puntuación de riesgo o superior, 0..100 |
Las sesiones vuelven de la más reciente a la más antigua:
{ "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 paginación se basa en cursores. No hay parámetro page ni offset: devuelva el
next_cursor que recibió como cursor y siga mientras has_more sea true. Puede que
la última página no incluya next_cursor en absoluto, así que no haga obligatorio ese
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}Trate el cursor como opaco: su contenido es un detalle de implementación y puede
cambiar. Un cursor que haya sido editado se rechaza con 400 invalid_request y el
mensaje malformed cursor.
Junto al navegador y al sistema operativo tomados del User-Agent, una sesión lleva lo que el navegador del visitante informa sobre la máquina, saneado por nuestra parte. Cada campo está ausente cuando la visita no traía esos datos, así que trate cada uno como opcional.
| Campo | Significado |
|---|---|
gpu | Modelo del adaptador de vídeo tal como lo informa el navegador (WebGL), normalizado a un nombre legible — Intel Iris Xe Graphics, Apple M1 Pro, Qualcomm Adreno 830; Software renderer significa que no hay GPU real (una máquina virtual o un entorno headless); Safari informa Apple GPU |
network.proxy_detected | El tráfico HTTP de la visita y sus rutas de red en bruto salen por redes distintas — un proxy o una VPN delante del navegador; dos direcciones del mismo proveedor (NAT del operador, una segunda salida de la misma VPN) no cuentan; no se activa cuando las direcciones no se pueden comparar (iCloud Private Relay, IPv4 junto a IPv6) |
network.real_ip.address, .country, .isp | La dirección pública observada en la ruta de red en bruto, es decir, la dirección detrás del proxy o de la VPN, con su país y su ISP — Business y superiores; ausente cuando no se observó ninguna dirección así (country e isp están ausentes cuando no se han podido resolver) |
device_info.device_id, .cross_browser, .confidence, .linked_browsers | Presente cuando se ha resuelto una identidad de dispositivo: un id estable del dispositivo físico común a los navegadores que hay en él, si esta visita llegó por un navegador distinto al de antes, la confianza de esa coincidencia y cuántos visitantes (navegadores) distintos comparten el dispositivo — más de uno significa una sola máquina bajo varias identidades de navegador — Business y superiores |
os_environment | El entorno de escritorio medido en una máquina Linux (Mint 22+, Ubuntu 25.04+, Ubuntu, GNOME, KDE) — Business y superiores; ausente cuando no se determina |
spoofing | Lo que la visita afirmó frente a lo que midieron comprobaciones independientes (claimed, real, spoofed_axes de os, gpu, screen, network, browser; anonymous_browser con nombres de producto) — Business y superiores; presente solo cuando se detectó una suplantación |
screen.width, .height, .color_depth, .pixel_ratio | Resolución de pantalla, profundidad de color y device pixel ratio tal como los informa el navegador — Business y superiores |
locale.languages, locale.timezone | Los idiomas preferidos y la zona horaria del propio navegador — a diferencia de geo.timezone, derivada de la dirección IP; una discrepancia entre ambos es una señal habitual de una ubicación falseada — Business y superiores |
client_hints.architecture, .bitness, .model, .device_name, .platform_version | User-Agent Client Hints: arquitectura y bitness de la CPU, código de modelo del dispositivo (Android, p. ej. SM-A556B) con su nombre comercial de la lista de dispositivos de Google Play (device_name, p. ej. Samsung Galaxy A55 5G) y la versión exacta de la plataforma; solo navegadores basados en Chromium — Business y superiores |
environment.virtual_machine, environment.hypervisor | Presente solo cuando el adaptador de vídeo se identificó a sí mismo como virtual; hypervisor es un diccionario cerrado (vmware, virtualbox, parallels, qemu, hyperv, bochs, intel-gvt, vgpu). Un bloque ausente significa que no hay tal indicio — Business y superiores |
extensions enumera las extensiones del navegador detectadas durante la visita — Pro y superiores.
Cada entrada es un objeto:
| Campo | Significado |
|---|---|
slug | Identificador estable y legible por máquina de la extensión, el mismo valor que entrega el webhook |
name | Nombre legible por humanos |
category | Clase general — adblock, privacy, automation, wallet, vpn, devtools, other, etc. |
risky | true para las extensiones asociadas a automatización, suplantación o robo de credenciales |
store_url | Enlace a la ficha de la extensión en la tienda, cuando se conoce |
Un hallazgo solo se comunica después de superar nuestras comprobaciones de fiabilidad: un entorno que responde «instalada» a cada sondeo, o un lote de más de doce nombres, se descarta por poco fiable. Por tanto, una lista vacía o ausente significa «nada que hayamos podido confirmar», no «ninguna extensión instalada». Léala como indicio, no como inventario.
fields contiene los pares clave-valor personalizados que su integración adjuntó a la visita: una referencia de pedido, el nombre de un plan, el resultado de un pago. Las claves y los valores son siempre cadenas: un número o un booleano adjunto se devuelve en forma de texto. Como el resto de la sesión, está disponible en cualquier plan con acceso a la API (Pro y superiores) y no aparece cuando la visita no tiene campos.
fields se lee en vivo en cada solicitud, no se copia en el momento de la visita. Los campos adjuntados después de la visita (consulte Adjuntar campos después de la visita) también aparecen aquí, por lo que, para la misma visita, fields puede contener más de lo que entregó el webhook.
No incluya datos personales, como nombres, direcciones de correo electrónico o números de teléfono, en los campos personalizados: adjunte en su lugar una referencia que sus propios sistemas puedan resolver, y envíe quién es la cuenta como registro de cuenta (más abajo).
account es su registro de la cuenta que hay detrás de la visita: lo último que envió
para ese account_id mediante POST /v2/accounts/metadata:
{ "account": { "id": "user-42", "email": "ann@example.com", "display_name": "Ann Lee" }}| Campo | Descripción |
|---|---|
id | Su ID de cuenta — el mismo valor que account_id |
email | La dirección de correo electrónico que envió para la cuenta; ausente si vacía |
display_name | El nombre visible que envió para la cuenta; ausente si está vacío |
El registro se lee en vivo en cada solicitud, así que un cambio de nombre también se refleja en las visitas antiguas: el bloque describe la cuenta tal como es ahora, no como era en el momento de la visita. Está disponible en cualquier plan con acceso a la API (Pro y superiores). Las etiquetas que envió con el registro no se devuelven.
El bloque está ausente cuando la visita no tiene una cuenta vinculada, cuando no hay registro para ella (o lo vació enviando valores vacíos) y —rara vez— cuando el registro no se pudo leer: la sesión se devuelve completa en lugar de hacer fallar la petición, así que trate un bloque ausente como «desconocido», no como «esta cuenta no tiene correo electrónico». Los webhooks no llevan este bloque.
La más reciente:
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/sessions/latest"Esto devuelve un objeto de sesión a secas: ni un array, ni envuelto en un sobre. Un
visitante sin sesiones en la ventana devuelve 404 not_found con
no sessions for this visitor in the retention window.
O por request_id, el identificador que también aparece en el 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"Aquí visitor_id es opcional, pero pasarlo cuando lo conoce hace la búsqueda
notablemente más rápida.
identification.drift_score —la puntuación de comportamiento suavizada sobre la que
se tomó el veredicto de apropiación de cuenta, Business y superiores— solo la devuelve
esta lectura de sesión individual. La deriva de comportamiento se mide durante la
visita, después de la identificación inicial, por lo que las rutas de lista y de
sesión más reciente la omiten. Una visita cuyo comportamiento nunca se evaluó no tiene
drift_score. El mismo valor le llega a través del webhook account_takeover.
Una visita puede entregarse más de una vez por webhook: primero primary y después
late o correction a medida que llegan las señales más lentas y los indicios de
comportamiento; una fase posterior puede anular el veredicto anterior. La Data API
responde a partir del registro primary. Las fases posteriores no se fusionan en
él, así que, para una visita corregida, el último webhook es la respuesta más
reciente. Si actúa minutos después de la visita, dé preferencia a la última fase que
recibió frente a una lectura nueva aquí.
Hay una cosa que funciona al revés: una vez que el detector de apropiación de cuenta
se ha activado para una visita, guidance lo refleja aquí, mientras que los cuerpos
de webhook identification de esa misma visita no llevan ese eje: viaja en la entrega
dedicada account_takeover.
Velocity responde a «cuánta actividad ha tenido este visitante últimamente»: la forma que tienen el credential stuffing, las pruebas de tarjetas y los registros masivos.
curl -H "Authorization: Bearer tracio_sk_XXXX...XXXX" \ "https://api.tracio.ai/v2/visitors/X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y/velocity?window=1h"window acepta 1h, 24h o 7d y por defecto es 24h. Cualquier otro valor se
rechaza con 400 invalid_request y 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 cuenta los valores linkedId distintos que ha enviado para este
dispositivo; consulte Vinculación de cuentas. bot_events es
de Business y superiores; en Pro la clave está ausente.
TRACIO conoce sus cuentas solo por el ID que su sitio pasa como linkedId, una cadena
opaca como usr_8412. Envíe una vez las etiquetas legibles, y cada pantalla del panel
que muestra esa cuenta mostrará el nombre o el correo electrónico en lugar del ID en
bruto, y el objeto de sesión los devolverá en su bloque
account. Nada de esto afecta a la detección ni a la puntuación; es
una capa de presentación.
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 correo
electrónico o un nombre enviados aquí viven solo en el registro de cuenta de su
workspace: no se guardan por visita, no se escriben en la página y un solo envío
actualiza cada visita de esa cuenta.400 invalid_request, y una entrada
incorrecta rechaza todo el lote: el error indica su posición. Los ID de cuenta
duplicados en un mismo lote no son problema: gana el último.Límites: 1.000 cuentas por petición, cuerpo de 1 MiB, account_id ≤ 256 caracteres,
email ≤ 320, display_name ≤ 256, como máximo 16 etiquetas con claves ≤ 64 y valores
≤ 256 caracteres.
El navegador solo puede enviar lo que la página sabe en el momento de renderizarse: un ID de pedido, nunca el resultado de una comprobación de pago ni nada que se resuelva más tarde. Esta ruta cubre ese hueco: encuentre la visita por un campo que ya lleva y adjúntele más campos desde el servidor.
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 encuentra la visita por un campo que ya tiene, no por request_id, dentro
del workspace y el entorno de su clave.404 not_found: escriba el campo poco después de que se resuelva el resultado.updated cuenta visitas distintas. Supera 1 solo cuando su match alcanza más
de una visita, es decir, un par clave/valor que no es exclusivo de un pedido o un
carrito. Un match que alcanza más de 100 eventos se rechaza con
400 invalid_request en lugar de aplicarse a un subconjunto arbitrario.server y tienen
prioridad sobre un valor con la misma clave escrito por el navegador.404 not_found, no un 200 vacío.Los límites coinciden con los del canal del navegador: 50 campos por llamada, claves
≤ 40 bytes, valores ≤ 500 bytes —bytes, no caracteres—, juego de caracteres de las
claves A-Za-z0-9_.:-, cuerpo de 1 MiB.
Borra campos personalizados, nunca la visita en sí. Úselo para valores que ya no necesita adjuntos a una visita, como el importe de un pedido. Los webhooks ya enviados y las exportaciones ya realizadas no cambian.
# 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 y match son mutuamente excluyentes: enviar ambos, o ninguno, da
400 invalid_request. match usa la misma ventana de 24 horas y el mismo tope de
100 eventos que al adjuntar.deleted cuenta los campos eliminados de la visita (por request_id) o las
visitas de las que se eliminó el campo (por match).404 not_found.Las mismas listas que sus operadores gestionan en el panel, accesibles desde su propio
back office. El tipo de una lista es su acción sobre una visita que coincide
—block, manual_review, challenge, allow— y su modo decide si la acción se
aplica: observe solo cuenta las coincidencias, enforce la aplica a guidance (el
eje list). Las listas y su modo se crean en el panel; la Data API lee las listas y
añade y quita entradas.
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"}Quite una entrada con el mismo cuerpo en POST /v2/lists/{list_id}/entries/delete; la
respuesta es { "removed": true, "propagation": "immediate" }.
value_type es aquello con lo que se compara el valor: linked_id, visitor_id,
device_id, ip, cidr o country. Un valor que no se puede interpretar para su
tipo da 400 invalid_request.linked_id →
visitor_id → device_id → ip → cidr → country— y, dentro de él, gana la
acción más estricta.ttl_minutes es opcional. Si se omite, se aplica el TTL por defecto de la lista;
si no lo hay, la entrada no caduca nunca (expires_at es null). Volver a añadir una
entrada la renueva.propagation indica cuándo el cambio está activo: immediate, o ttl, en unos
cinco minutos.200 con removed: false; 404 se reserva para
una lista desconocida.Un campo ausente significa «sin datos», nunca cero. Los campos sin valor se omiten
por completo en lugar de enviarse como 0, "" o null: un visitante recién llegado
no tiene match_confidence, y una visita limpia no tiene antidetect_score ni
suspect_score. La única excepción deliberada es bot.score, que siempre está
presente incluso cuando vale cero. Lea los campos de forma defensiva.
El payload depende de su plan. El acceso a la API empieza en Pro, y Pro recibe la
sesión base —identificadores, timestamp, URL, IP, user agent, navegador, SO,
dispositivo, geo, network, bot, identification y decision— junto con
identification.match_type, identification.match_confidence, bot.score,
bot.type, bot.antidetect_score, gpu, network.proxy_detected, extensions,
fields y account. Business y Enterprise añaden 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 y environment.
Los campos a nivel de persona (person_id, reputation, linked_accounts_count,
linked_visitors_count) están reservados a Business y Enterprise y aparecerán en cuanto
se active la capa de persona: hoy funciona en modo de observación y esos campos no se
entregan. Que falte un campo de Business en un plan Pro no es un error.
Los detalles internos a nivel de señal no se devuelven nunca, en ningún plan: los nombres de las señales individuales, sus pesos, los umbrales que hay detrás de un veredicto, los valores en bruto de las señales y el desglose de las puntuaciones se quedan de nuestro lado. Una puntuación que puede someterse a ingeniería inversa hasta sus entradas deja de ser útil como defensa.
Todo fallo usa un mismo sobre:
{ "error": { "code": "unauthorized", "message": "missing Authorization: Bearer <secret key>", "request_id": "8f14e45fceea167a5a36dedd" }}Este request_id no es el identificador de la visita. Dos valores distintos
comparten el nombre: dentro de un payload de sesión, request_id es el UUID de la
visita, el mismo que entrega el webhook; dentro de un sobre de error es un
identificador de traza de 24 caracteres, acuñado para cada llamada HTTP. El
identificador de traza vuelve también en la cabecera X-Request-Id en cada respuesta,
tenga éxito o no. Inclúyalo cuando contacte con soporte: es como encontramos su
llamada exacta.
| HTTP | code | Significado |
|---|---|---|
| 400 | invalid_request | Falta un parámetro o está mal formado |
| 401 | unauthorized | La clave falta, no es válida, está revocada o caducada |
| 402 | upgrade_required | Su plan no incluye acceso a la API |
| 404 | not_found | Nada coincidió dentro de la ventana de retención, o pertenece a otro entorno |
| 405 | method_not_allowed | La ruta existe, pero no para ese método |
| 429 | rate_limited | Se superaron las peticiones por segundo o la cuota diaria |
| 500 | internal | Algo falló de nuestro lado |
| 503 | unavailable | Un almacén de datos está temporalmente inaccesible |
Las comprobaciones se ejecutan en un orden fijo —clave, luego plan, luego límites—, de
modo que una petición con una clave incorrecta siempre informa primero de la clave,
nunca de un problema de cuota. Los datos de otro workspace no se distinguen de los
datos que no existen: dan 404, no 403.
Dos casos de 401 se leen distinto a propósito: missing Authorization: Bearer <secret key>
significa que la cabecera nunca llegó, mientras que invalid or revoked API key
significa que llegó y no coincidió. El 402 lleva
Data API requires the Pro plan or higher.
Reintente 429 y 503 con una pausa creciente; reintentar otros 4xx no tiene
sentido: significan que hay que corregir la propia petición.
Las respuestas en las que la clave ha sido reconocida llevan su situación actual (las
respuestas 401 y 402 no, y Enterprise, sin cuota diaria, no recibe cabeceras de
cuota):
| Cabecera | Significado |
|---|---|
X-RateLimit-Limit | Su cuota diaria; en un rechazo por segundo, el límite por segundo |
X-RateLimit-Remaining | Llamadas que le quedan hoy |
X-RateLimit-Reset | Hora Unix del reinicio — medianoche UTC |
Retry-After | Segundos de espera, se envía solo con un 429; guíese por él: es correcto para ambos límites |
| Plan | Peticiones por segundo | Peticiones por día | Profundidad del historial |
|---|---|---|---|
| Free | Sin acceso a la API | — | 7 días |
| Pro | 10 | 10.000 | 30 días |
| Business | 50 | 100.000 | 90 días |
| Enterprise | 200 | Sin límite | 365 días |