Alerta de dólar no celular com n8n
No tutorial n8n do zero com Docker: instale e receba a cotação do dólar no e-mail, o n8n buscava a cotação e mandava um e-mail todos os dias. Agora vamos dar um passo além: o n8n vai conferir o dólar a cada hora e só vai avisar quando ele passar de um limite que você escolher. O aviso chega como notificação no celular, pelo ntfy, sem cadastro e sem chave.
É a primeira vez nesta série que o workflow toma uma decisão: com o nó If, ele segue por um caminho quando a condição é verdadeira e por outro quando é falsa. Você também vai ver por que é importante converter texto em número antes de comparar valores.
O que você vai construir
Este é o workflow final no editor do n8n:

- Schedule Trigger: roda o workflow a cada hora.
- HTTP Request: busca a cotação do dólar na AwesomeAPI.
- Edit Fields: transforma a cotação e a variação em números e define o limite.
- If: pergunta se o dólar passou do limite.
- HTTP Request1: manda a notificação para o ntfy, só quando a resposta é sim (true).
Versão usada: n8n 2.40.7. Os nomes de botões e campos aparecem em inglês, exatamente como na interface. O tópico do ntfy usado aqui, alerta-dolar-35fadd3dde4ae2cc, é só um exemplo: crie o seu, como explicado no Nó 5.
Pré-requisitos
- Um n8n funcionando no seu computador. Se ainda não tem, siga antes o tutorial n8n do zero com Docker: instale e receba a cotação do dólar no e-mail.
- O app ntfy no celular, gratuito para Android e iPhone. O tutorial do lembrete no celular com n8n explica o ntfy com calma, inclusive como se inscrever num tópico.
- Nenhuma conta, senha ou chave de API.
Montando o workflow, nó por nó
Crie um workflow novo e dê a ele o nome Alerta de dólar no celular. Depois, adicione os nós abaixo, nesta ordem, sempre pelo botão + que aparece à direita do nó anterior.
Nó 1: Schedule Trigger (a cada hora)
Clique em Add first step, escolha On a schedule e preencha:

| Campo | Valor | Por que assim |
|---|---|---|
| Trigger Interval | Hours | A repetição é contada em horas. |
| Hours Between Triggers | 1 | Roda de hora em hora. |
| Trigger at Minute | 0 | Sempre na hora cheia: 9h00, 10h00, 11h00… |
O aviso no topo do nó lembra que o agendamento só vale depois que o workflow for publicado; para testar, basta clicar em Execute workflow no canvas. Ao clicar em Execute step, a saída mostra a data e a hora da execução e o fuso usado, America/Sao_Paulo (UTC-03:00).
Nó 2: HTTP Request (buscar a cotação)
Usamos a mesma API do primeiro tutorial, a AwesomeAPI, gratuita. Esta é a URL:
https://economia.awesomeapi.com.br/json/last/USD-BRL

| Campo | Valor | Por que assim |
|---|---|---|
| Method | GET | Vamos apenas consultar dados. |
| URL | a URL do bloco acima | Última cotação do par dólar/real (USD-BRL). |
| Authentication | None | A API é pública. |
| Send Query Parameters / Headers / Body | desligados | Não são necessários. |
A resposta vem dentro de um objeto chamado USDBRL. Os campos que vamos usar são bid (a cotação de compra, "5.1866" no teste), pctChange (a variação no dia, em porcentagem, "-0.096306") e create_date (quando a cotação foi registrada, 2026-09-25 18:30:14). Repare nas aspas: bid e pctChange chegam como texto, não como número. Isso faz diferença no nó If.
Um detalhe do teste: ele foi feito na madrugada de domingo, 27/09, e a cotação era a de sexta-feira, porque o mercado de câmbio não funciona no fim de semana.
Nó 3: Edit Fields (converter texto em número)
Clique no + à direita do HTTP Request e adicione um nó Edit Fields (Set). Em Mode, deixe Manual Mapping e crie quatro campos com Add Field. O tipo de cada campo é escolhido na lista abaixo do nome:

| Campo | Valor | Por que assim |
|---|---|---|
dolar (Number) | {{ $json.USDBRL.bid }} | A cotação, convertida em número pelo próprio tipo do campo. |
variacao (Number) | {{ $json.USDBRL.pctChange }} | A variação do dia, também como número. |
limite (Number) | 5.5 | O valor que dispara o alerta. Troque pelo seu. Use ponto, e não vírgula, nas casas decimais. |
atualizado (String) | {{ $json.USDBRL.create_date }} | A data da cotação, para mostrar na mensagem. |
| Include Other Input Fields | desligado | A saída fica só com esses quatro campos. |
Clique em Execute step. Na saída, dolar aparece como 5.1866, sem aspas, e variacao como -0.096306. Deixar o limite num campo próprio, logo no começo, facilita a manutenção: para mudar o valor, você mexe num lugar só.
Nó 4: If (passou do limite?)
Clique no + à direita do Edit Fields e adicione um nó If. Ele tem duas saídas: true, quando a condição é verdadeira, e false, quando não é.

| Campo | Valor | Por que assim |
|---|---|---|
| Conditions → valor 1 | {{ $json.dolar }} | A cotação atual. |
| Conditions → operador | Number → is greater than | Compara como número: “é maior que”. |
| Conditions → valor 2 | {{ $json.limite }} | O limite definido no nó anterior. |
| Convert types where required | desligado | Os campos já são números. Deixar desligado faz o n8n acusar se algum texto chegar por engano. |
Para escolher o operador, clique na lista ao lado do primeiro valor, passe o mouse em Number e escolha is greater than. Clique em Execute step: com o dólar em 5,1866 e o limite em 5,5, a condição é falsa, e o item aparece na aba False Branch (1 item).
Nó 5: HTTP Request1 (mandar o alerta para o ntfy)
O ntfy funciona com tópicos: quem está inscrito num tópico recebe tudo o que é enviado para ele. Qualquer pessoa que souber o nome do tópico pode ler as mensagens, por isso use um nome longo e aleatório. O tópico deste tutorial, alerta-dolar-35fadd3dde4ae2cc, é só um exemplo e, como está publicado aqui, deixou de ser secreto: crie o seu, trocando os caracteres depois de “alerta-dolar-” por outros quaisquer (letras sem acento, números e hífens).
No nó If, clique no + da saída true e adicione outro HTTP Request. Como já existe um nó com esse nome, o n8n o chama de HTTP Request1. Esta é a URL, com o tópico no final:
https://ntfy.sh/alerta-dolar-35fadd3dde4ae2cc
E este é o texto da mensagem, que vai no Body:
O dólar está em R$ {{ $json.dolar.toFixed(2) }}, acima do seu limite de R$ {{ $json.limite.toFixed(2) }}. Variação no dia: {{ $json.variacao.toFixed(2) }}%. Cotação de {{ $json.atualizado }}.

| Campo | Valor | Por que assim |
|---|---|---|
| Method | POST | Estamos enviando uma mensagem. |
| URL | a URL do primeiro bloco acima | Servidor público ntfy.sh com o nome do seu tópico. |
| Authentication | None | O ntfy.sh não exige conta. |
| Send Headers | ligado | Para mandar o título da notificação. |
| Headers → Name / Value | Title / Alerta de dolar | O ntfy usa o cabeçalho Title como título. Fica sem acento porque cabeçalhos HTTP embaralham acentos, como mostramos no tutorial do lembrete. |
| Send Body | ligado | O texto da notificação vai no corpo. |
| Body Content Type | Raw | Enviamos o texto puro. |
| Content Type | text/plain | Avisa que o corpo é texto simples. |
| Body | o texto do segundo bloco acima | A mensagem. No corpo, os acentos funcionam normalmente. |
No texto, .toFixed(2) arredonda os números para duas casas decimais: 5,1866 vira 5.19. Esse método só existe para números; é mais um motivo para converter os campos no Nó 3. A saída false do If fica sem nenhum nó: quando o dólar está abaixo do limite, o workflow simplesmente termina.
O workflow completo e o teste
Antes de testar, inscreva o celular no seu tópico pelo app ntfy (botão +, nome exato do tópico, servidor padrão ntfy.sh). Depois, teste os dois caminhos.
Caminho false: dólar abaixo do limite
Com o limite em 5.5, clique em Execute workflow. O item passa pelo If e sai pela saída false, que não tem nada ligado. O HTTP Request1 não roda e nenhuma notificação é enviada:

Caminho true: dólar acima do limite
Para ver o alerta funcionando sem esperar o dólar subir, abra o Edit Fields e troque o limite para 5, temporariamente. Clique em Execute workflow de novo. Agora o item sai pela saída true e o HTTP Request1 roda:


O ntfy confirmou o envio e a notificação chegou com o título “Alerta de dolar” e o texto “O dólar está em R$ 5.19, acima do seu limite de R$ 5.00. Variação no dia: -0.10%. Cotação de 2026-09-25 18:30:14.”. Abaixo, a mesma mensagem vista no navegador, na página do tópico no ntfy.sh:

Depois do teste, volte o limite para o valor que você quer de verdade (no exemplo, 5.5).
Ligar o alerta de verdade
Clique em Publish, no canto superior direito do editor, e confirme. A partir daí, o n8n consulta o dólar a cada hora cheia, enquanto estiver rodando. Atenção: enquanto o dólar continuar acima do limite, chega um alerta por hora. Se isso incomodar, aumente o intervalo no Schedule Trigger (por exemplo, a cada 3 horas) ou suba o limite depois de receber o aviso.
Erros comuns
“Wrong type: ‘5.1866’ is a string but was expecting a number”. Aconteceu quando deixamos o campo dolar como String no Edit Fields. O If recebeu um texto para comparar como número e parou com erro. O próprio n8n sugere duas saídas: ligar Convert types where required ou acrescentar .toNumber(). A solução mais clara é a do Nó 3: escolher o tipo Number no campo.
![Nó If com a condição em vermelho e o erro Wrong type: 5.1866 is a string but was expecting a number [condition 0, item 0], com as sugestões Enabling Convert types where required e .toNumber()](https://orbitacode.cloud/wp-content/uploads/2026/09/dolar-11-erro-texto-em-vez-de-numero.webp)
O alerta nunca dispara, sem nenhum erro. Este é o mais traiçoeiro. Aconteceu quando escrevemos {{ $json.bid }} em vez de {{ $json.USDBRL.bid }}: o campo bid fica dentro de USDBRL, então a expressão não achou nada e dolar ficou null (vazio).

O If não reclamou: comparou o vazio com o limite, concluiu que não era maior e mandou o item para a saída false. Na prática, o workflow roda toda hora e nunca avisa. Por isso, teste sempre o caminho true, como fizemos acima, e confira se dolar tem um número na saída do Edit Fields.

JSON do workflow para importar
Se preferir, importe o workflow pronto. Baixe o arquivo abaixo ou copie o JSON. No n8n, crie um workflow novo e escolha uma das opções: abra o menu … (três pontinhos) no topo do editor, vá em Import e depois em From file; ou cole o JSON direto no canvas com Ctrl+V.
O download é um arquivo .zip com o alerta-dolar-celular.json dentro. Descompacte antes de importar (ou copie o JSON do bloco abaixo).
{
"name": "Alerta de dólar no celular",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours"
}
]
}
},
"id": "6d2f8a41-1111-4e3b-a106-120000000001",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
0,
0
]
},
{
"parameters": {
"url": "https://economia.awesomeapi.com.br/json/last/USD-BRL",
"options": {}
},
"id": "6d2f8a41-2222-4e3b-a106-120000000002",
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.5,
"position": [
220,
0
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "6d2f8a41-a001-4e3b-a106-1200000000a1",
"name": "dolar",
"value": "={{ $json.USDBRL.bid }}",
"type": "number"
},
{
"id": "6d2f8a41-a002-4e3b-a106-1200000000a2",
"name": "variacao",
"value": "={{ $json.USDBRL.pctChange }}",
"type": "number"
},
{
"id": "6d2f8a41-a003-4e3b-a106-1200000000a3",
"name": "limite",
"value": 5.5,
"type": "number"
},
{
"id": "6d2f8a41-a004-4e3b-a106-1200000000a4",
"name": "atualizado",
"value": "={{ $json.USDBRL.create_date }}",
"type": "string"
}
]
},
"options": {}
},
"id": "6d2f8a41-3333-4e3b-a106-120000000003",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
440,
0
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "6d2f8a41-c001-4e3b-a106-1200000000c1",
"leftValue": "={{ $json.dolar }}",
"rightValue": "={{ $json.limite }}",
"operator": {
"type": "number",
"operation": "gt"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "6d2f8a41-4444-4e3b-a106-120000000004",
"name": "If",
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
660,
0
]
},
{
"parameters": {
"method": "POST",
"url": "https://ntfy.sh/alerta-dolar-35fadd3dde4ae2cc",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Title",
"value": "Alerta de dolar"
}
]
},
"sendBody": true,
"contentType": "raw",
"rawContentType": "text/plain",
"body": "=O dólar está em R$ {{ $json.dolar.toFixed(2) }}, acima do seu limite de R$ {{ $json.limite.toFixed(2) }}. Variação no dia: {{ $json.variacao.toFixed(2) }}%. Cotação de {{ $json.atualizado }}.",
"options": {}
},
"id": "6d2f8a41-5555-4e3b-a106-120000000005",
"name": "HTTP Request1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.5,
"position": [
900,
-100
]
}
],
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"If": {
"main": [
[
{
"node": "HTTP Request1",
"type": "main",
"index": 0
}
],
[]
]
}
},
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"meta": {
"templateCredsSetupCompleted": false
}
}
Depois de importar, troque o tópico de exemplo na URL do HTTP Request1 pelo seu e ajuste o limite no Edit Fields. O workflow não usa credenciais.
Recapitulando
- O Schedule Trigger roda o workflow a cada hora, depois de publicado.
- A AwesomeAPI manda a cotação como texto; o tipo Number no Edit Fields converte em número.
- O If divide o caminho: true envia o alerta, false termina sem fazer nada.
- Teste os dois caminhos mudando o limite, e volte o valor ao normal depois.
- Um caminho errado na expressão não dá erro, mas deixa o alerta mudo: confira sempre os dados na saída de cada nó.
Com o If, seus workflows passam a decidir sozinhos. A mesma estrutura serve para avisar quando qualquer valor passa de um limite: outra moeda, a temperatura, o preço de um produto.