Validate
Validates an event filter definition with a BigQuery dry-run and returns the estimated cost, without running the query.
POST /api/event-criterias/validate-from-body
Validates an event filter definition: it compiles it to SQL and submits it to a BigQuery dry-run, which checks the query against the real schema and estimates its cost without running it.
Auth: Required — event-criteria:view-sql permission
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
queryBlocks | QueryBlockDto[] | Yes | At least 1 element. The definition to validate. |
The structure of each block is in Definition.
This endpoint receives only the definition: name, description and format are
not part of the body and sending them produces a 400 for unknown property.
Example
curl -X POST https://api.reten.ai/api/event-criterias/validate-from-body \
-H "Authorization: Bearer <token>" \
-H "x-tenant-id: <tenant-id>" \
-H "x-project-id: <project-id>" \
-H "Content-Type: application/json" \
-d '{
"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 = {
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/validate-from-body',
body,
{ headers: { Authorization: 'Bearer <token>', 'x-tenant-id': '<tenant-id>', 'x-project-id': '<project-id>' } },
);
const { valid, errors, bytesProcessed } = response.data;Response
Status 201 Created. The body reports the result of the dry-run:
| Field | Type | Required | Description |
|---|---|---|---|
valid | boolean | Yes | true if the dry-run succeeded; false if BigQuery rejected the query. |
errors | string[] | No | Present only when valid: false. Contains the BigQuery error message(s). |
bytesProcessed | number | Yes | Bytes BigQuery estimates it will process. On success, the dry-run estimate; on failure, 0. |
The dry-run does not execute the query or return rows: it only validates it against BigQuery and estimates its cost. To get a sample of real rows use Preview; to see the generated SQL, Generate SQL.
errors is an array by contract, but in practice the dry-run returns a single
message (the one BigQuery reports). Always discriminate by valid before reading
errors.
Example — valid (valid: true)
{
"valid": true,
"bytesProcessed": 10485760
}With valid: true, errors is omitted and bytesProcessed carries the BigQuery
estimate (in this example, ~10 MB).
Example — invalid (valid: false)
The definition passed structural and business validation and compiled to SQL, but the
BigQuery dry-run rejected it. Even so, the status is 201:
{
"valid": false,
"errors": [
"Unrecognized name: legacy_column at [3:8]"
],
"bytesProcessed": 0
}Structural validation vs. dry-run
This is the key point of the endpoint: not all failures reach errors[]. A request
goes through stages and each one fails differently.
| Stage | How it fails | Where it shows |
|---|---|---|
| 1. DTO validation (structure, types, enums) | HTTP 400 error | message (array of strings); stops the request. |
| 2. Business validation (catalog, aggregation, time) | HTTP 400 error | message (string); stops the request. |
| 3. BigQuery dry-run | valid: false (status 201) | errors field of the response body. |
Do not assume that an "invalid definition" always arrives as valid: false. Most shape
and business errors are HTTP 400 errors and never reach the dry-run.
valid: false specifically means that BigQuery rejected a query that had already
passed all local validation.
Validation Rules
Before the dry-run, the definition goes through the two layers of validation. The full catalog of rules and their exact messages is in Definition → Validation Rules.
Error Responses
These are the HTTP errors (distinct from valid: false, which travels with status 201):
| Status | Description |
|---|---|
400 | Invalid DTO (missing field, wrong type, enum out of range, unknown property) or a broken business rule. |
401 | Missing or invalid Authorization: Bearer. |
403 | The user lacks the event-criteria:view-sql permission, or the x-tenant-id is not authorized. |
404 | The tenant has no dataset configured (Dataset not configured for tenant <id>). |