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:
- Integração universal: Conectar com qualquer API REST que não tenha node dedicado
- Flexibilidade total: Suporte a todos os métodos HTTP (GET, POST, PUT, PATCH, DELETE)
- Customização completa: Controle de headers, body, timeout e autenticação
- Notificações: Enviar eventos para sistemas externos em tempo real
- Automação: Disparar ações em outros sistemas baseado no flow
Como funciona internamente?
Quando o WEBHOOK é executado, o sistema:
- Valida URL: Verifica se a URL foi fornecida
- Prepara configuração: Define método, headers, body e timeout
- Configura headers: Adiciona Content-Type e headers customizados
- Inclui body: Se método for POST/PUT/PATCH, serializa o body
- Executa requisição: Faz chamada HTTP para URL externa
- Retorna resposta: Status code, headers e dados da resposta
- 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
- Enviar notificação: Disparar evento para sistema de notificações
- Integrar CRM: Criar/atualizar leads em sistemas não suportados
- Webhooks externos: Notificar serviços de eventos do flow
- APIs REST customizadas: Chamar APIs internas da sua empresa
- 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