Reten Docs

Event catalog

Tables, columns, repeated records and semi-joins available to build an event filter.

Catalog

The catalog answers what can be filtered. There are two routes: one lists the available tables and the other, for a table, everything it offers —scalar columns, RECORD REPEATED columns and semi-joins against related tables.

Without the catalog the definition is not buildable: there is no other way to know that attributes is a repeated record, that items[] has sub-fields, or that products reaches the product_properties table.

Auth: Required — event-criteria:view permission on both routes


GET /api/event-criterias/tables

Lists the catalog tables on which an event filter can be built. The catalog is identical across tenants: this route does not query the tenant's dataset.

Example

curl https://api.reten.ai/api/event-criterias/tables \
  -H "Authorization: Bearer <token>" \
  -H "x-tenant-id: <tenant-id>" \
  -H "x-project-id: <project-id>"
import axios from 'axios';

const response = await axios.get(
  'https://api.reten.ai/api/event-criterias/tables',
  { headers: { Authorization: 'Bearer <token>', 'x-tenant-id': '<tenant-id>', 'x-project-id': '<project-id>' } },
);
const tables = response.data;

Response 200 OK

An array of IEventTable:

FieldTypeDescription
tableNamestringTable name; it is the value that goes in from.table and in ColumnRefDto.table.
defaultTimeReferenceColumnstringOptional. TIMESTAMP column suggested as the time window's reference. Another TIMESTAMP column can be chosen.
requiresInnerJoinbooleantrue if the table can only participate as the main table of the from or as the target of an INNER JOIN.
[
  {
    "tableName": "event_transactions",
    "defaultTimeReferenceColumn": "event_date",
    "requiresInnerJoin": false
  }
]

The tables in this catalog do not declare identityColumn: an event filter projects events, not subjects. The field exists in the response shape for parity with the audience catalog, but here it always comes absent.


GET /api/event-criterias/tables/:tableName/columns

Returns everything the catalog offers about a table. Unlike /tables, this route reconciles the catalog against the real schema of the tenant's dataset before responding.

Path Parameters

ParameterTypeDescription
tableNamestringTable name, as returned by GET /tables.

Example

curl https://api.reten.ai/api/event-criterias/tables/event_transactions/columns \
  -H "Authorization: Bearer <token>" \
  -H "x-tenant-id: <tenant-id>" \
  -H "x-project-id: <project-id>"
import axios from 'axios';

const response = await axios.get(
  'https://api.reten.ai/api/event-criterias/tables/event_transactions/columns',
  { headers: { Authorization: 'Bearer <token>', 'x-tenant-id': '<tenant-id>', 'x-project-id': '<project-id>' } },
);
const entries = response.data;

Response 200 OK

An array of IEventCatalogEntry: a discriminated union by kind with three variants.

Narrow by kind before reading type or fields. Only the scalar variant carries type; only record and semiJoin carry fields. Reading entry.type without discriminating returns undefined for the other two variants.

  • kind: "scalar" — a column that can be filtered directly:

    FieldTypeDescription
    columnNamestringColumn name. For leaves of a non-repeated STRUCT it is the dotted path (pricing.final_amount).
    kind"scalar"Discriminator.
    typeCatalogFieldTypeEnumCatalog type; it determines which comparison operators it admits.
  • kind: "record" — a RECORD REPEATED column, filterable only with a record filter:

    FieldTypeDescription
    columnNamestringName of the repeated column.
    kind"record"Discriminator.
    fieldsIEventColumn[]Filterable sub-fields, relative to the record. It may contain other record.
  • kind: "semiJoin" — a related table reachable with a related table filter:

    FieldTypeDescription
    kind"semiJoin"Discriminator.
    semiJoinNamestringName of the semi-join; it is the value that goes in semiJoinPredicate.semiJoin.
    targetTablestringRelated table against which the filter is resolved.
    fieldsIEventColumn[]Filterable fields of the related table.

The fields of a record and of a semiJoin use the same scalar | record union, so the rule of narrowing by kind applies at every level.

Example response

GET /api/event-criterias/tables/event_transactions/columns (trimmed in the scalar columns for brevity; the records and the semi-join are complete):

[
  { "columnName": "event_id", "kind": "scalar", "type": "STRING" },
  { "columnName": "event_date", "kind": "scalar", "type": "TIMESTAMP" },
  { "columnName": "user_id", "kind": "scalar", "type": "STRING" },
  { "columnName": "status", "kind": "scalar", "type": "STRING" },
  { "columnName": "coupon_code", "kind": "scalar", "type": "STRING" },
  { "columnName": "pricing.net_amount", "kind": "scalar", "type": "FLOAT64" },
  { "columnName": "pricing.final_amount", "kind": "scalar", "type": "FLOAT64" },
  { "columnName": "payment_details.method", "kind": "scalar", "type": "STRING" },
  { "columnName": "payment_details.date", "kind": "scalar", "type": "TIMESTAMP" },
  { "columnName": "shipping_address.region", "kind": "scalar", "type": "STRING" },
  {
    "columnName": "attributes",
    "kind": "record",
    "fields": [
      { "columnName": "key", "kind": "scalar", "type": "STRING" },
      { "columnName": "value", "kind": "scalar", "type": "STRING" }
    ]
  },
  {
    "columnName": "items",
    "kind": "record",
    "fields": [
      { "columnName": "item_id", "kind": "scalar", "type": "STRING" },
      { "columnName": "name", "kind": "scalar", "type": "STRING" },
      { "columnName": "price", "kind": "scalar", "type": "FLOAT64" },
      { "columnName": "quantity", "kind": "scalar", "type": "FLOAT64" },
      { "columnName": "category", "kind": "scalar", "type": "STRING" }
    ]
  },
  {
    "kind": "semiJoin",
    "semiJoinName": "products",
    "targetTable": "product_properties",
    "fields": [
      { "columnName": "sku", "kind": "scalar", "type": "STRING" },
      { "columnName": "name", "kind": "scalar", "type": "STRING" },
      { "columnName": "categorization.family_name", "kind": "scalar", "type": "STRING" },
      { "columnName": "categorization.subfamily_name", "kind": "scalar", "type": "STRING" },
      { "columnName": "categorization.category_name", "kind": "scalar", "type": "STRING" },
      { "columnName": "categorization.brand_name", "kind": "scalar", "type": "STRING" },
      { "columnName": "categorization.collection_name", "kind": "scalar", "type": "STRING" },
      { "columnName": "commercial.base_price", "kind": "scalar", "type": "FLOAT64" },
      { "columnName": "composition.is_pack", "kind": "scalar", "type": "BOOLEAN" },
      { "columnName": "composition.is_combo", "kind": "scalar", "type": "BOOLEAN" }
    ]
  }
]

How each variant is used in the definition

VariantWhere it goes
scalarColumnRefDto.column of a predicate leaf, of the select, of the groupBy, of an aggregate or of the time window's reference.
recordcolumn of a recordPredicate leaf; its fields go in the field of the subWhere leaves.
semiJoinsemiJoin of a semiJoinPredicate leaf; its fields go in the field of the subWhere leaves.

The targetTable of a semi-join is not a catalog table: it does not appear in GET /tables, it cannot go in the from nor be the target of a join. It is only reached with a semiJoinPredicate leaf.

A semi-join is omitted from the response if the tenant's dataset does not have its related table: it is not an error, it is that this tenant does not have that data source. The absence of the semiJoin from the catalog is the signal that the filter is not available.

Error Responses

StatusDescription
401Missing or invalid Authorization: Bearer.
403The user does not have the event-criteria:view permission, or the x-tenant-id is not authorized.
404Only on /tables/:tableName/columns: the table is not in the catalog (La tabla no existe o no está en el catálogo de eventos.), or the tenant has no dataset configured (Dataset not configured for tenant <id>).
500Only on /tables/:tableName/columns: the real schema of the dataset does not satisfy the catalog (El schema de datos no satisface el catálogo de eventos.).

GET /api/event-criterias/tables does not query the tenant's dataset, so it only returns 200, 401 or 403.