Validar
Valida uma definição de audience criteria e executa um dry-run contra o BigQuery, a partir do corpo (ainda não persistida) ou por id de um critério salvo; retorna se é válida e o custo estimado, sem dados nem SQL.
Validar
Valida uma definição de audience criteria e, se passar em todas as validações, executa um dry-run contra o BigQuery. Um mesmo motor atende duas entradas:
POST /api/audience-criterias/validate-from-body— valida uma definição enviada no corpo (ainda não persistida).POST /api/audience-criterias/:id/validate— valida um critério já salvo, referenciado por seuid.
Ambos retornam a mesma forma de resposta:
IValidateAudienceCriteriaResult, com a
validade e o custo estimado do query. A validação não retorna linhas nem o SQL
gerado: apenas se a definição é executável e quantos bytes ela processaria.
Dentro de um projeto, toda audiência que não seja a audiência raiz é validada intersectada com a audiência raiz do projeto — veja Interseção com a audiência raiz.
Auth: Obrigatória — permissão audience-criteria:view-sql (ambos endpoints).
Distinga dois caminhos de falha que este recurso trata de forma diferente:
- A validação estrutural e de negócio (DTO, catálogo, regras de agregação,
janela temporal, etc.) ocorre antes do dry-run e, se falhar, responde com um
erro HTTP (
400/404) — não chega ao corpo da resposta. - O dry-run do BigQuery é a única coisa refletida no corpo como
valid: false(com status201).
POST /api/audience-criterias/validate-from-body
Valida uma definição enviada no corpo, sem persisti-la.
Auth: Obrigatória — permissão audience-criteria:view-sql
O endpoint responde 201 Created —não 200—, mesmo sem criar nenhum
recurso.
Corpo da requisição
Nível raiz (CriteriaDefinitionDto): a definição do critério, sem wrapper.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
queryBlocks | QueryBlockDto[] | Sim | Pelo menos 1 elemento. Cada bloco ≈ um statement SQL completo. |
composedWith | CreateCompositionDto[] | Não | Compõe esta definição com outras audiências via operações de conjunto. |
criteriaId | string (UUID) | null | Não | A audiência salva que esta definição edita: o rascunho assume a identidade dessa audiência, então gera o mesmo resultado que essa audiência gerará ao ser salva (veja Interseção com a audiência raiz). Ausente ou null: uma audiência nova. Deve ser um UUID válido (caso contrário, 400) de uma audiência do projeto ativo (caso contrário, 404). |
Diferentemente de Criar, a
definição não leva name nem description: é apenas a árvore de consulta.
Também não existe aqui o campo format de
Gerar SQL —validar não emite
SQL—. A validação do DTO é estrita, então enviar name/description/format
(ou qualquer outra propriedade desconhecida) produz um 400.
Definição do critério
É a mesma árvore que Criar recebe,
sem os campos name/description. Está documentada aqui de forma autocontida.
queryBlocks[] — bloco de consulta
Cada elemento de queryBlocks (QueryBlockDto) é um statement SQL completo:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
order | number (inteiro) | Sim | Posição do bloco; inteiro ≥ 0. |
setOperator | SetOperatorEnum | Não | Combina este bloco com o anterior. Ausente no primeiro bloco; obrigatório nos demais (ver regras). |
from | FromDto | Sim | Fonte de dados: tabela principal + joins. |
select | SelectDto | Sim | Projeção (colunas e/ou agregações). |
timeWindow | TimeWindowDto | Não | Janela temporal do bloco (união discriminada por timeOperator). |
where | WhereDto | Sim | Árvore de predicados. Obrigatório mesmo que seja um grupo vazio. |
groupBy | ColumnRefDto[] | Não | Colunas de agrupamento. |
having | HavingDto | Não | Filtro sobre agregados. |
O setOperator de um query block combina blocos dentro da mesma definição; não
deve ser confundido com o setOperator de uma composição,
que combina critérios inteiros. São dois níveis distintos de operação de conjunto.
ColumnRefDto — referência a coluna
Usado em toda a árvore (select, filtros, group by, joins, agregados, janela temporal):
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
table | string | Sim | Tabela do catálogo. Não vazio. |
column | string | Sim | Coluna. Não vazio. Pode ser um path de STRUCT (ex.: "pricing.final_amount"). |
Toda coluna é sempre qualificada com sua table para evitar ambiguidade.
from — fonte de dados (FromDto)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
table | string | Sim | Tabela principal do catálogo. Não vazio. |
joins | JoinDto[] | Não | Joins com outras tabelas. Padrão []. |
unnests | ColumnRefDto[] | Não | Colunas repetidas declaradas como fonte de linhas (uma linha por elemento). Uma audiência não as aceita: omita o campo ou envie [] (o padrão); uma lista não vazia retorna 400. |
Cada JoinDto:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
type | JoinTypeEnum | Sim | INNER | LEFT | RIGHT | FULL. |
table | string | Sim | Tabela a unir (do catálogo). Não vazio. |
on | JoinPredicateDto[] | Sim | Condições de junção. |
Cada JoinPredicateDto é um par de colunas: { left: ColumnRefDto, right: ColumnRefDto }.
select — projeção (SelectDto)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
distinct | boolean | Sim | Aplica SELECT DISTINCT. |
items | (SelectColumnItem | SelectAggregateItem)[] | Sim | Não vazio. União discriminada pelo campo kind. |
Os items são discriminados por kind:
-
Coluna —
kind: "column":Campo Tipo Obrigatório Descrição kind"column"Sim Discriminador. columnColumnRefDtoSim Coluna projetada. aliasstring Não Deve casar com ^[A-Za-z_][A-Za-z0-9_]*$. -
Agregado —
kind: "aggregate":Campo Tipo Obrigatório Descrição kind"aggregate"Sim Discriminador. aggregateAggregateDtoSim Expressão de agregação. aliasstring Sim Aqui o alias é obrigatório. Mesmo regex de identificador.
AggregateDto:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
aggregationOperator | AggregationOperatorEnum | Sim | COUNT | SUM | AVG | MIN | MAX. |
operand | object | Sim | O que é agregado. União discriminada por kind: column, star ou arithmetic (veja abaixo). |
distinct | boolean | Não | Aplica DISTINCT dentro do agregado. |
operand —o que é agregado— é discriminado por kind:
kind | Campos adicionais | Significado |
|---|---|---|
column | column: ColumnRefDto | Uma coluna do catálogo. |
star | (nenhum) | *: conta linhas. Só é válido com COUNT e sem distinct (COUNT(DISTINCT *) não é permitido). |
arithmetic | arithmeticOperator: ArithmeticOperatorEnum, left, right | Expressão binária. Cada lado é outro operando: uma column ou um arithmetic aninhado (nunca star). |
ArithmeticOperatorEnum: ADD | SUBTRACT | MULTIPLY | SAFE_DIVIDE (uma divisão que retorna
NULL quando o denominador é zero, em vez de fazer a consulta falhar). As colunas de uma expressão
aritmética precisam ser numéricas (INT64, NUMERIC, BIGNUMERIC, FLOAT64), e as expressões se
aninham até 3 níveis de arithmetic, contando o externo.
where — árvore de predicados (WhereDto)
O where é uma árvore recursiva. O nó raiz é sempre um grupo, e suas folhas são de
dois tipos:
kind | O que filtra |
|---|---|
group | Não é uma folha: agrupa filhos com AND / OR. Os grupos podem ser aninhados. |
predicate | Uma coluna escalar de uma tabela do from. |
recordPredicate | Uma coluna RECORD REPEATED: pelo menos 1 elemento satisfaz o sub-filtro. |
Grupo — kind: "group"
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
kind | "group" | Sim | Discriminador. |
logicalOperator | LogicalOperatorEnum (AND | OR) | Sim | Conectivo entre os filhos. |
children | (Group | Leaf)[] | Sim | Filhos do grupo; podem ser grupos aninhados. |
logicalOperator é sempre obrigatório em um grupo, mas só tem efeito com 2 ou
mais filhos. Com menos de 2 filhos seu valor é indiferente (gera o mesmo SQL), mas
ainda assim deve ser enviado. Um where sem filtros é expresso como um grupo vazio:
{ "kind": "group", "logicalOperator": "AND", "children": [] }.
Folha de coluna — kind: "predicate"
Compara uma coluna escalar qualificada por sua tabela.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
kind | "predicate" | Sim | Discriminador. |
column | ColumnRefDto | Sim | Coluna do predicado. |
comparisonOperator | ComparisonOperatorEnum | Sim | Operador de comparação. |
value | PredicateValue | Depende | Seu formato depende do operador. |
{
"kind": "predicate",
"column": { "table": "user_properties", "column": "country" },
"comparisonOperator": "IN",
"value": ["CL", "MX"]
}Folha de registro — kind: "recordPredicate"
Filtra por uma coluna RECORD REPEATED (um array de structs, como attributes).
Significa que pelo menos um elemento do array satisfaz o sub-filtro.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
kind | "recordPredicate" | Sim | Discriminador. |
column | ColumnRefDto | Sim | Coluna RECORD REPEATED de uma tabela do from. |
subWhere | Sub-árvore relativa | Sim | Condições sobre os sub-campos do elemento. Não pode ficar vazio. |
{
"kind": "recordPredicate",
"column": { "table": "event_transactions", "column": "attributes" },
"subWhere": {
"kind": "group",
"logicalOperator": "AND",
"children": [
{ "kind": "predicate", "field": "key", "comparisonOperator": "EQUALS", "value": "canal" },
{ "kind": "predicate", "field": "value", "comparisonOperator": "EQUALS", "value": "web" }
]
}
}As condições do subWhere são avaliadas sobre um mesmo elemento do array, e não
sobre o array inteiro. O exemplo acima seleciona linhas que têm um atributo cujo key
é canal e cujo value é web — não linhas que têm um atributo com esse key e
outro, diferente, com esse value.
Quais colunas aceitam um filtro de registro é informado pelo
catálogo: as que vêm com
kind: "record".
Sub-árvore relativa
O subWhere é um grupo AND/OR cujas folhas são resolvidas contra os sub-campos que o
registro declara.
Há uma única diferença em relação à árvore de nível superior, e ela é a origem mais comum de erros:
Dentro de uma sub-árvore relativa os operandos não levam tabela: você escreve
"field": "key", e não "column": { "table": "attributes", "column": "key" }. A folha
usa a chave field (uma string), não column.
Folhas permitidas dentro de uma sub-árvore relativa:
- Folha escalar —
{ "kind": "predicate", "field": string, "comparisonOperator": …, "value"?: … }. Ofielddeve ser um sub-campo escalar do registro. - Registro aninhado —
{ "kind": "recordPredicate", "field": string, "subWhere": … }. Um registro dentro de outro registro; aninha sem limite declarado, desde que o catálogo declare cada nível. - Grupo — o mesmo formato de grupo, para combinar as folhas anteriores com
AND/OR.
Forma de value por comparisonOperator
| Operadores | Forma de value | Exemplo |
|---|---|---|
IS_NULL, IS_NOT_NULL | Sem value (omitido) | (omitido) |
IN, NOT_IN | Lista não vazia ScalarValue[] | ["CL", "MX"] |
BETWEEN | Par [min, max] | [10, 20] |
O resto (EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH) | Escalar único | "active" · 42 |
ScalarValue = string | number | boolean. Além disso, cada operador deve ser
compatível com o tipo da coluna (ver regras de validação).
groupBy — colunas de agrupamento
Lista opcional de ColumnRefDto[]. Quando o bloco agrega (declara groupBy ou tem um
agregado no select), o groupBy deve coincidir exatamente com as colunas não
agregadas do select (ver regras de validação).
having — filtro sobre agregados (HavingDto)
Mesma estrutura recursiva que where (grupos AND/OR aninhados e mesma regra de value
por operador), mas a folha opera sobre um agregado, não sobre uma coluna:
- Predicado (folha) —
{ kind: "predicate", aggregate: AggregateDto, comparisonOperator: ComparisonOperatorEnum, value?: PredicateValue }. - Grupo — idêntico ao de
where.
timeWindow — janela temporal (TimeWindowDto)
União discriminada por timeOperator. Restringe o bloco a um período de tempo sobre
uma coluna TIMESTAMP do catálogo (reference). É um campo irmão de where, não
um nó da árvore de filtros.
timeOperator | Campos adicionais |
|---|---|
ALL_TIME | (nenhum) — sem restrição de tempo. |
IN_THE_LAST | reference: ColumnRefDto, unit: TimeUnitEnum, value: inteiro > 0 |
IN_THE_FIRST | reference: ColumnRefDto, unit: TimeUnitEnum, value: inteiro > 0 |
SINCE | reference: ColumnRefDto, from: string (YYYY-MM-DD) |
BETWEEN | reference: ColumnRefDto, from: string (YYYY-MM-DD), to: string (YYYY-MM-DD) |
TimeUnitEnum: DAYS | WEEKS | MONTHS | YEARS.
Semântica de negócio de cada operador:
ALL_TIME— sem janela; considera todo o histórico.IN_THE_LAST— janela móvel relativa a "agora": os últimosvalueunit(ex.: últimos30 DAYS). Recalculada a cada execução.IN_THE_FIRST— janela relativa à origem do ciclo de vida do usuário (sua data de cadastro): os primeirosvalueunitde vida de cada usuário. Ancorada por usuário, não a uma data fixa.SINCE— a partir da data civilfrom(inclusive).BETWEEN— entrefrometo, ambas datas civis inclusivas do dia completo.
As datas civis YYYY-MM-DD (SINCE, BETWEEN) se resolvem para o início do dia
no fuso horário do tenant. O detalhe do fuso horário é interno; basta enviar a
data civil.
composedWith[] — composição com outras audiências
Cada elemento (CreateCompositionDto) combina esta definição com outra
audiência via uma operação de conjunto:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
operandCriteriaId | string (UUID) | Sim | Id da outra audiência (operando). Deve existir. |
setOperator | SetOperatorEnum | Sim | UNION_DISTINCT | UNION_ALL | INTERSECT_DISTINCT. |
Exemplo
Definição de uma audiência de usuários com 3 ou mais transações COMPLETED nos
últimos 90 dias.
curl -X POST https://api.reten.ai/api/audience-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" },
"select": {
"distinct": false,
"items": [
{
"kind": "column",
"column": { "table": "event_transactions", "column": "user_id" }
}
]
},
"timeWindow": {
"timeOperator": "IN_THE_LAST",
"reference": { "table": "event_transactions", "column": "event_date" },
"unit": "DAYS",
"value": 90
},
"where": {
"kind": "group",
"logicalOperator": "AND",
"children": [
{
"kind": "predicate",
"column": { "table": "event_transactions", "column": "status" },
"comparisonOperator": "EQUALS",
"value": "COMPLETED"
}
]
},
"groupBy": [{ "table": "event_transactions", "column": "user_id" }],
"having": {
"kind": "group",
"logicalOperator": "AND",
"children": [
{
"kind": "predicate",
"aggregate": {
"aggregationOperator": "COUNT",
"operand": { "kind": "star" }
},
"comparisonOperator": "GREATER_THAN_OR_EQUAL",
"value": 3
}
]
}
}
]
}'import axios from 'axios';
const body = {
queryBlocks: [
{
order: 0,
from: { table: 'event_transactions' },
select: {
distinct: false,
items: [
{
kind: 'column',
column: { table: 'event_transactions', column: 'user_id' },
},
],
},
timeWindow: {
timeOperator: 'IN_THE_LAST',
reference: { table: 'event_transactions', column: 'event_date' },
unit: 'DAYS',
value: 90,
},
where: {
kind: 'group',
logicalOperator: 'AND',
children: [
{
kind: 'predicate',
column: { table: 'event_transactions', column: 'status' },
comparisonOperator: 'EQUALS',
value: 'COMPLETED',
},
],
},
groupBy: [{ table: 'event_transactions', column: 'user_id' }],
having: {
kind: 'group',
logicalOperator: 'AND',
children: [
{
kind: 'predicate',
aggregate: {
aggregationOperator: 'COUNT',
operand: { kind: 'star' },
},
comparisonOperator: 'GREATER_THAN_OR_EQUAL',
value: 3,
},
],
},
},
],
};
const response = await axios.post(
'https://api.reten.ai/api/audience-criterias/validate-from-body',
body,
{ headers: { Authorization: 'Bearer <token>', 'x-tenant-id': '<tenant-id>', 'x-project-id': '<project-id>' } },
);
const result = response.data; // IValidateAudienceCriteriaResultA resposta é documentada em
IValidateAudienceCriteriaResult, com um
exemplo válido e um inválido.
POST /api/audience-criterias/:id/validate
Valida um critério já salvo, referenciado por seu id. A definição não viaja no
corpo: é obtida do critério persistido no projeto ativo.
Auth: Obrigatória — permissão audience-criteria:view-sql
Assim como validate-from-body, o endpoint responde 201 Created —não 200—,
mesmo sem criar nenhum recurso.
Parâmetros de rota
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | UUID | Sim | Id do audience criteria. Deve ser um UUID válido (caso contrário, 400). |
Este endpoint não recebe corpo nem parâmetros de consulta.
Exemplo
curl -X POST https://api.reten.ai/api/audience-criterias/f47ac10b-58cc-4372-a567-0e02b2c3d479/validate \
-H "Authorization: Bearer <token>" \
-H "x-tenant-id: <tenant-id>" \
-H "x-project-id: <project-id>"import axios from 'axios';
const id = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
const response = await axios.post(
`https://api.reten.ai/api/audience-criterias/${id}/validate`,
undefined, // sem corpo
{ headers: { Authorization: 'Bearer <token>', 'x-tenant-id': '<tenant-id>', 'x-project-id': '<project-id>' } },
);
const result = response.data; // IValidateAudienceCriteriaResultResposta — IValidateAudienceCriteriaResult
Status 201 Created em ambos os endpoints. O corpo relata o resultado do
dry-run do BigQuery:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
valid | boolean | Sim | true se o dry-run teve sucesso; false se o BigQuery rejeitou o query. |
errors | string[] | Não | Presente somente quando valid: false. Contém a(s) mensagem(ns) de erro do BigQuery. |
bytesProcessed | number | Sim | Bytes que o BigQuery estima processar. Em caso de sucesso, a estimativa do dry-run; em caso de falha, 0. |
O dry-run não executa o query nem retorna linhas: apenas o valida contra o
BigQuery e estima seu custo (bytesProcessed). Para obter uma amostra de linhas
reais use Pré-visualizar; para ver
o SQL gerado, Gerar SQL.
errors é um array por contrato, mas na prática o dry-run retorna uma única
mensagem (a que o BigQuery reporta). Sempre discrimine por valid antes de
ler errors.
Exemplo — válida (valid: true)
Uma resposta 201 para uma definição que compila e passa no dry-run:
{
"valid": true,
"bytesProcessed": 10485760
}Quando valid é true, errors é omitido e bytesProcessed traz a estimativa do
BigQuery (neste exemplo, ~10 MB).
Exemplo — inválida (valid: false)
A definição passou na validação estrutural e de negócio e compilou para SQL, mas o
dry-run do BigQuery a rejeitou (ex.: uma coluna do catálogo que ainda não existe na
tabela real do dataset, ou um query cujo custo estimado excede o limite de bytes
faturáveis). Ainda assim o status é 201:
{
"valid": false,
"errors": [
"Unrecognized name: legacy_column at [3:8]"
],
"bytesProcessed": 0
}Com valid: false, errors traz a mensagem do BigQuery e bytesProcessed é 0.
Interseção com a audiência raiz
Todo projeto tem uma audiência raiz, e toda outra
audiência do projeto é avaliada dentro dela. O dry-run roda sobre o mesmo SQL que
Gerar SQL
retorna: para qualquer audiência que não seja a audiência raiz, intersectado com a audiência raiz
do projeto. Por isso valid e bytesProcessed se referem a essa consulta intersectada, e a
estimativa inclui a parte da audiência raiz.
Não há interseção quando a audiência validada é a própria audiência raiz — :id/validate com
o id da audiência raiz, ou um rascunho de validate-from-body cujo criteriaId é a audiência
raiz.
A interseção é posicional (SELECT * nos dois lados): a audiência deve projetar as mesmas
colunas que a audiência raiz, na mesma ordem e com tipos compatíveis — com a definição padrão da
audiência raiz, apenas user_id. Caso contrário, o BigQuery rejeita a consulta intersectada no
dry-run e a resposta é valid: false, com a mensagem do BigQuery em errors.
Validação estrutural vs. dry-run
Este é o ponto-chave do recurso: nem todas as falhas chegam a errors[]. Uma
requisição passa por etapas e cada uma falha de forma diferente.
| Etapa | Como falha | Onde aparece |
|---|---|---|
| 1. Validação do DTO (estrutura, tipos, enums) | Erro HTTP 400 | message (array de strings); interrompe a requisição. |
2. Resolução do critério (somente :id, criteriaId e composedWith) | Erro HTTP 404 | message (string); interrompe a requisição. |
| 3. Validação de negócio (catálogo, agregação, tempo) | Erro HTTP 400 | message (string); interrompe a requisição. |
| 4. Dry-run do BigQuery | valid: false (status 201) | Campo errors do corpo de resposta. |
Em outras palavras:
- Tudo o que acontece antes do dry-run (etapas 1–3) que falha responde com um
erro HTTP e não produz um corpo
IValidateAudienceCriteriaResult. Por exemplo: uma tabela fora do catálogo, um critério que não projeta sua coluna de identidade, umtimeWindowmalformado, umidou umcriteriaIdinexistente, ou umoperandCriteriaIdque não existe. valid: falseé exclusivo do dry-run: a definição já era estruturalmente válida e compilou para SQL, mas o BigQuery a rejeitou ao estimá-la. O status continua sendo201.
Não assuma que um "critério inválido" sempre chega como valid: false. A maioria
dos erros de forma e de negócio são erros HTTP 400/404 e nunca alcançam o
dry-run. valid: false significa especificamente que o BigQuery rejeitou um
query que já havia passado por toda a validação local.
Regras de validação
Antes do dry-run, a definição passa pelas mesmas duas camadas de validação que
Criar, e ambas
retornam 400 Bad Request:
- Validação do DTO (estrutura, tipos, enums, campos obrigatórios).
messageé um array de strings e propriedades desconhecidas são rejeitadas (incluindoname/description/format). - Validação de negócio (a definição deve gerar SQL válido e coerente com o
catálogo).
messageé um string único com a regra violada, e para no primeiro invariante violado.
A validação de negócio roda em ambos os endpoints: validate-from-body valida a
definição do corpo, e :id/validate valida o critério salvo antes de compilá-lo.
O catálogo completo de regras e suas mensagens exatas está em
Criar.
Respostas de erro
Estes são os erros HTTP (diferentes de valid: false, que viaja com status 201):
| Status | Descrição |
|---|---|
400 | DTO inválido (campo faltando, tipo incorreto, enum fora do intervalo, propriedade desconhecida como name/description/format) ou uma regra de negócio violada. Em :id/validate, também se o id não for um UUID válido; em validate-from-body, se o criteriaId não for. |
401 | Falta ou é inválido o Authorization: Bearer. |
403 | O usuário não tem a permissão audience-criteria:view-sql, ou o x-tenant-id não está autorizado. |
404 | Em :id/validate, não existe um audience criteria com esse id no projeto ativo. Em validate-from-body, um operandCriteriaId de composedWith ou o criteriaId não existe no projeto ativo. |
Gerar SQL
Compila uma definição de audience criteria para SQL do BigQuery, a partir do corpo da requisição (ainda não persistida) ou por id de um critério salvo, em formato parametrizado ou literal.
Pré-visualizar
Executa um audience criteria contra o BigQuery e retorna uma amostra de linhas reais mais o total, a partir do corpo (ainda não persistido) ou por id de um critério salvo.