Reten Docs

Event Filters

Select events with a query-builder, without writing SQL, and generate, validate and preview the resulting query.

Overview

An event filter (event criteria) is a set of events selected with a query-builder —table → columns → filters → time window → aggregations— without writing SQL by hand.

The definition is assembled by composing:

PieceWhat it provides
Query blocksOne or more blocks; each block starts from a table of the events catalog and defines on it columns, filters, time and aggregations.
Column filtersConditions over a scalar column with a comparison operator (EQUALS, IN, BETWEEN, …).
Record filtersConditions over a RECORD REPEATED column (attributes, items): there is at least one element that satisfies the sub-filter.
Related table filtersConditions over a semi-join declared by the catalog (products): there is at least one match in the related table.
Time windowNarrows the block to a time period (IN_THE_LAST 30 DAYS, SINCE, …).
AggregationsSummarizes block columns into a metric (COUNT, SUM, AVG, …).

The full tree —with the three where leaves and all their fields— is documented once in Definition; the endpoint pages reference it instead of repeating it.

No identity column

An event filter projects events, not subjects: there is no mandatory identity column and the generated SQL returns subjectColumn: null. That is the structural difference with audiences, which do have to expose their identity in at least one block.

Endpoints

Base URL and environments

All routes hang off the global prefix /api under the /event-criterias resource (for example POST /api/event-criterias).

Reten Environments

EnvironmentAdmin PanelAPI Base URL
Developmentapp-development.reten.aihttps://api-development.reten.ai
Stagingapp-staging.reten.aihttps://api-staging.reten.ai
Productionapp.reten.aihttps://api.reten.ai

Use the admin panel URL to manage API keys and dispatch configurations. Replace BASE_URL in code examples with the API base URL for your environment.

Authentication

All endpoints require a JWT Bearer token, the x-tenant-id header that identifies the tenant on whose schema the request operates, and the x-project-id header that identifies the project the request works in (see Authentication → Project Context).

HeaderRequiredValue
AuthorizationYesBearer <access_token>
x-tenant-idYesTenant UUID
x-project-idYesProject UUID
-H "Authorization: Bearer <access_token>"
-H "x-tenant-id: <tenant-id>"
-H "x-project-id: <project-id>"

Permissions

Each route requires a specific permission:

PermissionEndpoints
event-criteria:viewGET /event-criterias, GET /event-criterias/:id, GET /tables, GET /tables/:tableName/columns
event-criteria:createPOST /event-criterias
event-criteria:updatePATCH /event-criterias/:id
event-criteria:deleteDELETE /event-criterias/:id
event-criteria:view-sqlPOST /generate-sql, GET /:id/sql, POST /validate-from-body, POST /preview-from-body, POST /:id/preview

The catalog (/tables and /tables/:tableName/columns) requires event-criteria:view, the same read permission of the resource: whoever can see a filter can see what it is built with.

Status codes

The read-only POST endpoints (generate-sql, validate-from-body, preview-from-body, :id/preview) respond 201 Created —not 200—, even though they don't create any resource.

Method + routeCodeResponse body
POST /event-criterias (create)201The created filter
GET /event-criterias200Paginated list
GET /event-criterias/:id200The filter
GET /event-criterias/tables200Catalog tables
GET /tables/:tableName/columns200The table's columns and semi-joins
PATCH /event-criterias/:id200The updated filter
DELETE /event-criterias/:id204(no body)
POST /generate-sql201Generated SQL
GET /:id/sql200Generated SQL
POST /validate-from-body201Validation result
POST /preview-from-body201Sample result
POST /:id/preview201Sample result

Error format

Validation, authorization and resolution errors follow the API's standard error format:

{
  "statusCode": 400,
  "message": ["name should not be empty"],
  "error": "Bad Request"
}

On DTO validation errors, message is an array of strings (one entry per broken rule). Validation is strict: undeclared properties are rejected, so sending an unknown field produces a 400.

Common errors in this API:

  • 400 Bad Request — invalid definition or DTO (missing field, wrong type, enum out of range, unknown property), or a broken business rule.
  • 401 Unauthorized — the Authorization: Bearer is missing or invalid.
  • 403 Forbidden — the user lacks the required permission, or the x-tenant-id is not authorized.
  • 404 Not Found — the requested id does not exist in the tenant (Event criteria not found).

Pagination

The list wraps results in PaginatedResponseDto<T>:

{
  "data": [],
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total": 0,
    "total_pages": 0,
    "has_next": false,
    "has_previous": false
  }
}

The fields inside pagination use snake_case (per_page, total_pages, has_next, has_previous), unlike the rest of the resource which uses camelCase.

The detail of the pagination parameters is documented in List.

Enum glossary

Quick reference catalog. The field where each one appears and its exact shape are in Definition.

SetOperatorEnum

Combination of query blocks within the same filter (a block's setOperator).

  • UNION_DISTINCT · UNION_ALL · INTERSECT_DISTINCT

LogicalOperatorEnum

Chaining of predicates within a group of the filter tree.

  • AND · OR

ComparisonOperatorEnum

Operator of a predicate over a column or over a sub-field.

  • EQUALS · NOT_EQUALS · GREATER_THAN · LESS_THAN · GREATER_THAN_OR_EQUAL · LESS_THAN_OR_EQUAL · CONTAINS · NOT_CONTAINS · STARTS_WITH · ENDS_WITH · IS_NULL · IS_NOT_NULL · IN · NOT_IN · BETWEEN

AggregationOperatorEnum

Aggregation function over an operand (a column, * or an arithmetic expression).

  • COUNT · SUM · AVG · MIN · MAX

ArithmeticOperatorEnum

Operator of an arithmetic expression inside an aggregate's operand. SAFE_DIVIDE yields NULL when the denominator is zero.

  • ADD · SUBTRACT · MULTIPLY · SAFE_DIVIDE

TimeOperatorEnum

Operator of the time window (timeWindow).

  • ALL_TIME · IN_THE_LAST · IN_THE_FIRST · SINCE · BETWEEN

IN_THE_FIRST is not supported in this resource: the "in the first N" window anchors to the lifetime origin of a subject, and an event filter has no subject. Sending it responds 400 with timeWindow IN_THE_FIRST is not supported: the catalog does not declare a lifetime origin.

TimeUnitEnum

Unit of the time window.

  • DAYS · WEEKS · MONTHS · YEARS

JoinTypeEnum

Type of join between catalog tables.

  • INNER · LEFT · RIGHT · FULL

CatalogFieldTypeEnum

Data type of a scalar column of the events catalog. It determines which comparison operators it accepts.

  • STRING · TIMESTAMP · BOOLEAN · FLOAT64 · INT64 · NUMERIC · BIGNUMERIC

Differences from audiences

Both resources share the query-builder, but they are not symmetric. If you arrive from audiences, these are the assumptions that do not carry over:

AspectAudiencesEvent filters
Composition with other criteriacomposedWithDoes not exist
Identity columnMandatory in ≥1 block; 400 if missingNot applicable — it projects events, not subjects
subjectColumn of the SQLThe identity columnAlways null
IN_THE_FIRSTSupported400 — with no subject there is no lifetime origin to anchor to
Validate by idPOST /:id/validateDoes not exist; only POST /validate-from-body
List countsqueryBlockCount, compositionCountconditionCount — where leaves of every block
Catalog — columnsisIdentity and isDefaultTimeReference per columnNeither; the time reference belongs to the table (defaultTimeReferenceColumn)
Catalog — semi-joinsNot declaredproducts → product_properties
Filter tree leavespredicate, recordPredicatepredicate, recordPredicate, semiJoinPredicate
finalCteName of the SQLThe one from the audiences domainCTE_VALID_EVENTS