Um fluxo de uma transportadora mandava aos clientes um e-mail de confirmação de coleta. Funcionou por três semanas. Depois vieram as reclamações: a hora da coleta chegava 3 horas adiantada, o valor aparecia como 1234.5 e, quando o cliente não tinha telefone cadastrado, o e-mail nem saía, porque o fluxo falhava. Os três problemas têm a mesma solução: três expressões de uma linha.
Este post reúne as expressões que eu uso em quase todo fluxo, por grupo, com o erro que cada uma evita. A sintaxe é a da linguagem de expressões do Power Automate, a mesma do Azure Logic Apps, e todas as funções estão na referência oficial citada no fim.
Onde e como escrever uma expressão
Ao clicar em um campo de uma ação, o painel oferece Conteúdo dinâmico e Expressão (o botão fx). Conteúdo dinâmico é um atalho: o "Título" do gatilho do SharePoint vira triggerOutputs()?['body/Title'] por baixo. Quando você precisa transformar o valor (formatar, cortar, converter, comparar), a aba Expressão é o lugar. Três regras: texto fixo vai entre aspas simples; nome de ação com espaço vira sublinhado (Obter item vira outputs('Obter_item')); e aspas simples dentro de um texto são escritas em dobro.
Para ver o que uma expressão devolve, crie uma ação Compor, cole a expressão e rode o fluxo. A saída fica no histórico de execução. É o jeito mais rápido de testar sem mandar e-mail errado para ninguém.
Texto
Limpeza de entrada e montagem de mensagens. trim tira espaços das pontas, toLower padroniza, replace remove caracteres e split transforma texto separado por ponto e vírgula em lista.
Texto: expressão e, na linha de baixo, o resultadotext
toLower(trim(triggerOutputs()?['body/Email']))
ana.souza@empresa.com.br
replace(triggerOutputs()?['body/Telefone'], '-', '')
11987654321
concat('Pedido ', triggerOutputs()?['body/Title'], ' aberto por ', triggerOutputs()?['body/Author/DisplayName'])
Pedido 2026-0412 aberto por Ana Souza
split(triggerOutputs()?['body/Tags'], ';')
["urgente","compras"]
substring(variables('CNPJ'), 0, 8)
12345678
length(triggerOutputs()?['body/Observacoes'])
0Datas e fuso horário
O Power Automate trabalha em UTC: utcNow() devolve UTC, a coluna de data e hora do SharePoint chega em UTC e as aprovações registram em UTC. Brasília é UTC menos 3 horas o ano inteiro desde 2019, quando o horário de verão acabou. O nome do fuso, no padrão do Windows, é "E. South America Standard Time"; Manaus usa "SA Western Standard Time". A lista completa está nas fontes.
Datas: expressão e, na linha de baixo, o resultadotext
utcNow()
2026-11-20T14:05:33.1234567Z
convertFromUtc(utcNow(), 'E. South America Standard Time', 'dd/MM/yyyy HH:mm')
20/11/2026 11:05
convertTimeZone(triggerOutputs()?['body/DataColeta'], 'UTC', 'E. South America Standard Time', 'dd/MM/yyyy HH:mm')
25/11/2026 08:00
formatDateTime(utcNow(), 'dddd, dd MMMM yyyy', 'pt-BR')
sexta-feira, 20 novembro 2026
addDays(utcNow(), 5, 'yyyy-MM-dd')
2026-11-25
parseDateTime('25/11/2026', 'pt-BR', 'dd/MM/yyyy')
2026-11-25T00:00:00.0000000
dayOfWeek(utcNow())
5Grave sempre em UTC e converta só na hora de mostrar. Quando a pessoa digita uma data no app e você precisa comparar com utcNow(), converta a entrada no sentido contrário, com convertToUtc(data, 'E. South America Standard Time'). Coluna só de data (sem hora) chega como "2026-11-25" e dispensa conversão. dayOfWeek devolve 0 para domingo e 6 para sábado, o que serve para pular fim de semana em lembretes.
Nulos e lógica
Campo de pessoa vazio, coluna opcional sem valor, item que não existe: quando a expressão navega até uma propriedade que não está lá, o fluxo falha. O operador ? depois de cada nível devolve nulo em vez de erro, e coalesce troca o nulo por um valor padrão.
Nulos e lógica: expressão e, na linha de baixo, o resultadotext
coalesce(triggerOutputs()?['body/Telefone'], 'não informado')
não informado
if(empty(triggerOutputs()?['body/Observacoes']), 'sem observações', triggerOutputs()?['body/Observacoes'])
sem observações
equals(toLower(trim(triggerOutputs()?['body/Status/Value'])), 'aprovado')
true
and(greater(triggerOutputs()?['body/Valor'], 5000), equals(triggerOutputs()?['body/Centro/Value'], 'Compras'))
true
not(empty(triggerOutputs()?['body/Responsavel']))
falseColeções
Saída de Obter itens, lista de respostas de uma aprovação, anexos de um e-mail: tudo chega como array. first e last pegam as pontas, length conta, join vira texto e items lê o item atual dentro de um Aplicar a cada.
Coleções: expressão e, na linha de baixo, o resultadotext
first(body('Obter_itens')?['value'])?['Title']
Pedido 2026-0412
last(split(triggerOutputs()?['body/{FilenameWithExtension}'], '.'))
pdf
length(body('Obter_itens')?['value'])
17
join(body('Selecionar'), ', ')
Ana Souza, Bruno Lima, Carla Dias
items('Aplicar_a_cada')?['Email']
ana.souza@empresa.com.br
union(variables('ListaA'), variables('ListaB'))
["a","b","c"]O caso mais comum de first é a aprovação. Quando você arrasta "Respostas Nome do aprovador" para uma ação, o editor cria um Aplicar a cada, porque pode haver várias respostas. Com um único aprovador, a expressão first(body('Iniciar_e_aguardar_uma_aprovação')?['responses'])?['responder']?['displayName'] resolve sem laço. O passo a passo completo está em fluxo de aprovação no Power Automate.
JSON: body, outputs e Analisar JSON
outputs('Acao') devolve tudo o que a ação retornou: código de status, cabeçalhos e corpo. body('Acao') é um atalho para outputs('Acao')?['body']. O mesmo vale para triggerOutputs() e triggerBody(). Quando a resposta vem de um HTTP ou de um conector que devolve texto JSON, a ação Analisar JSON transforma o texto em propriedades que aparecem no conteúdo dinâmico.
JSON: expressão e, na linha de baixo, o resultadotext
outputs('Obter_item')
{ "statusCode": 200, "headers": { ... }, "body": { ... } }
body('Obter_item')?['Valor']
1234.5
triggerBody()?['Email']
ana.souza@empresa.com.br
body('Analisar_JSON')?['cliente']?['nome']
Ana Souza
json('{"status":"ok","itens":2}')?['itens']
2
string(outputs('Compor'))
texto com o conteúdo do ComporNo Analisar JSON, gere o esquema a partir de um exemplo real de carga. Depois edite duas coisas: tire de required os campos que podem faltar e troque "type": "string" por "type": ["string", "null"] nos campos que podem vir vazios. Sem isso, a ação falha no primeiro registro incompleto, e o erro aparece como "Invalid type. Expected String but got Null".
O e-mail da transportadora, corrigido
Os três campos do e-mail de confirmação ficaram assim no corpo da ação Enviar um email (V2):
E-mail de confirmação: três expressõestext
convertFromUtc(triggerOutputs()?['body/DataColeta'], 'E. South America Standard Time', 'dd/MM/yyyy HH:mm')
25/11/2026 08:00
formatNumber(triggerOutputs()?['body/Valor'], 'C2', 'pt-BR')
R$ 1.234,50
coalesce(triggerOutputs()?['body/Telefone'], 'não informado')
não informadoformatNumber exige número. Se o valor vier como texto, envolva com float(). O formato "C2" é moeda com duas casas; "N2" é número com separador de milhar e sem símbolo; "P1" é porcentagem com uma casa. O terceiro parâmetro, "pt-BR", é o que coloca a vírgula no lugar certo.
Erro comum e expressão certa
| Sintoma | O que estava escrito | Expressão certa |
|---|---|---|
| Hora 3 horas adiantada no e-mail | formatDateTime(data, 'dd/MM/yyyy HH:mm') | convertFromUtc(data, 'E. South America Standard Time', 'dd/MM/yyyy HH:mm') |
| Data digitada "25/11/2026" recusada pela ação | formatDateTime('25/11/2026', 'yyyy-MM-dd') | parseDateTime('25/11/2026', 'pt-BR', 'dd/MM/yyyy') |
| Fluxo falha quando o campo de pessoa está vazio | triggerOutputs()['body']['Responsavel']['Email'] | coalesce(triggerOutputs()?['body/Responsavel/Email'], 'sem responsável') |
| Comparação de valor dá erro ou resultado errado | greater(variables('ValorTexto'), 5000) | greater(float(variables('ValorTexto')), 5000) |
| "Aprovado" e "aprovado " tratados como diferentes | equals(status, 'Aprovado') | equals(toLower(trim(status)), 'aprovado') |
| Valor sai como 1234.5 | string(valor) | formatNumber(valor, 'C2', 'pt-BR') |
| Aplicar a cada criado sem querer ao pegar o nome do aprovador | Conteúdo dinâmico "Respostas Nome do aprovador" | first(body('Iniciar_e_aguardar_uma_aprovação')?['responses'])?['responder']?['displayName'] |
Antes de salvar um fluxo com expressões
- Toda navegação em propriedade usa o operador ?, como body('X')?['campo']
- Campos que podem vir vazios passam por coalesce ou if(empty())
- Datas convertidas para 'E. South America Standard Time' só na exibição; gravação em UTC
- Números vindos como texto passam por int() ou float() antes de comparar ou somar
- Valores em reais formatados com formatNumber(valor, 'C2', 'pt-BR')
- Comparações de texto com toLower(trim())
- Esquema do Analisar JSON aceita null nos campos opcionais
- Expressões longas testadas em um Compor antes de ir para o e-mail ou para a gravação
- Ações com nome claro desde o início, porque o nome entra em outputs('Nome_da_acao')
O próximo passo prático é abrir o fluxo que mais falha na sua empresa, procurar no histórico o primeiro erro de nulo ou de data e trocar a navegação direta por ? e coalesce. Depois passe pelas datas. Os outros motivos pelos quais fluxos param em produção, de conexão a limite de requisições, estão em 7 erros que derrubam fluxos do Power Automate. Para praticar expressões com fluxos reais, do primeiro Compor ao Analisar JSON, a Formação Power Automate tem um módulo dedicado a tratamento de dados.
Fontes
- Microsoft Learn: referência de funções da linguagem de expressões (Logic Apps e Power Automate)
- Microsoft Learn: usar expressões em condições no Power Automate
- Microsoft Learn: convertFromUtc, convertToUtc e convertTimeZone
- Microsoft Learn: nomes de fuso horário do Windows
- Microsoft Learn: operações de dados (Compor, Analisar JSON, Selecionar, Associar)
Preços, nomes de plano e limites mudam. Confira sempre a tabela oficial da Microsoft antes de decidir.
Perguntas frequentes
O que mais perguntam sobre este assunto
- Por que a data aparece com 3 horas de diferença?
- Porque o Power Automate guarda e devolve datas em UTC, e Brasília é UTC menos 3 horas. Quando você exibe o valor sem converter, aparece a hora de Londres. Use convertFromUtc(data, 'E. South America Standard Time', 'dd/MM/yyyy HH:mm') na hora de mostrar e mantenha o dado gravado em UTC. Coluna só de data, sem hora, não precisa de conversão.
- Como tratar campo vazio?
- Navegue com o operador ?, que devolve nulo em vez de erro quando a propriedade não existe: triggerOutputs()?['body/Telefone']. Depois dê um valor padrão com coalesce(valor, 'não informado') ou teste com if(empty(valor), um, outro). Em Analisar JSON, permita null no esquema dos campos opcionais, senão a ação falha no primeiro registro incompleto.
- Qual a diferença entre body e outputs?
- outputs('Acao') devolve tudo o que a ação retornou: código de status, cabeçalhos e corpo. body('Acao') é um atalho para outputs('Acao')?['body'], só o conteúdo. O mesmo vale para triggerOutputs() e triggerBody(). Na prática, body serve para ler dados e outputs para quando você precisa do status ou de um cabeçalho da resposta.
- Como formatar número em reais?
- formatNumber(valor, 'C2', 'pt-BR') devolve R$ 1.234,50. O valor precisa ser número: se veio como texto, envolva com float() antes. Sem o símbolo, use 'N2' com 'pt-BR', que devolve 1.234,50. A formatação é só para exibir em e-mail ou cartão; para gravar em coluna numérica, mande o número puro.

