Pular para conteúdo

WEBHOOK - Requisições HTTP Genéricas

O que é este Node?

O WEBHOOK é o node responsável por executar requisições HTTP para qualquer URL externa com suporte a diferentes métodos, headers e corpo da requisição.

Por que este Node existe?

Integrar sistemas externos via HTTP é essencial. O WEBHOOK existe para:

  1. Integração universal: Conectar com qualquer API REST que não tenha node dedicado
  2. Flexibilidade total: Suporte a todos os métodos HTTP (GET, POST, PUT, PATCH, DELETE)
  3. Customização completa: Controle de headers, body, timeout e autenticação
  4. Notificações: Enviar eventos para sistemas externos em tempo real
  5. Automação: Disparar ações em outros sistemas baseado no flow

Como funciona internamente?

Quando o WEBHOOK é executado, o sistema:

  1. Valida URL: Verifica se a URL foi fornecida
  2. Prepara configuração: Define método, headers, body e timeout
  3. Configura headers: Adiciona Content-Type e headers customizados
  4. Inclui body: Se método for POST/PUT/PATCH, serializa o body
  5. Executa requisição: Faz chamada HTTP para URL externa
  6. Retorna resposta: Status code, headers e dados da resposta
  7. Se erro: Lança exceção com mensagem de erro

Código interno (infrastructure-executor.service.ts:734-775):

private async executeWebhook(parameters: any, context: any): Promise<any> {
  const { url, method = 'POST', headers = {}, body, timeout = 30000 } = parameters;

  this.logger.log(`🪝 WEBHOOK - Method: ${method}, URL: ${url}`);

  if (!url) {
    throw new Error('Webhook URL is required');
  }

  try {
    const config: any = {
      method: method.toUpperCase(),
      url,
      timeout,
      headers: {
        'Content-Type': 'application/json',
        ...headers
      }
    };

    if (body && ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase())) {
      config.data = typeof body === 'string' ? body : JSON.stringify(body);
    }

    const response = await firstValueFrom(this.httpService.request(config));

    return {
      success: true,
      action: 'webhook_executed',
      method: method.toUpperCase(),
      url,
      statusCode: response.status,
      statusText: response.statusText,
      headers: response.headers,
      data: response.data,
      timestamp: new Date().toISOString()
    };
  } catch (error) {
    this.logger.error(`❌ Webhook execution failed:`, error);
    throw new Error(`Webhook failed: ${error.message}`);
  }
}

Quando você DEVE usar este Node?

Use WEBHOOK sempre que precisar integrar com APIs externas:

Casos de uso

  1. Enviar notificação: Disparar evento para sistema de notificações
  2. Integrar CRM: Criar/atualizar leads em sistemas não suportados
  3. Webhooks externos: Notificar serviços de eventos do flow
  4. APIs REST customizadas: Chamar APIs internas da sua empresa
  5. Testes de API: Validar endpoints durante desenvolvimento

Quando NÃO usar WEBHOOK

  • Google APIs: Use nodes específicos do Google (Google Sheets, Gmail, etc.)
  • AWS Services: Use nodes específicos da AWS (SQS, SNS, S3, etc.)
  • Integrações nativas: Se existe node dedicado, use ele ao invés

Parâmetros Detalhados

url (string, obrigatório)

O que é: URL completa do endpoint que será chamado.

Flow completo para testar:

{
  "name": "Teste WEBHOOK - URL",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "webhook_1",
      "type": "webhook",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Chamar API",
        "parameters": {
          "url": "https://jsonplaceholder.typicode.com/posts/1",
          "method": "GET"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Mostrar Resposta",
        "parameters": {
          "message": "Status: {{webhook_1.statusCode}}\nDados recebidos!"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "webhook_1" },
    { "source": "webhook_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Execute o flow e veja a API ser chamada com sucesso!

method (string, opcional)

O que é: Método HTTP a ser usado na requisição.

Padrão: "POST"

Valores válidos: GET, POST, PUT, PATCH, DELETE

Flow completo para testar:

{
  "name": "Teste WEBHOOK - Method POST",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "webhook_1",
      "type": "webhook",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "POST Request",
        "parameters": {
          "url": "https://jsonplaceholder.typicode.com/posts",
          "method": "POST",
          "body": {
            "title": "Teste",
            "body": "Conteúdo do post",
            "userId": 1
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "Criado! ID: {{webhook_1.data.id}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "webhook_1" },
    { "source": "webhook_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: POST cria novo recurso na API e retorna ID gerado.

headers (object, opcional)

O que é: Headers HTTP customizados para incluir na requisição.

Padrão: { "Content-Type": "application/json" }

Flow completo para testar:

{
  "name": "Teste WEBHOOK - Headers",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "webhook_1",
      "type": "webhook",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Com Autenticação",
        "parameters": {
          "url": "https://api.exemplo.com/dados",
          "method": "GET",
          "headers": {
            "Authorization": "Bearer SEU_TOKEN_AQUI",
            "X-Custom-Header": "valor-customizado"
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Sucesso",
        "parameters": {
          "message": "Requisição autenticada executada!"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "webhook_1" },
    { "source": "webhook_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Headers customizados são enviados na requisição.

body (any, opcional)

O que é: Corpo da requisição (usado em POST, PUT, PATCH).

Flow completo para testar:

{
  "name": "Teste WEBHOOK - Body",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Pedir Nome",
        "parameters": {
          "message": "Qual seu nome?",
          "variable": "nome"
        }
      }
    },
    {
      "id": "webhook_1",
      "type": "webhook",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Enviar Dados",
        "parameters": {
          "url": "https://jsonplaceholder.typicode.com/posts",
          "method": "POST",
          "body": {
            "nome": "{{nome}}",
            "timestamp": "{{now}}",
            "origem": "Lumina Flow"
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "Dados enviados: {{nome}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "webhook_1" },
    { "source": "webhook_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Body com variáveis é serializado e enviado para API.

timeout (number, opcional)

O que é: Tempo máximo de espera pela resposta em milissegundos.

Padrão: 30000 (30 segundos)

Flow completo para testar:

{
  "name": "Teste WEBHOOK - Timeout",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "webhook_1",
      "type": "webhook",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Timeout Curto",
        "parameters": {
          "url": "https://jsonplaceholder.typicode.com/posts/1",
          "method": "GET",
          "timeout": 5000
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Sucesso",
        "parameters": {
          "message": "Respondeu em menos de 5 segundos!"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "webhook_1" },
    { "source": "webhook_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Se API demorar mais que timeout, dispara erro.

Parâmetros

Campo Tipo Obrigatório Descrição
url string Sim URL completa do endpoint
method string Não GET, POST, PUT, PATCH, DELETE (padrão: POST)
headers object Não Headers HTTP customizados
body any Não Corpo da requisição (para POST/PUT/PATCH)
timeout number Não Timeout em ms (padrão: 30000)

Exemplo 1: GET Simples

Objetivo: Buscar dados de uma API pública

JSON para Importar

{
  "name": "WEBHOOK - GET Simples",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "webhook_1",
      "type": "webhook",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Buscar Usuário",
        "parameters": {
          "url": "https://jsonplaceholder.typicode.com/users/1",
          "method": "GET"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Mostrar Nome",
        "parameters": {
          "message": "Nome: {{webhook_1.data.name}}\nEmail: {{webhook_1.data.email}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "webhook_1" },
    { "source": "webhook_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Nome: Leanne Graham
Email: Sincere@april.biz

Exemplo 2: POST com Autenticação

Objetivo: Criar recurso em API com autenticação Bearer

JSON para Importar

{
  "name": "WEBHOOK - POST Autenticado",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Pedir Título",
        "parameters": {
          "message": "Digite o título do post:",
          "variable": "titulo"
        }
      }
    },
    {
      "id": "input_2",
      "type": "input",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Pedir Conteúdo",
        "parameters": {
          "message": "Digite o conteúdo:",
          "variable": "conteudo"
        }
      }
    },
    {
      "id": "webhook_1",
      "type": "webhook",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Criar Post",
        "parameters": {
          "url": "https://jsonplaceholder.typicode.com/posts",
          "method": "POST",
          "headers": {
            "Authorization": "Bearer SEU_TOKEN",
            "Content-Type": "application/json"
          },
          "body": {
            "title": "{{titulo}}",
            "body": "{{conteudo}}",
            "userId": 1
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "Post criado com sucesso!\nID: {{webhook_1.data.id}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "input_2" },
    { "source": "input_2", "target": "webhook_1" },
    { "source": "webhook_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Digite o título do post:
Usuário: Meu primeiro post
Sistema: Digite o conteúdo:
Usuário: Este é o conteúdo do meu post
Sistema: Post criado com sucesso!
ID: 101

Exemplo 3: PUT para Atualizar

Objetivo: Atualizar recurso existente via PUT

JSON para Importar

{
  "name": "WEBHOOK - PUT Atualizar",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "webhook_1",
      "type": "webhook",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Atualizar Post",
        "parameters": {
          "url": "https://jsonplaceholder.typicode.com/posts/1",
          "method": "PUT",
          "body": {
            "id": 1,
            "title": "Título Atualizado",
            "body": "Conteúdo atualizado pelo Lumina",
            "userId": 1
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "Post atualizado!\nStatus: {{webhook_1.statusCode}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "webhook_1" },
    { "source": "webhook_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Post atualizado!
Status: 200

Resposta do Node

{
  "success": true,
  "action": "webhook_executed",
  "method": "POST",
  "url": "https://api.exemplo.com/endpoint",
  "statusCode": 200,
  "statusText": "OK",
  "headers": {
    "content-type": "application/json",
    "date": "Wed, 15 Jan 2025 10:30:00 GMT"
  },
  "data": {
    "id": 123,
    "message": "Success"
  },
  "timestamp": "2025-01-15T10:30:00.000Z"
}

Boas Práticas

SIM:

  • Use GET para buscar dados (não modifica)
  • Use POST para criar novos recursos
  • Use PUT para atualizar recursos completos
  • Use PATCH para atualizar parcialmente
  • Use DELETE para remover recursos
  • Defina timeout apropriado (APIs lentas = timeout maior)
  • Trate erros com node de erro/fallback
  • Use variáveis para URLs dinâmicas

NÃO:

  • Não exponha tokens/secrets diretamente no flow
  • Não use GET para operações que modificam dados
  • Não ignore status codes de erro (4xx, 5xx)
  • Não faça loops infinitos de webhooks
  • Não envie dados sensíveis sem HTTPS

Dicas

💡 Status Codes: 200-299 = sucesso, 400-499 = erro cliente, 500-599 = erro servidor

💡 Variáveis na URL: Use {{variavel}} para URLs dinâmicas

💡 Debug: Use https://webhook.site para testar e inspecionar requisições

💡 Timeout: APIs externas podem ser lentas, ajuste timeout conforme necessário

💡 Rate Limiting: Adicione DELAY entre webhooks para não exceder limites

Próximo Node

HTTP_REQUEST - Requisições HTTP avançadas → API - Gerenciador de APIs configuradas