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 evento | Order Completed |
| Propiedades obligatorias | total, currency |
| Recomendadas | total_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
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
userId | cadena | Sí* | Tu identificador de usuario. *Se requiere uno de userId, joryioUserId, anonymousId o userAlias. |
eventName | cadena | Sí | Nombre del evento (máx. 255 caracteres). |
properties | objeto | No | Propiedades del evento (máx. 200 claves de nivel superior, 50 KB y profundidad de anidación 5). |
timestamp | cadena o número | No | Marca de tiempo del evento (cadena ISO 8601 o milisegundos epoch; predeterminado: ahora). |
joryioUserId | cadena | No | ID de usuario interno de Joryio: el id de 24 caracteres hexadecimales devuelto por la API de usuarios (alternativa a userId). |
anonymousId | cadena | No | ID de visitante anónimo (identificador alternativo). |
userAlias | objeto | No | { aliasLabel, aliasName }: identificador de alias (alternativa a userId). |
sessionId | cadena | No | Identificador de sesión. |
deviceId | cadena | No | Identificador de dispositivo. |
clientEventId | cadena | No | ID 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": []
}
| Campo | Descripción |
|---|---|
processed | Número de elementos recibidos en la matriz de solicitud. |
accepted | Eventos registrados realmente. |
rejected | Errores 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 devuelve400. - 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
rejectedpara 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ámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
userId | cadena | - | Filtra por ID de usuario. |
eventName | cadena | - | Filtra por nombre de evento. |
startDate | cadena | - | Filtra eventos posteriores a esta fecha (ISO 8601). |
endDate | cadena | - | Filtra eventos anteriores a esta fecha (ISO 8601). |
limit | número | 100 | Resultados por página (máx. 1000). |
offset | número | 0 | Nú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
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
eventName | cadena | Sí | Nombre del evento que se agregará. |
startDate | cadena | No | Fecha inicial (ISO 8601). |
endDate | cadena | No | Fecha final (ISO 8601). |
groupBy | cadena | No | Agrupación temporal: hour, day, week, month (predeterminado: day). |
metrics | matriz | No | Métricas que se calcularán: count, sum, avg, min, max (predeterminado: ['count']). |
sumField | cadena | No | Nombre de la clave de properties que se sumará/agregará, por ejemplo total. |
avgField | cadena | No | Nombre de la clave de properties de la que se calculará la media. |
eventProperties | objeto | No | Filtra 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ímite | Valor |
|---|---|
| Longitud máxima del nombre de evento | 255 caracteres |
Longitud máxima de identificador (userId, anonymousId, sessionId, deviceId, clientEventId) | 255 caracteres |
| Máximo de claves de propiedad de nivel superior por evento | 200 |
| Tamaño máximo de propiedades (JSON) | 50 KB |
| Profundidad máxima de anidación de propiedades | 5 niveles |
| Máximo de eventos por solicitud de cuerpo de matriz | 500 |
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
- Ve a Usuarios y busca un usuario.
- Haz clic en la pestaña Actividad.
- 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:
- SDK web: guía de integración.
- SDK de iOS: Swift Package / CocoaPods.
- SDK de Android: Gradle.
- SDK de React Native: npm install @joryio/react-native-sdk.