Painel de controle de automação de fluxos de aprovação com n8n mostrando dashboard moderno

Construí um Sistema de Aprovação Automático com n8n Que Eliminou 200 Emails Por Semana

Na segunda-feira passada, abri o email e tinha 47 mensagens esperando aprovação. Orçamento de cliente. Acesso ao servidor. Release de código. Solicitação de compra. Cada uma precisava de um “OK” meu. Eu tinha me tornado o gargalo humano da minha própria operação.

O problema não era a quantidade — era o context switching. Toda vez que alguém me mandava um email pedindo aprovação, eu interrompia o que estava fazendo, abria o email, avaliava, respondia, e tentava voltar ao foco. Pesquisa da Universidade da Califórnia mostra que cada interrupção custa em média 23 minutos de reconexão. Faça a conta: 47 emails × 23 minutos = 18 horas perdidas por semana só em mudança de contexto.

Foi quando decidi automatizar todo o ciclo de aprovação com n8n e webhooks. Hoje, recebo em média 3 notificações por dia — e o sistema aprova sozinho 85% das solicitações baseado em regras que eu defini. Os outros 15% chegam no meu Telegram com contexto suficiente pra eu decidir em 30 segundos.

Diagrama de fluxo de aprovação desenhado mostrando etapas de automação com n8n
O segredo está em mapear o fluxo ANTES de abrir o n8n. Papel e caneta salvam horas de retrabalho.

Se você já brincou com automações do dia a dia mas nunca construiu algo que toma decisões por você, este post é o próximo nível. Vou mostrar cada webhook, cada condicional, cada erro que eu cometi no caminho — pra você não repetir.

Por Que n8n e Não Zapier ou Make?

Eu comecei com Zapier. Funcionou por 2 meses. Aí as tasks começaram a passar do limite gratuito, os webhooks ficaram lentos, e eu percebi que estava pagando U$ 49/mês pra aprovar orçamentos de R$ 200.

n8n é self-hosted, sem limites de execução, e a lógica condicional é muito mais poderosa. Você escreve JavaScript nos nós quando precisa de flexibilidade — algo que no Zapier exige conectar 3 apps intermediários.

Comparativo honesto:

  • Zapier: Mais fácil de começar, interface bonita, caro pra escalar. Bom pra quem não quer tocar em código.
  • Make (Integromat): Mais flexível que Zapier, visual confuso, pricing melhor. Bom pra fluxos complexos sem código.
  • n8n: Self-hostado, sem limites, requer mais setup inicial. Ideal pra quem quer controle total e já se sente confortável com APIs e automação.

Eu escolhi n8n porque queria que minhas aprovações rodassem no meu servidor, com meu banco de dados, sem depender de terceiro que pode mudar o pricing amanhã.

A Arquitetura do Sistema de Aprovação

Antes de abrir o n8n, desenhei o fluxo completo no papel. Esse passo é essencial — pule e você vai refatorar 4 vezes como eu fiz.

O sistema tem 3 camadas:

Camada 1: Ingestão (Webhook Receiver)

Diferentes fontes enviam solicitações pra um único endpoint do n8n. Cada fonte tem um formato diferente:

  • Formulários Google → POST com JSON estruturado
  • Email (via IMAP trigger) → Parse do corpo do email
  • Slack/Discord → Webhook de reação ou comando
  • API customizada → POST de sistemas internos

Camada 2: Motor de Decisão (Conditional + Code Nodes)

Aqui mora a inteligência. Regras como:

  • Orçamento menor que R$ 500? Aprova automaticamente.
  • Solicitante está na lista de confiáveis? Aprova com log.
  • Valor entre R$ 500 e R$ 2000? Notifica via Telegram com botões de aprovar/rejeitar.
  • Acima de R$ 2000? Bloqueia e notifica com alerta.
  • Compra recorrente já aprovada antes? Auto-aprova se dentro de 10% do último valor.

Camada 3: Execução e Auditoria

Uma vez aprovado (ou rejeitado), o sistema:

  1. Registra a decisão num banco de dados com timestamp, solicitante, valor e justificativa
  2. Notifica o solicitante via email ou Slack
  3. Se for compra, cria um card no Trello/Notion com os detalhes
  4. Atualiza uma planilha de controle mensal

Passo a Passo: Construindo o Webhook Receiver

No n8n, crie um novo workflow e adicione um nó Webhook. Configure assim:

{
  "httpMethod": "POST",
  "path": "approval-request",
  "authentication": "headerAuth",
  "responseMode": "lastNode"
}

O headerAuth é fundamental. Sem autenticação, qualquer pessoa pode enviar solicitações falsas pro seu endpoint. Eu uso um header customizado:

// No header da requisição:
X-Approval-Token: sua-chave-secreta-aqui

// No n8n, configure headerAuth com:
// Header Name: X-Approval-Token
// Header Value: sua-chave-secreta-aqui

Depois do Webhook node, adicione um Switch node pra classificar o tipo de solicitação baseado no campo type do payload:

// Payload padrão que toda fonte deve enviar:
{
  "type": "budget" | "purchase" | "access" | "release",
  "requester": "nome@email.com",
  "amount": 150.00,
  "description": "Renovação licença Figma",
  "urgency": "low" | "medium" | "high",
  "source": "google-form" | "email" | "slack"
}

Cada branch do Switch vai pra um fluxo diferente. Vou detalhar o fluxo de compras, que é o mais complexo.

O Motor de Decisão em Detalhes

Depois do Switch (branch “purchase”), o fluxo tem esta sequência:

1. Verificar se é compra recorrente

Adicione um nó Postgres (ou MySQL/SQLite) que consulta o histórico:

-- Query no banco de aprovações
SELECT amount, approved_at, requester
FROM approvals
WHERE description ILIKE '%{{ $json.description }}%'
  AND status = 'approved'
  AND approved_at > NOW() - INTERVAL '90 days'
ORDER BY approved_at DESC
LIMIT 1;

Se encontrar uma compra similar nos últimos 90 dias, o próximo nó Code compara os valores:

// Code node: check_recurring_purchase
const lastAmount = $input.all()[0]?.json?.amount || 0;
const currentAmount = $('Webhook').item.json.amount;
const requester = $('Webhook').item.json.requester;
const trustedRequesters = [
  'dev@minhaempresa.com',
  'design@minhaempresa.com',
  'pm@minhaempresa.com'
];

const isRecurring = lastAmount > 0;
const withinThreshold = Math.abs(currentAmount - lastAmount) / lastAmount <= 0.10;
const isTrusted = trustedRequesters.includes(requester);
const belowLimit = currentAmount <= 500;

// Decisão automática
if ((isRecurring && withinThreshold) || (belowLimit && isTrusted)) {
  return [{
    json: {
      decision: 'auto_approved',
      reason: isRecurring
        ? `Compra recorrente. Último valor: R$ ${lastAmount}. Dentro de 10%.`
        : `Abaixo de R$ 500 e solicitante confiável.`,
      autoApproved: true
    }
  }];
}

// Precisa de aprovação humana
return [{
  json: {
    decision: 'pending',
    reason: `Valor R$ ${currentAmount}. Precisa aprovação manual.`,
    autoApproved: false
  }
}];
Código de webhook e automação n8n em tela com sintaxe colorida para fluxos de aprovação
Code nodes são onde a mágica acontece. JavaScript puro dentro do n8n = flexibilidade sem limites.

2. Se auto-aprovado → Loga e Notifica

Adicione um nó Postgres pra registrar a aprovação:

INSERT INTO approvals (
  type, requester, amount, description,
  status, decision_reason, auto_approved,
  webhook_payload, approved_at
) VALUES (
  '{{ $('Webhook').item.json.type }}',
  '{{ $('Webhook').item.json.requester }}',
  {{ $('Webhook').item.json.amount }},
  '{{ $('Webhook').item.json.description }}',
  'approved',
  '{{ $json.reason }}',
  true,
  '{{ JSON.stringify($('Webhook').item.json) }}',
  NOW()
);

E um nó Telegram pra me notificar que algo foi auto-aprovado (supervisão, não intervenção):

✅ Aprovação automática

📝 {{ $json.description }}
💰 R$ {{ $('Webhook').item.json.amount }}
👤 {{ $('Webhook').item.json.requester }}
🤖 Motivo: {{ $json.reason }}

📊 Aprovações hoje: {{ $('Count Today').item.json.count }}

3. Se pendente → Notifica com Botões de Aprovação

Esse é o pulo do gato. Em vez de mandar um email que eu preciso abrir, logar e responder, mando uma mensagem no Telegram com inline buttons:

// Telegram node com Inline Keyboard
{
  "chat_id": "seu_chat_id",
  "text": "⏳ Aprovação Pendente\n\n📝 {{ $('Webhook').item.json.description }}\n💰 R$ {{ $('Webhook').item.json.amount }}\n👤 {{ $('Webhook').item.json.requester }}\n⚡ Urgência: {{ $('Webhook').item.json.urgency }}",
  "reply_markup": {
    "inline_keyboard": [
      [
        {"text": "✅ Aprovar", "callback_data": "approve_{{ $runIndex }}"},
        {"text": "❌ Rejeitar", "callback_data": "reject_{{ $runIndex }}"}
      ],
      [
        {"text": "⏰ Lembrar em 1h", "callback_data": "snooze_{{ $runIndex }}"}
      ]
    ]
  }
}

Para capturar os callbacks, crie um segundo workflow no n8n com um Telegram Trigger node que escuta callback_query. Quando alguém aperta "Aprovar", o workflow registra a decisão no banco e notifica o solicitante.

Erros Que Me Custaram Horas (Pra Você Não Repetir)

🔥 Perrengue #1: O Loop Infinito de Aprovação

Na primeira versão, configurei a notificação de "aprovado" pra ir pro mesmo canal que recebia as solicitações. Resultado: o sistema aprovava, notificava, a notificação era interpretada como nova solicitação, aprovava de novo... 340 emails em 12 minutos. O Gmail marcou meu servidor como spam por 3 dias.

Correção: Use headers diferentes pra "solicitação" vs "notificação". E coloque um deduplication_id em cada payload.

🔥 Perrengue #2: O Webhook Que Morreu Silenciosamente

O n8n tava rodando num container Docker com restart policy on-failure. Só que o webhook não dava erro — ele simplesmente parava de funcionar quando o container reiniciava, porque o endpoint mudava. Fiquei 2 semanas achando que ninguém tava pedindo aprovação.

Correção: Use restart: unless-stopped no docker-compose e configure um health check que bate no webhook a cada 5 minutos. Se falhar, reinicia e manda alerta.

🔥 Perrengue #3: A Injeção de SQL Disfarçada de Descrição

Um solicitante colocou na descrição: Renovação'; DROP TABLE approvals; --. Claro que eu tava usando concatenação de string nas queries em vez de parâmetros preparados. O n8n executou a query como string literal e... bem, o banco tava com backup automático, mas levei um susto.

Correção: NUNCA use {{ }} direto em queries SQL. Use Query Parameters do nó Postgres/MySQL do n8n. Sempre.

Monitoramento: Dashboard de Aprovações

Com os dados no banco, criei uma view que alimenta um Grafana simples:

-- View para o dashboard
CREATE VIEW v_approval_dashboard AS
SELECT
  DATE(approved_at) AS dia,
  COUNT(*) FILTER (WHERE auto_approved = true) AS auto_aprovadas,
  COUNT(*) FILTER (WHERE auto_approved = false) AS manuais,
  COUNT(*) FILTER (WHERE status = 'rejected') AS rejeitadas,
  ROUND(AVG(amount), 2) AS valor_medio,
  SUM(amount) AS total_dia
FROM approvals
WHERE approved_at > NOW() - INTERVAL '30 days'
GROUP BY DATE(approved_at)
ORDER BY dia DESC;

Esse dashboard me mostra tendências. Descobri, por exemplo, que terças-feiras têm 3x mais solicitações de compra que sexta-feiras. Provavelmente porque segunda todo mundo planeja e terça executa. Com essa info, ajustei o limite de auto-aprovação pra ser mais generoso nas terças (pra não me interromper tanto) e mais restrito nas sextas (quando tem menos volume e posso avaliar melhor).

Se você ainda não tem scripts de automação no terminal pra monitorar seus serviços, esse é um bom momento pra começar.

Integração com Seu Stack Existente

Google Forms → n8n → Aprovação

O fluxo mais simples. Configure um Google Form com campos que mapeiam pro payload padrão. Use o trigger "On form submit" do Google Apps Script pra fazer um POST pro webhook do n8n:

// Google Apps Script (no editor do Google Forms)
function onFormSubmit(e) {
  var responses = e.response.getItemResponses();
  var payload = {};
  
  responses.forEach(function(r) {
    var title = r.getItem().getTitle().toLowerCase()
      .replace(/[^a-z0-9]/g, '_');
    payload[title] = r.getResponse();
  });
  
  payload.type = 'purchase';
  payload.source = 'google-form';
  payload.amount = parseFloat(payload.valor) || 0;
  
  var options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'X-Approval-Token': 'sua-chave-secreta-aqui'
    },
    payload: JSON.stringify(payload)
  };
  
  UrlFetchApp.fetch('https://seu-n8n.com/webhook/approval-request', options);
}

Notion Database → n8n

Se você usa Notion pra organizar a vida, pode criar um database de "Solicitações" com um status "Pendente". Configure um trigger no n8n que monitora mudanças no database via Notion API:

// Notion trigger setup no n8n
// 1. Adicione Notion Trigger node
// 2. Configure: Database = "Solicitações"
// 3. Filter: Status = "Pendente"
// 4. Mapeie os campos pro payload padrão
// 5. Conecte ao mesmo fluxo de decisão

// Mapeamento dos campos:
const notionItem = $input.all()[0].json;
return [{
  json: {
    type: notionItem.properties.Tipo.select.name.toLowerCase(),
    requester: notionItem.properties.Solicitante.email,
    amount: notionItem.properties.Valor.number,
    description: notionItem.properties.Descrição.title[0]?.plain_text || '',
    urgency: notionItem.properties.Urgência.select.name.toLowerCase(),
    source: 'notion',
    notion_page_id: notionItem.id
  }
}];

Segurança: Não Seja Inocente

Um sistema que aprova automaticamente gastos precisa de proteção séria. Aqui vão as medidas não-negociáveis:

  • Autenticação no webhook: Header token + IP whitelist se possível
  • Rate limiting: Máximo de 10 solicitações por requester por hora. Acima disso, bloqueia e alerta
  • Auditoria completa: Toda decisão é logada com payload original, regra aplicada e timestamp
  • Limite diário: Soma de auto-aprovações não pode passar de um teto diário (ex: R$ 5.000)
  • Reversão: Toda aprovação automática pode ser revertida em até 24h
// Code node: daily_limit_check
const todayTotal = $input.all()
  .filter(item => item.json.auto_approved)
  .reduce((sum, item) => sum + (item.json.amount || 0), 0);

const currentRequest = $('Webhook').item.json.amount;
const DAILY_LIMIT = 5000;

if (todayTotal + currentRequest > DAILY_LIMIT) {
  return [{
    json: {
      decision: 'pending',
      reason: `Limite diário excedido. Aprovado hoje: R$ ${todayTotal}. Solicitado: R$ ${currentRequest}. Limite: R$ ${DAILY_LIMIT}`,
      autoApproved: false,
      limitExceeded: true
    }
  }];
}

// Passa pra próxima verificação
return [{ json: { ...$('Webhook').item.json, dailyTotal: todayTotal } }];

O Antes e Depois em Números

Depois de 30 dias rodando o sistema:

MétricaAntesDepois
Emails de aprovação/semana~200~30
Tempo médio de resposta4 horas12 minutos
Aprovações automáticas0%85%
Erros de aprovação3/mês0 em 30 dias
Horas economizadas/semana~12 horas

O número que mais me impressiona é o tempo de resposta. Antes, alguém pedia aprovação e esperava em média 4 horas (porque eu estava em outra coisa, via o email, esquecia, lembrava...). Hoje, se é auto-aprovado, leva 12 segundos. Se precisa de mim, eu decido em 30 segundos pelo Telegram.

Isso tem um efeito cascata impressionante. Projetos que antes esperavam dias por aprovação de orçamento agora avançam na mesma hora. O debug de problemas que antes dependia de aprovação de acesso agora é instantâneo.

Próximos Passos: IA no Loop de Decisão

O sistema atual usa regras estáticas. Funciona, mas tem limites. Estou experimentando adicionar um LLM no loop de decisão pra casos que não se encaixam nas regras:

// Code node: ai_assisted_decision (experimental)
const description = $('Webhook').item.json.description;
const amount = $('Webhook').item.json.amount;
const history = $('Get History').all().map(h => h.json);

// Chama LLM local (Ollama) com contexto
const prompt = `Você é um assistente de aprovação de compras.
Analise esta solicitação e recomende APROVAR ou REJEITAR.

Solicitação: ${description}
Valor: R$ ${amount}

Histórico de aprovações similares (últimos 30 dias):
${history.map(h => `- ${h.description}: R$ ${h.amount} → ${h.status}`).join('\n')}

Responda em JSON: {"decision": "approve"|"reject", "confidence": 0-1, "reasoning": "..."}`;

// A aprovação final ainda é humana pra confiança < 0.9
// Isso é um ASSISTENTE, não um decisor autônomo

O ponto chave: IA recomenda, humano decide. Pelo menos até eu ter confiança estatística de que o modelo acerta em >99% dos casos. Atualizar regras estáticas é chato, mas perder controle de um processo financeiro é pior.

Setup em 30 Minutos: O Fluxo Mínimo Viável

Se você quer começar hoje sem complicação, aqui vai o MVP:

  1. Instale o n8n: docker run -p 5678:5678 n8nio/n8n
  2. Crie o webhook: POST endpoint com autenticação por header
  3. Adicione um Code node com a regra mais simples: "se valor < X, aprova"
  4. Adicione um Telegram node pra notificar aprovações e pendências
  5. Teste com curl:
    curl -X POST https://seu-n8n.com/webhook/test -H "X-Approval-Token: key" -H "Content-Type: application/json" -d '{"type":"purchase","amount":50,"description":"Teste","requester":"voce@email.com"}'

Funciona? Ótimo. Agora itere. Adicione banco de dados, depois regras mais complexas, depois o dashboard. Não tente construir o sistema inteiro no primeiro dia.

Eu demorei 2 semanas pra chegar na versão atual — e ainda estou melhorando. Meu pipeline de IA também já me quebrou a cara, então aprendi que iteração > perfeição.

CTA: Qual Automação Você Quer Ver?

Montei esse sistema porque garra é resolver o problema que ninguém resolve por você. Se você tivesse um sistema que aprova automaticamente as tarefas repetitivas do seu dia, qual seria a primeira coisa que você automatizaria?

Me conta nos comentários. Se eu receber 5 pedidos do mesmo tipo, eu construo e documento aqui no blog — passo a passo, com os erros incluídos.

E se você quer aprender mais sobre automação com IA e ferramentas de produtividade, assina a newsletter. Toda semana tem um tutorial novo que saiu da minha vida real — não de um manual teórico escrito por quem nunca automatizou nada.

Posts Similares