# Sintaxe para expressões A expressão de uma [condição](/pt/rules/conditions/) segue uma sintaxe enxuta, inspirada em fórmulas de planilhas. Ela resulta sempre em verdadeiro ou falso, e é composta por, no mínimo, uma **variável**, uma **operação** e um **valor**. ``` $merchant_id == "XYZ" ``` A expressão acima é verdadeira quando o campo `merchant_id` do evento é igual a `"XYZ"`. ## Os três prefixos Toda variável começa com um prefixo que indica **de onde o valor vem** e **quanto tempo ele dura**: | Prefixo | Contém | Duração | | :------------- | :---------------------------------------------- | :------------------------------------------ | | `$campo` | um campo do evento | persistido com o evento | | `@lista` | uma lista de valores da conta | mantida pela conta, entre eventos | | `%temporaria` | um valor calculado durante esta execução | só existe durante a execução da regra | ## Campos do evento (`$`) As variáveis disponíveis são exatamente os **campos do tipo de evento** ao qual a regra pertence; não existe uma lista fixa. Se o tipo de evento tem um campo `amount`, a regra pode usar `$amount`; um tipo de evento diferente terá outro conjunto de variáveis. O painel oferece os campos disponíveis enquanto você escreve a condição e destaca a expressão conforme ela é escrita. Campos iniciados por `_` são reservados da plataforma e não ficam disponíveis para uso em expressões. Além dos campos do tipo de evento, `$id` contém o identificador do evento informado em `POST /events`, e pode ser usado tanto nas condições quanto como dimensão de uma [análise](/pt/rules/analyses/). O tipo do campo determina como o valor é comparado: | Tipo do campo | Exemplo de comparação | | :-------------- | :------------------------------------- | | Texto | `$status == "approved"` | | Inteiro | `$installments > 6` | | Decimal | `$amount >= 1500.00` | | Booleano | `$is_first_purchase == true` | | Data e hora | `$signup_at > "30 days ago"` | Um campo que não veio no evento é tratado como vazio. Para testar essa ausência, compare com `null`, sem aspas: ``` $device_fingerprint_id == null ``` A expressão acima é verdadeira quando o evento não trouxe fingerprint do dispositivo. Use `!=` para o caso contrário. ## Operações | Operação | Significado | | :------- | :------------------------- | | `==` | Igualdade | | `!=` | Desigualdade | | `>` | Maior que | | `>=` | Maior ou igual | | `<` | Menor que | | `<=` | Menor ou igual | | `in` | Pertence a uma coleção | | `not in` | Não pertence a uma coleção | | `any in` | Pelo menos um dos valores pertence a uma coleção | | `all in` | Todos os valores pertencem a uma coleção | ## Valores O valor comparado com uma variável pode ser um texto, um número ou um booleano: - **Texto**: sempre entre aspas duplas, como `"XYZ"`. Aspas simples e textos sem aspas não são aceitos. - **Número**: sem aspas, com ponto como separador decimal, como `1000` ou `99.01`. - **Booleano**: `true` ou `false`, sem aspas. Como todo texto fica entre aspas duplas, valores como um IP, uma data ou uma palavra usada na própria sintaxe (por exemplo, `in`) também precisam das aspas para serem tratados como texto. ### Datas Campos de data e hora aceitam valores relativos e absolutos, sempre entre aspas: ``` $signup_at > "30 days ago" $signup_at == "2026-03-15" ``` O formato relativo é `[número] [hour|day|week|month|year]s ago`. O formato absoluto aceita ano (`"2026"`), ano e mês (`"2026-03"`) ou data completa (`"2026-03-15"`); nos dois primeiros casos, a comparação cobre todo o período. ## Combinando expressões Use `and` e `or` para combinar expressões. O `and` tem precedência sobre o `or`: em uma combinação sem parênteses, as partes ligadas por `and` são avaliadas primeiro. Assim, `A and B or C` equivale a `(A and B) or C`. Use parênteses para agrupar expressões e alterar essa precedência: ``` ($amount > 1000 and $user_email_domain == "gmail.com") or $issuer_country != "BR" ``` Uma quebra de linha funciona como um espaço entre os termos. Uma combinação longa pode ser distribuída em várias linhas para facilitar a leitura, sem alterar o resultado: ``` ($amount > 1000 and $user_email_domain == "gmail.com") or $issuer_country != "BR" ``` ## `true` e `false` como condição inteira Uma expressão pode consistir apenas em `true` ou `false`, sem variável nem comparação. `true` é sempre verdadeira e mantém a condição sempre ativa; `false` é sempre falsa e desativa a condição sem removê-la. Difere da comparação de um campo booleano com `true` ou `false`, descrita em [Valores](#valores): naquele caso o literal está à direita de uma comparação; como condição inteira, ele constitui a expressão por completo. ## Coleções (`@`) As [listas](/pt/rules/lists/) da conta ficam disponíveis como coleções, identificadas pelo prefixo `@`. Por exemplo, para verificar se um cliente está em uma lista de quarentena: ``` $user_id in @clientes_quarentena ``` Também é possível escrever a coleção diretamente na expressão, entre colchetes e com os valores separados por vírgula: ``` $issuer_country not in ["BR", "AR", "CL"] ``` Além do formato acima, `in` e `not in` aceitam: - **um texto fixo à esquerda**, para testar um valor conhecido contra uma coleção: `"BR" in @paises_atendidos`; - **um campo dos dois lados**, para testar se o valor de um campo está contido no de outro: `$user_id in $allowed_users`. ### Testando vários valores de uma vez Quando o lado esquerdo é uma coleção escrita entre colchetes, é preciso dizer **quantos** dos valores precisam pertencer à coleção da direita: | Operação | Verdadeira quando | | :------- | :--------------------------------------- | | `any in` | pelo menos um dos valores pertence | | `all in` | todos os valores pertencem | | `not in` | nenhum dos valores pertence | ``` ["susp_59", "susp_83"] any in %regua.triggered_cells ["BR", "AR"] all in @paises_atendidos ["tor", "vpn"] not in @tipos_permitidos ``` **Não existe forma sem quantificador**: escrever `["a", "b"] in @lista` é um erro de escrita. "A e B estão na lista" é ambíguo entre "pelo menos um" e "os dois", e uma condição de risco não pode depender de qual das duas leituras o autor tinha em mente. Na negação a ambiguidade não existe, já que "A e B não estão na lista" só pode significar que nenhum dos dois está, e por isso `not in` dispensa quantificador. Pelo mesmo motivo, `not any in` e `not all in` não são aceitos. A coleção da direita pode ser uma lista da conta, uma variável temporária de conjunto, um campo ou outra coleção literal. ## Variáveis temporárias (`%`) Uma variável temporária guarda um valor **calculado durante a execução da regra**: uma [ação](/pt/rules/actions/) a produz e as condições seguintes podem lê-la. Ela não é gravada no evento, não aparece na resposta da API e não é reaproveitada no próximo evento: um valor que precise sobreviver ao evento deve ser gravado em um campo. As variáveis temporárias existem em duas formas. **Valores simples**, definidos por uma ação de definir variável temporária: ``` %revisao_manual == "1" ``` **Resultados de uma [análise](/pt/rules/analyses/)**, publicados por uma ação de executar análise sob o nome do resultado, com atributos acessados por ponto: | Atributo | Contém | Tipo | | :----------------- | :---------------------------------------------------- | :------- | | `score` | score calculado pela análise | Decimal | | `score_cell` | nome da célula que originou o score | Texto | | `triggered` | se a análise foi acionada | Booleano | | `triggered_count` | quantas células foram acionadas | Inteiro | | `triggered_cells` | nomes das células acionadas | Conjunto | ``` %bot.triggered_count >= 2 ``` O atributo `triggered_cells` é um **conjunto**, não um valor único: ele só pode ser usado à direita de uma operação de pertencimento, para testar quais células foram acionadas. ``` "email_velocity" in %bot.triggered_cells ["susp_59", "susp_83"] any in %bot.triggered_cells ``` Compará-lo com `==`, ou usá-lo em qualquer outra operação, é um erro de escrita e a condição não é aceita. Um conjunto também pode ser guardado em uma variável temporária simples, por uma [ação em modo expressão](/pt/rules/actions/#valor-fixo-ou-expressão), e continua sendo um conjunto, testável do mesmo jeito. ## Funções ### `concat` A função `concat` junta vários valores em um único texto, que pode ser comparado com um valor. Cada argumento é um campo do evento (`$campo`), uma [variável temporária](#variáveis-temporárias-) (`%temporaria`) ou um texto fixo, separados por vírgula: ``` concat($user_id, "-", $merchant_id) == "cliente-1234-loja-1234" concat($merchant_id, "-", %bot.score_cell) == "loja-1234-email_velocity" ``` A primeira expressão é verdadeira quando a combinação do ID do usuário e do ID do estabelecimento, unidos por um hífen, resulta em `"cliente-1234-loja-1234"`. Considerações sobre os valores juntados: - Variáveis sem valor são tratadas como texto vazio. - Valores numéricos são convertidos para texto na forma original (por exemplo, `99.01` e `0.9`). - Um conjunto, como `%bot.triggered_cells`, não pode entrar em um `concat`: ele só pode ser testado com uma operação de pertencimento. O resultado de `concat` também aceita `in` e `not in`, o que permite comparar a combinação contra uma lista: ``` concat($user_id, "-", $merchant_id) in @pares_bloqueados ``` ## Erros de escrita A expressão é validada no momento em que a condição é salva. A regra não é publicada enquanto houver erro, e o painel aponta o problema. Os casos mais comuns: - **campo inexistente**: a variável não corresponde a nenhum campo do tipo de evento vinculado à regra; - **tipo incompatível**: o valor comparado não faz sentido para o tipo do campo, como comparar um campo numérico com `"aprovado"`; - **variável temporária desconhecida**: o nome ou o atributo não é produzido por nenhuma ação da regra; - **variável temporária lida cedo demais**: nenhuma condição anterior a produz. Como as condições são avaliadas em ordem, o produtor precisa vir antes do leitor; - **texto sem aspas**: valores de texto precisam de aspas duplas. Cada expressão tem um limite de tamanho. Consulte [limites e parâmetros](/pt/limits/#regras-e-listas).