Crear filtro de eventos
Crea un filtro de eventos a partir de su definición completa (bloques de consulta, filtros, ventana temporal y agregaciones).
POST /api/event-criterias
Crea un filtro de eventos a partir de su definición completa. La operación es transaccional: el filtro y sus bloques de consulta se crean juntos, o no se crea nada.
Auth: Requerida — permiso event-criteria:create
Cuerpo de la solicitud
Nivel raíz (CreateEventCriteriaDto):
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre del filtro. No puede ser vacío. |
description | string | No | Descripción de texto libre. Si se omite, la respuesta la devuelve como null. |
queryBlocks | QueryBlockDto[] | Sí | Mínimo 1 elemento. Cada bloque ≈ un statement SQL completo. |
La estructura de cada bloque —order, setOperator, from, select, timeWindow,
where, groupBy, having— está en
Definición.
No existe composedWith: un filtro de eventos no se compone con otros filtros. Enviarlo
produce un 400 por propiedad desconocida.
Ejemplos
Filtro de columna
Eventos cuyo status es Facturada.
curl -X POST https://api.reten.ai/api/event-criterias \
-H "Authorization: Bearer <token>" \
-H "x-tenant-id: <tenant-id>" \
-H "x-project-id: <project-id>" \
-H "Content-Type: application/json" \
-d '{
"name": "Venta oficial — solo facturada",
"description": "Definición canónica de evento válido",
"queryBlocks": [
{
"order": 0,
"from": { "table": "event_transactions", "joins": [] },
"select": {
"distinct": true,
"items": [
{ "kind": "column", "column": { "table": "event_transactions", "column": "event_id" } }
]
},
"where": {
"kind": "group",
"logicalOperator": "AND",
"children": [
{
"kind": "predicate",
"column": { "table": "event_transactions", "column": "status" },
"comparisonOperator": "EQUALS",
"value": "Facturada"
}
]
}
}
]
}'import axios from 'axios';
const body = {
name: 'Venta oficial — solo facturada',
description: 'Definición canónica de evento válido',
queryBlocks: [
{
order: 0,
from: { table: 'event_transactions', joins: [] },
select: {
distinct: true,
items: [
{ kind: 'column', column: { table: 'event_transactions', column: 'event_id' } },
],
},
where: {
kind: 'group',
logicalOperator: 'AND',
children: [
{
kind: 'predicate',
column: { table: 'event_transactions', column: 'status' },
comparisonOperator: 'EQUALS',
value: 'Facturada',
},
],
},
},
],
};
const response = await axios.post(
'https://api.reten.ai/api/event-criterias',
body,
{ headers: { Authorization: 'Bearer <token>', 'x-tenant-id': '<tenant-id>', 'x-project-id': '<project-id>' } },
);
const created = response.data;Filtro de registro
Eventos que tienen un atributo cuya key es documento_tipo y cuyo value es
factura — las dos condiciones sobre el mismo elemento de attributes.
{
"name": "Documentos tipo factura",
"queryBlocks": [
{
"order": 0,
"from": { "table": "event_transactions", "joins": [] },
"select": {
"distinct": true,
"items": [
{ "kind": "column", "column": { "table": "event_transactions", "column": "event_id" } }
]
},
"where": {
"kind": "group",
"logicalOperator": "AND",
"children": [
{
"kind": "recordPredicate",
"column": { "table": "event_transactions", "column": "attributes" },
"subWhere": {
"kind": "group",
"logicalOperator": "AND",
"children": [
{ "kind": "predicate", "field": "key", "comparisonOperator": "EQUALS", "value": "documento_tipo" },
{ "kind": "predicate", "field": "value", "comparisonOperator": "EQUALS", "value": "factura" }
]
}
}
]
}
}
]
}Filtro de tabla relacionada
Eventos facturados con al menos una línea cuyo producto es de categoría Food Service u
HORECA. El camino hasta product_properties lo resuelve el
catálogo: la solicitud solo nombra el
semi-join.
{
"name": "Proyecto Food Service",
"queryBlocks": [
{
"order": 0,
"from": { "table": "event_transactions", "joins": [] },
"select": {
"distinct": true,
"items": [
{ "kind": "column", "column": { "table": "event_transactions", "column": "event_id" } }
]
},
"where": {
"kind": "group",
"logicalOperator": "AND",
"children": [
{
"kind": "predicate",
"column": { "table": "event_transactions", "column": "status" },
"comparisonOperator": "EQUALS",
"value": "Facturada"
},
{
"kind": "semiJoinPredicate",
"table": "event_transactions",
"semiJoin": "products",
"subWhere": {
"kind": "group",
"logicalOperator": "AND",
"children": [
{
"kind": "predicate",
"field": "categorization.category_name",
"comparisonOperator": "IN",
"value": ["Food Service", "HORECA"]
}
]
}
}
]
}
}
]
}Respuesta 201 Created
Devuelve el filtro creado como IEventCriteriaDetail — la misma forma que
GET /event-criterias/:id: el recurso base más
queryBlocks[], con su id ya resuelto y ordenados por order ascendente.
| Campo | Tipo | Descripción |
|---|---|---|
id | string (UUID) | Id del filtro creado. |
projectId | string (UUID) | Proyecto al que pertenece el filtro. |
name | string | |
description | string | null | null si no se envió. |
isActive | boolean | Siempre true: ningún endpoint lo modifica. |
ownerId | string (UUID) | Usuario creador. |
updatedBy | string (UUID) | Último editor (en la creación, el creador). |
createdAt | string (ISO 8601) | |
updatedAt | string (ISO 8601) | |
queryBlocks | array | Los bloques persistidos, con su id. |
{
"id": "9f3a1c22-4b7e-4c31-9a8d-2f5e6b7c8d90",
"projectId": "3f6c2b1a-8d4e-4f7a-9b2c-5e1d0a7f6c34",
"name": "Venta oficial — solo facturada",
"description": "Definición canónica de evento válido",
"isActive": true,
"ownerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"updatedBy": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"createdAt": "2026-07-10T09:12:44.005Z",
"updatedAt": "2026-07-10T09:12:44.005Z",
"queryBlocks": [
{
"id": "e5f6a708-91b2-4c33-8d44-5e6f7a8b9c01",
"order": 0,
"setOperator": null,
"from": { "table": "event_transactions", "joins": [] },
"select": {
"distinct": true,
"items": [
{ "kind": "column", "column": { "table": "event_transactions", "column": "event_id" } }
]
},
"timeWindow": null,
"where": {
"kind": "group",
"logicalOperator": "AND",
"children": [
{
"kind": "predicate",
"column": { "table": "event_transactions", "column": "status" },
"comparisonOperator": "EQUALS",
"value": "Facturada"
}
]
},
"groupBy": null,
"having": null
}
]
}Reglas de validación
La definición se valida antes de persistirse: un filtro que no compila a SQL no se crea. El catálogo completo de reglas y sus mensajes exactos está en Definición → Reglas de validación.
Respuestas de error
| Estado | Descripción |
|---|---|
400 | DTO inválido (campo faltante, tipo incorrecto, enum fuera de rango, propiedad desconocida) o una regla de negocio incumplida. |
401 | Falta o es inválido el Authorization: Bearer. |
403 | El usuario no tiene el permiso event-criteria:create, o el x-tenant-id no está autorizado. |