Saltar al contenido principal

API de eventos

Rastrea eventos y comportamiento de usuarios mediante programación con la API REST.

Todos los endpoints de esta página son relativos a la URL base: https://api-eu1.joryio.com. Consulta el resumen de la API.

El evento de compra

Los informes de ingresos, la atribución, el CLV y los modelos predictivos leen un solo evento. Si envías las compras con otro nombre, no se cuentan en ningún sitio.

Nombre del eventoOrder Completed
Propiedades obligatoriastotal, currency
Recomendadastotal_base, base_currency, orderId
{
"eventName": "Order Completed",
"userId": "user_123",
"properties": {
"total": 149.90,
"currency": "EUR",
"total_base": 162.35,
"base_currency": "USD",
"orderId": "1024"
}
}

Por qué solo un nombre

Otras plataformas usan otros nombres: Placed Order (Klaviyo), purchase (GA4). No los aceptamos deliberadamente, porque aceptar varios nombres implica sumarlos: una tienda que ejecute una etiqueta de GA4 junto a nuestro conector enviaría una misma venta con dos nombres y vería sus ingresos duplicados. Una cifra de ingresos silenciosamente multiplicada por dos es mucho más difícil de detectar que una que es evidentemente cero.

Por eso la regla es un único contrato publicado. Si tus pedidos no aparecen, la causa se ve de inmediato durante la integración - y se puede corregir - en lugar de estar en silencio equivocada durante meses.

Sobre los importes

total y total_base son dos cifras distintas, no alternativas:

  • total: lo que pagó el cliente, en la moneda en que pagó.
  • total_base + base_currency: el mismo pedido convertido a tu moneda de referencia. Envíalos si vendes en más de una moneda, para que los totales sumen correctamente.

Envía solo total si tienes una única moneda. orderId es opcional pero recomendable: evita duplicar un pedido que llega más de una vez (un reintento, una recarga de la página de pago).

Si ya envías otro nombre

Tus eventos históricos se conservan, pero no se tratan como pedidos. Cambia los pedidos nuevos a Order Completed y los informes de ingresos empezarán desde ese momento. No reescribimos eventos pasados, así que nada se reinterpreta en silencio.

Autenticación

Todas las solicitudes requieren autenticación mediante clave de API:

Authorization: Bearer jry_live_your_api_key_here
Content-Type: application/json

Rastrear un evento

Rastrea un evento único de usuario con propiedades opcionales.

Este endpoint acepta dos formatos de cuerpo: un objeto de evento único (documentado aquí) o una matriz JSON de objetos de evento para rastreo por lotes (máx. 500). Consulta rastrear varios eventos (cuerpo de matriz).

Endpoint

POST /events/track

Cuerpo de la solicitud

CampoTipoObligatorioDescripción
userIdcadenaSí*Tu identificador de usuario. *Se requiere uno de userId, joryioUserId, anonymousId o userAlias.
eventNamecadenaNombre del evento (máx. 255 caracteres).
propertiesobjetoNoPropiedades del evento (máx. 200 claves de nivel superior, 50 KB y profundidad de anidación 5).
timestampcadena o númeroNoMarca de tiempo del evento (cadena ISO 8601 o milisegundos epoch; predeterminado: ahora).
joryioUserIdcadenaNoID de usuario interno de Joryio: el id de 24 caracteres hexadecimales devuelto por la API de usuarios (alternativa a userId).
anonymousIdcadenaNoID de visitante anónimo (identificador alternativo).
userAliasobjetoNo{ aliasLabel, aliasName }: identificador de alias (alternativa a userId).
sessionIdcadenaNoIdentificador de sesión.
deviceIdcadenaNoIdentificador de dispositivo.
clientEventIdcadenaNoID de evento generado por el cliente; se usa como ID almacenado, por lo que los reintentos con el mismo valor se deduplican.

Solicitud de ejemplo

curl -X POST https://api-eu1.joryio.com/events/track \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_123",
"eventName": "Order Completed",
"properties": {
"orderId": "order_456",
"total": 99.99,
"currency": "USD",
"items": 3,
"paymentMethod": "credit_card"
},
"timestamp": "2024-01-20T14:30:00.000Z"
}'

Respuesta

El formato de objeto único devuelve el ID del evento almacenado:

{
"eventId": "9b2f6c1e-4a8d-4f0b-9c3d-2e1f5a6b7c8d",
"success": true
}

Notas

  • Los eventos se procesan de forma asíncrona.
  • Usa nombres de evento coherentes (consulta prácticas recomendadas para nombres de eventos).
  • Las propiedades se indexan para segmentación.
  • Si no se proporciona timestamp, se usa la hora del servidor.

Rastrear varios eventos (cuerpo de matriz)

No hay un endpoint de lotes independiente: POST /events/track acepta un objeto de evento único o una matriz JSON de objetos de evento, sin objeto envoltorio. El formato de matriz rastrea hasta 500 eventos en una solicitud.

Endpoint

POST /events/track

Cuerpo de la solicitud

Una matriz JSON de hasta 500 elementos. Cada elemento sigue el mismo formato que el objeto único.

Cada elemento recibe una validación completa. Un elemento no válido se informa en rejected mediante su índice de matriz, nunca se acepta silenciosamente, y el resto de elementos válidos se procesa de todos modos.

Solicitud de ejemplo

curl -X POST https://api-eu1.joryio.com/events/track \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '[
{
"userId": "user_123",
"eventName": "Product Viewed",
"properties": {
"productId": "prod_456",
"price": 49.99
}
},
{
"userId": "user_123",
"eventName": "Added To Cart",
"properties": {
"productId": "prod_456",
"quantity": 1
}
},
{
"userId": "user_456",
"eventName": "Page Viewed",
"properties": {
"page": "/pricing"
}
}
]'

Respuesta

A diferencia del formato de objeto, que devuelve { eventId, success }, el formato de matriz devuelve un resumen agregado:

{
"processed": 3,
"accepted": 3,
"rejected": []
}
CampoDescripción
processedNúmero de elementos recibidos en la matriz de solicitud.
acceptedEventos registrados realmente.
rejectedErrores por elemento: index (posición en la matriz de solicitud), name (nombre del evento del elemento, cuando existe) y reason.

Ejemplo con un elemento no válido:

{
"processed": 3,
"accepted": 2,
"rejected": [
{
"index": 1,
"name": "Added To Cart",
"reason": "property hacker should not exist"
}
]
}

Límites

  • Máximo de 500 eventos por solicitud (si hay más, devuelve 400); una matriz vacía también devuelve 400.
  • Cada evento sigue el mismo formato que el objeto único.
  • El procesamiento por lotes no es atómico: los eventos válidos se registran aunque se rechacen algunos elementos. Consulta rejected para los fallos parciales.

Consultar eventos

Recupera eventos con filtrado y paginación. No existe un endpoint para obtener por ID de evento: filtra esta consulta en su lugar.

Endpoint

GET /events/query

Parámetros de consulta

ParámetroTipoPredeterminadoDescripción
userIdcadena-Filtra por ID de usuario.
eventNamecadena-Filtra por nombre de evento.
startDatecadena-Filtra eventos posteriores a esta fecha (ISO 8601).
endDatecadena-Filtra eventos anteriores a esta fecha (ISO 8601).
limitnúmero100Resultados por página (máx. 1000).
offsetnúmero0Número de eventos que se omitirán.

Solicitud de ejemplo

# Obtiene todos los eventos "Order Completed" de enero de 2024
curl -X GET "https://api-eu1.joryio.com/events/query?eventName=Order+Completed&startDate=2024-01-01T00:00:00Z&endDate=2024-02-01T00:00:00Z&limit=100" \
-H "Authorization: Bearer jry_live_your_api_key"

Respuesta

Una matriz JSON sin envoltorio, del más reciente al más antiguo. Los campos de evento usan snake_case (proceden del almacén de analítica):

[
{
"event_id": "9b2f6c1e-4a8d-4f0b-9c3d-2e1f5a6b7c8d",
"user_id": "665f1e2a9b3c4d5e6f7a8b9c",
"anonymous_id": "",
"event_name": "Order Completed",
"properties": {
"orderId": "order_456",
"total": 99.99
},
"timestamp": "2024-01-20 14:30:00",
"session_id": "",
"device_id": ""
},
{
"event_id": "1c3e5a7b-9d2f-4b6c-8e0a-3f5d7b9c1e2a",
"user_id": "665f1e2a9b3c4d5e6f7a8b9d",
"anonymous_id": "",
"event_name": "Order Completed",
"properties": {
"orderId": "order_789",
"total": 149.99
},
"timestamp": "2024-01-19 10:15:00",
"session_id": "",
"device_id": ""
}
]

Agregación de eventos

Obtiene estadísticas agregadas de eventos con agrupaciones y métricas.

Endpoint

POST /events/aggregate

Cuerpo de la solicitud

CampoTipoObligatorioDescripción
eventNamecadenaNombre del evento que se agregará.
startDatecadenaNoFecha inicial (ISO 8601).
endDatecadenaNoFecha final (ISO 8601).
groupBycadenaNoAgrupación temporal: hour, day, week, month (predeterminado: day).
metricsmatrizNoMétricas que se calcularán: count, sum, avg, min, max (predeterminado: ['count']).
sumFieldcadenaNoNombre de la clave de properties que se sumará/agregará, por ejemplo total.
avgFieldcadenaNoNombre de la clave de properties de la que se calculará la media.
eventPropertiesobjetoNoFiltra por propiedades de evento.

Solicitud de ejemplo

curl -X POST https://api-eu1.joryio.com/events/aggregate \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"eventName": "Order Completed",
"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-02-01T00:00:00Z",
"groupBy": "day",
"metrics": ["count", "sum"],
"sumField": "total"
}'

Respuesta

{
"success": true,
"data": {
"eventName": "Order Completed",
"groupBy": "day",
"metrics": ["count", "sum"],
"results": [
{
"period": "2024-01-01T00:00:00Z",
"count": 45,
"sum_value": 4567.89
},
{
"period": "2024-01-02T00:00:00Z",
"count": 52,
"sum_value": 5123.45
},
{
"period": "2024-01-03T00:00:00Z",
"count": 38,
"sum_value": 3890.12
}
],
"total": 3
}
}

Métricas compatibles

  • count: número total de eventos.
  • sum: suma de los valores del campo indicado.
  • avg: media de los valores del campo indicado.
  • min: valor mínimo del campo indicado.
  • max: valor máximo del campo indicado.

Ejemplo: análisis de ingresos

# Obtiene ingresos diarios de compras
curl -X POST https://api-eu1.joryio.com/events/aggregate \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"eventName": "Order Completed",
"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-01-31T00:00:00Z",
"groupBy": "day",
"metrics": ["count", "sum", "avg"],
"sumField": "total"
}'

Ejemplo: uso de funcionalidades por hora

# Rastrea patrones de uso de funcionalidades por hora
curl -X POST https://api-eu1.joryio.com/events/aggregate \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"eventName": "Feature Used",
"startDate": "2024-01-20T00:00:00Z",
"endDate": "2024-01-21T00:00:00Z",
"groupBy": "hour",
"metrics": ["count"]
}'

Eventos comunes

Eventos de e-commerce

// Producto visto
POST /events/track
{
"userId": "user_123",
"eventName": "Product Viewed",
"properties": {
"productId": "prod_456",
"productName": "Premium Plan",
"category": "Subscription",
"price": 99.99,
"currency": "USD"
}
}

// Añadido al carrito
POST /events/track
{
"userId": "user_123",
"eventName": "Added To Cart",
"properties": {
"productId": "prod_456",
"quantity": 1,
"price": 99.99
}
}

// Pedido completado
POST /events/track
{
"userId": "user_123",
"eventName": "Order Completed",
"properties": {
"orderId": "order_789",
"total": 249.99,
"currency": "USD",
"itemCount": 3,
"discount": 25.00,
"paymentMethod": "credit_card"
}
}

Eventos de ciclo de vida de usuario

// Registro completado
POST /events/track
{
"userId": "user_123",
"eventName": "Signup Completed",
"properties": {
"method": "email",
"source": "homepage_cta"
}
}

// Incorporación completada
POST /events/track
{
"userId": "user_123",
"eventName": "Onboarding Completed",
"properties": {
"stepsCompleted": 5,
"timeSpent": "8m 30s"
}
}

// Prueba iniciada
POST /events/track
{
"userId": "user_123",
"eventName": "Trial Started",
"properties": {
"plan": "premium",
"trialDays": 14
}
}

Eventos de interacción

// Funcionalidad utilizada
POST /events/track
{
"userId": "user_123",
"eventName": "Feature Used",
"properties": {
"featureName": "export",
"exportFormat": "csv",
"recordCount": 1500
}
}

// Página vista
POST /events/track
{
"userId": "user_123",
"eventName": "Page Viewed",
"properties": {
"page": "/pricing",
"category": "Marketing",
"referrer": "google"
}
}

Propiedades de evento

Prácticas recomendadas

Usa nombres de propiedad descriptivos:

Bien:

{
"properties": {
"productId": "prod_123",
"productName": "Premium Plan",
"price": 99.99,
"currency": "USD"
}
}

Mal:

{
"properties": {
"pid": "prod_123",
"n": "Premium Plan",
"p": 99.99
}
}

Tipos de datos compatibles

{
"properties": {
"string": "value",
"number": 99.99,
"integer": 5,
"boolean": true,
"date": "2024-01-15T10:30:00Z",
"array": ["tag1", "tag2"],
"object": {
"nested": "value",
"deep": {
"property": "value"
}
}
}
}

Propiedades reservadas

Las propiedades que empiezan por $ están reservadas para uso del sistema:

  • $app_id: identificador de app.
  • $app_name: nombre de app.
  • $platform: plataforma (web, ios, android).
  • $session_id: identificador de sesión.
  • $anonymous_id: ID de usuario anónimo.

No uses estos nombres en propiedades personalizadas.


Límites de eventos

Límites de tamaño

LímiteValor
Longitud máxima del nombre de evento255 caracteres
Longitud máxima de identificador (userId, anonymousId, sessionId, deviceId, clientEventId)255 caracteres
Máximo de claves de propiedad de nivel superior por evento200
Tamaño máximo de propiedades (JSON)50 KB
Profundidad máxima de anidación de propiedades5 niveles
Máximo de eventos por solicitud de cuerpo de matriz500

Límites de frecuencia

La API de eventos no tiene hoy límites de frecuencia fijos por endpoint. Consulta resumen de la API: límites de frecuencia.


Respuestas de error

Todos los errores usan el cuerpo de error estándar. Consulta resumen de la API: respuesta de error.

400 Solicitud incorrecta: error de validación

{
"statusCode": 400,
"message": "Bad Request Exception",
"timestamp": "2026-01-15T10:30:00.000Z",
"path": "/events/track",
"errors": [
"eventName should not be empty"
]
}

400 Solicitud incorrecta: propiedades demasiado grandes

{
"statusCode": 400,
"message": "Event properties exceed maximum size of 50KB (received 63KB)",
"timestamp": "2026-01-15T10:30:00.000Z",
"path": "/events/track"
}

Prácticas recomendadas

1. Agrupar eventos cuando sea posible

Bien: agrupa varios eventos con un cuerpo de matriz:

await fetch('/events/track', {
method: 'POST',
body: JSON.stringify([event1, event2, event3])
});

Mal: solicitudes individuales:

await fetch('/events/track', { method: 'POST', body: JSON.stringify(event1) });
await fetch('/events/track', { method: 'POST', body: JSON.stringify(event2) });
await fetch('/events/track', { method: 'POST', body: JSON.stringify(event3) });

2. Usar nombres de evento coherentes

Sigue el patrón «objeto + verbo en pasado»:

Bien: Product Viewed, Order Completed, Trial Started. Mal: view_product, clicked, user_action_123.

3. Incluir marcas de tiempo

Para los eventos históricos, incluye siempre marcas de tiempo precisas:

{
"userId": "user_123",
"eventName": "Order Completed",
"timestamp": "2024-01-15T10:30:00.000Z", // Hora real del evento
"properties": { ... }
}

4. Mantener las propiedades ligeras

Incluye solo propiedades relevantes:

Bien:

{
"eventName": "Order Completed",
"properties": {
"orderId": "order_123",
"total": 99.99,
"currency": "USD"
}
}

Mal:

{
"eventName": "Order Completed",
"properties": {
"orderId": "order_123",
"total": 99.99,
"currency": "USD",
"userAgent": "Mozilla/5.0...", // Demasiado detalle
"sessionData": { /* objeto grande */ },
"cookies": [ /* matriz de cookies */ ]
}
}

5. Gestionar errores correctamente

Implementa lógica de reintento con espera exponencial:

async function trackWithRetry(event, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch('/events/track', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(event)
});

if (response.ok) return await response.json();

if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || Math.pow(2, i);
await sleep(retryAfter * 1000);
continue;
}

throw new Error(`HTTP ${response.status}`);
} catch (error) {
if (i === maxRetries - 1) throw error;
await sleep(Math.pow(2, i) * 1000); // 1s, 2s, 4s
}
}
}

Depuración

Activar el modo de depuración (SDK)

Al usar el SDK web:

import JoryioSDK from '@joryio/web-sdk';

const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_...',
enableDebug: true // Registra todos los eventos en consola
});

Verificar eventos en el dashboard

  1. Ve a Usuarios y busca un usuario.
  2. Haz clic en la pestaña Actividad.
  3. Consulta todos los eventos rastreados.

Problemas comunes

Los eventos no aparecen:

  • Verifica que la clave de API sea correcta.
  • Comprueba que el usuario esté identificado.
  • Asegúrate de que el nombre de evento y las propiedades sean válidos.
  • Comprueba los límites de frecuencia.

Las propiedades no se muestran:

  • Verifica que los nombres de propiedad sean correctos.
  • Comprueba que los tipos de datos sean compatibles.
  • Evita nombres de propiedades reservados (prefijo $).

SDK

Para una integración más sencilla, usa los SDK oficiales:


Siguientes pasos