Audience catalog
Tables, columns and repeated records available to build an audience.
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 and RECORD REPEATED columns.
Without the catalog the definition is not buildable: there is no other way to know which is
the identity column of a table, which TIMESTAMP column it suggests as the time reference,
or that attributes is a repeated record and not a comparable column.
Auth: Required — audience-criteria:view permission on both routes
GET /api/audience-criterias/tables
Lists the catalog tables on which an audience 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/audience-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/audience-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 IAudienceTable:
| Field | Type | Description |
|---|---|---|
tableName | string | Table name; it is the value that goes in from.table and in ColumnRefDto.table. |
identityColumn | string | Optional. Identity column of the table (for example user_id). A table that only serves to join may not have one. |
defaultTimeReferenceColumn | string | Optional. TIMESTAMP column suggested as the time window's reference. Another TIMESTAMP column can be chosen. |
requiresInnerJoin | boolean | true if the table can only participate as the main table of the from or as the target of an INNER JOIN. |
[
{
"tableName": "user_properties",
"identityColumn": "user_id",
"defaultTimeReferenceColumn": "sign_up_date",
"requiresInnerJoin": false
},
{
"tableName": "event_transactions",
"identityColumn": "user_id",
"defaultTimeReferenceColumn": "event_date",
"requiresInnerJoin": false
},
{
"tableName": "user_segment_relation",
"identityColumn": "user_id",
"requiresInnerJoin": true
},
{
"tableName": "user_seller_relation",
"identityColumn": "user_id",
"requiresInnerJoin": true
}
]The identityColumn is the column that at least one query block has to project in its
select: a definition that does not expose it is rejected with 400. The detail is in
Identity column.
A table with requiresInnerJoin: true restricts the entire block: if it takes part in
a block, all the joins of that block have to be INNER. The signal is in the catalog so
that the block is built right from the start, instead of discovering it with a 400 when
validating.
GET /api/audience-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
| Parameter | Type | Description |
|---|---|---|
tableName | string | Table name, as returned by GET /tables. |
Example
curl https://api.reten.ai/api/audience-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/audience-criterias/tables/event_transactions/columns',
{ headers: { Authorization: 'Bearer <token>', 'x-tenant-id': '<tenant-id>', 'x-project-id': '<project-id>' } },
);
const columns = response.data;Response 200 OK
An array of IAudienceColumn: a discriminated union by kind with two variants.
Narrow by kind before reading type or fields. Only the scalar variant carries
type; only record carries fields. Reading column.type without discriminating
returns undefined for a repeated record.
-
kind: "scalar"— a column that can be filtered directly:Field Type Description columnNamestring Column 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. isIdentityboolean trueif it is the identity column of the table. At most one column per table has it.isDefaultTimeReferenceboolean trueif it is the table's suggested time reference. It is a suggestion: the window can be anchored on anotherTIMESTAMPcolumn. -
kind: "record"— a RECORD REPEATED column, filterable only with a record filter:Field Type Description columnNamestring Name of the repeated column. kind"record"Discriminator. fieldsIAudienceColumn[]Filterable sub-fields, relative to the record. It may contain other record.isIdentityfalseAlways false: a repeated record cannot be the identity of the table.isDefaultTimeReferencefalseAlways false: a repeated record cannot anchor the time window.
The fields of a record use the same scalar | record union, so the rule of narrowing
by kind applies at every level.
A sub-field of a record never carries isIdentity or isDefaultTimeReference as true,
not even if it has the same name as the identity column of the table. The two roles
belong to the table over its first-level columns.
Example response
GET /api/audience-criterias/tables/event_transactions/columns:
[
{
"columnName": "user_id",
"kind": "scalar",
"type": "STRING",
"isIdentity": true,
"isDefaultTimeReference": false
},
{
"columnName": "event_date",
"kind": "scalar",
"type": "TIMESTAMP",
"isIdentity": false,
"isDefaultTimeReference": true
},
{
"columnName": "event_id",
"kind": "scalar",
"type": "STRING",
"isIdentity": false,
"isDefaultTimeReference": false
},
{
"columnName": "status",
"kind": "scalar",
"type": "STRING",
"isIdentity": false,
"isDefaultTimeReference": false
},
{
"columnName": "coupon_code",
"kind": "scalar",
"type": "STRING",
"isIdentity": false,
"isDefaultTimeReference": false
},
{
"columnName": "pricing.final_amount",
"kind": "scalar",
"type": "FLOAT64",
"isIdentity": false,
"isDefaultTimeReference": false
},
{
"columnName": "attributes",
"kind": "record",
"fields": [
{
"columnName": "key",
"kind": "scalar",
"type": "STRING",
"isIdentity": false,
"isDefaultTimeReference": false
},
{
"columnName": "value",
"kind": "scalar",
"type": "STRING",
"isIdentity": false,
"isDefaultTimeReference": false
}
],
"isIdentity": false,
"isDefaultTimeReference": false
}
]How each variant is used in the definition
| Variant | Where it goes |
|---|---|
scalar | ColumnRefDto.column of a predicate leaf, of the select, of the groupBy, of an aggregate, of a join's on or of the time window's reference. |
record | column of a recordPredicate leaf; its fields go in the field of the subWhere leaves. |
A record column cannot be compared or projected: using it in the select, in the
groupBy, in an aggregate, in a join's on or in a predicate leaf returns 400. Its
only use is the record filter.
Error Responses
| Status | Description |
|---|---|
401 | Missing or invalid Authorization: Bearer. |
403 | The user does not have the audience-criteria:view permission, or the x-tenant-id is not authorized. |
404 | Only on /tables/:tableName/columns: the table is not in the catalog (La tabla no existe o no está en el catálogo de audiencias.), or the tenant has no dataset configured (Dataset not configured for tenant <id>). |
500 | Only 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 audiencias.). |
GET /api/audience-criterias/tables does not query the tenant's dataset, so it only returns
200, 401 or 403.