The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "System :: Flow Runner",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "system/flows/run",
"responseMode": "responseNode",
"options": {
"rawBody": true
}
},
"id": "webhook-trigger",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
250,
300
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.KEYCLOAK_TOKEN_URL || 'https://keycloak.callback-local-cchagas.xyz/realms/assistenteexecutivo/protocol/openid-connect/token' }}",
"authentication": "none",
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "grant_type",
"value": "client_credentials"
},
{
"name": "client_id",
"value": "={{ $env.KEYCLOAK_CLIENT_ID || 'assistente-api' }}"
},
{
"name": "client_secret",
"value": "={{ $env.KEYCLOAK_CLIENT_SECRET }}"
}
]
},
"options": {}
},
"id": "get-token",
"name": "Get OAuth Token",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
470,
300
]
},
{
"parameters": {
"jsCode": "// Validate and normalize input\nconst webhookData = $('Webhook Trigger').item.json;\nconst tokenData = $('Get OAuth Token').item.json;\nconst input = webhookData;\n\n// Generate run ID\nconst runId = input.runId || `run_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n// Extract fields\nconst workflowId = input.workflowId;\nconst specId = input.specId;\nconst specVersion = input.specVersion;\nconst inputs = input.inputs || {};\nconst tenantId = input.tenantId || 'default';\nconst requestedBy = input.requestedBy || 'system';\nconst idempotencyKey = input.idempotencyKey || runId;\nconst waitForCompletion = input.waitForCompletion !== false; // default true\nconst timeoutSeconds = input.timeoutSeconds || 300; // 5 minutes default\n\n// Validation\nif (!workflowId && !specId) {\n throw new Error('Either workflowId or specId is required');\n}\n\nreturn {\n runId,\n workflowId,\n specId,\n specVersion,\n inputs,\n tenantId,\n requestedBy,\n idempotencyKey,\n waitForCompletion,\n timeoutSeconds,\n startedAt: new Date().toISOString(),\n accessToken: tokenData.access_token\n};"
},
"id": "validate-input",
"name": "Validate Input",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
470,
300
]
},
{
"parameters": {
"method": "GET",
"url": "={{ $env.API_BASE_URL }}/api/workflows/runs/check?idempotencyKey={{ $json.idempotencyKey }}",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $json.accessToken }}"
}
]
},
"options": {
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "check-idempotency",
"name": "Check Idempotency",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
690,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": ""
},
"conditions": [
{
"leftValue": "={{ $json.exists }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
}
},
"id": "if-already-executed",
"name": "Already Executed?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
910,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": true,\n \"cached\": true,\n \"runId\": \"{{ $('Check Idempotency').item.json.runId }}\",\n \"executionId\": \"{{ $('Check Idempotency').item.json.executionId }}\",\n \"status\": \"{{ $('Check Idempotency').item.json.status }}\",\n \"result\": {{ JSON.stringify($('Check Idempotency').item.json.result) }}\n}",
"options": {}
},
"id": "respond-cached",
"name": "Respond Cached",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
1130,
150
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": ""
},
"conditions": [
{
"leftValue": "={{ $('Validate Input').item.json.workflowId }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty"
}
}
],
"combinator": "and"
}
},
"id": "has-workflow-id",
"name": "Has Workflow ID?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1130,
400
]
},
{
"parameters": {
"method": "GET",
"url": "={{ $env.API_BASE_URL }}/api/workflows/specs/{{ $('Validate Input').item.json.specId }}/resolve?version={{ $('Validate Input').item.json.specVersion || 'latest' }}",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('Validate Input').item.json.accessToken }}"
}
]
},
"options": {}
},
"id": "resolve-spec",
"name": "Resolve Spec to Workflow",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1350,
550
]
},
{
"parameters": {
"jsCode": "// Merge workflow ID from different sources\nconst validateInput = $('Validate Input').item.json;\nconst hasWorkflowId = $('Has Workflow ID?').item.json;\n\nlet workflowId;\nlet resolvedFrom;\n\n// Check which branch we came from\ntry {\n const resolveSpec = $('Resolve Spec to Workflow').item?.json;\n if (resolveSpec && resolveSpec.n8nWorkflowId) {\n workflowId = resolveSpec.n8nWorkflowId;\n resolvedFrom = 'spec';\n }\n} catch (e) {\n // Came from the other branch\n}\n\nif (!workflowId) {\n workflowId = validateInput.workflowId;\n resolvedFrom = 'direct';\n}\n\nif (!workflowId) {\n throw new Error('Could not resolve workflow ID');\n}\n\nreturn {\n ...validateInput,\n workflowId,\n resolvedFrom\n};"
},
"id": "merge-workflow-id",
"name": "Merge Workflow ID",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1570,
400
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.API_BASE_URL }}/api/workflows/runs",
"authentication": "none",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"runId\": \"{{ $json.runId }}\",\n \"workflowId\": \"{{ $json.workflowId }}\",\n \"tenantId\": \"{{ $json.tenantId }}\",\n \"requestedBy\": \"{{ $json.requestedBy }}\",\n \"idempotencyKey\": \"{{ $json.idempotencyKey }}\",\n \"inputs\": {{ JSON.stringify($json.inputs) }},\n \"startedAt\": \"{{ $json.startedAt }}\",\n \"status\": \"Running\"\n}",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $json.accessToken }}"
}
]
}
},
"id": "register-run",
"name": "Register Run",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1790,
400
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.N8N_API_URL }}/api/v1/workflows/{{ $('Merge Workflow ID').item.json.workflowId }}/execute",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify($('Merge Workflow ID').item.json.inputs) }}",
"options": {}
},
"id": "execute-workflow",
"name": "Execute Target Workflow",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2010,
400
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": ""
},
"conditions": [
{
"leftValue": "={{ $('Merge Workflow ID').item.json.waitForCompletion }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
}
},
"id": "should-wait",
"name": "Wait for Completion?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
2230,
400
]
},
{
"parameters": {
"jsCode": "// Poll for execution status\nconst executionId = $('Execute Target Workflow').item.json.id;\nconst timeoutSeconds = $('Merge Workflow ID').item.json.timeoutSeconds;\nconst maxIterations = Math.ceil(timeoutSeconds / 2); // Poll every 2 seconds\n\nlet iteration = 0;\nlet status = 'running';\nlet result = null;\nlet error = null;\n\nwhile (iteration < maxIterations && status === 'running') {\n // Wait 2 seconds\n await new Promise(resolve => setTimeout(resolve, 2000));\n \n // Check status via n8n API\n const response = await this.helpers.httpRequest({\n method: 'GET',\n url: `${$env.N8N_API_URL}/api/v1/executions/${executionId}`,\n headers: {\n 'X-N8N-API-KEY': $env.N8N_API_KEY\n }\n });\n \n if (response.finished) {\n if (response.stoppedAt) {\n status = response.data?.resultData?.error ? 'failed' : 'success';\n result = response.data?.resultData?.lastNodeExecuted;\n error = response.data?.resultData?.error;\n }\n }\n \n iteration++;\n}\n\nif (status === 'running') {\n status = 'timeout';\n}\n\nreturn {\n executionId,\n status,\n result,\n error,\n iterations: iteration,\n finishedAt: new Date().toISOString()\n};"
},
"id": "poll-status",
"name": "Poll Execution Status",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2450,
300
]
},
{
"parameters": {
"method": "PUT",
"url": "={{ $env.API_BASE_URL }}/api/workflows/runs/{{ $('Register Run').item.json.runId }}",
"authentication": "none",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"n8nExecutionId\": \"{{ $('Execute Target Workflow').item.json.id }}\",\n \"status\": \"{{ $json.status }}\",\n \"result\": {{ JSON.stringify($json.result) }},\n \"error\": {{ JSON.stringify($json.error) }},\n \"finishedAt\": \"{{ $json.finishedAt }}\"\n}",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('Merge Workflow ID').item.json.accessToken }}"
}
]
}
},
"id": "update-run-completed",
"name": "Update Run (Completed)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2670,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": {{ $('Poll Execution Status').item.json.status === 'success' }},\n \"runId\": \"{{ $('Merge Workflow ID').item.json.runId }}\",\n \"executionId\": \"{{ $('Execute Target Workflow').item.json.id }}\",\n \"status\": \"{{ $('Poll Execution Status').item.json.status }}\",\n \"result\": {{ JSON.stringify($('Poll Execution Status').item.json.result) }},\n \"error\": {{ JSON.stringify($('Poll Execution Status').item.json.error) }},\n \"startedAt\": \"{{ $('Merge Workflow ID').item.json.startedAt }}\",\n \"finishedAt\": \"{{ $('Poll Execution Status').item.json.finishedAt }}\"\n}",
"options": {}
},
"id": "respond-completed",
"name": "Respond Completed",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
2890,
300
]
},
{
"parameters": {
"method": "PUT",
"url": "={{ $env.API_BASE_URL }}/api/workflows/runs/{{ $('Register Run').item.json.runId }}",
"authentication": "none",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"n8nExecutionId\": \"{{ $('Execute Target Workflow').item.json.id }}\",\n \"status\": \"Accepted\"\n}",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('Merge Workflow ID').item.json.accessToken }}"
}
]
}
},
"id": "update-run-async",
"name": "Update Run (Async)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2450,
550
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": true,\n \"async\": true,\n \"runId\": \"{{ $('Merge Workflow ID').item.json.runId }}\",\n \"executionId\": \"{{ $('Execute Target Workflow').item.json.id }}\",\n \"status\": \"Accepted\",\n \"message\": \"Workflow execution started. Poll /api/workflows/runs/{{ $('Merge Workflow ID').item.json.runId }} for status.\",\n \"startedAt\": \"{{ $('Merge Workflow ID').item.json.startedAt }}\"\n}",
"options": {
"responseCode": 202
}
},
"id": "respond-async",
"name": "Respond Async",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
2670,
550
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": false,\n \"error\": \"{{ $json.message || 'Execution failed' }}\",\n \"runId\": \"{{ $('Merge Workflow ID').item.json.runId || 'unknown' }}\"\n}",
"options": {
"responseCode": 500
}
},
"id": "respond-error",
"name": "Respond Error",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
2010,
600
]
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "Get OAuth Token",
"type": "main",
"index": 0
}
]
]
},
"Get OAuth Token": {
"main": [
[
{
"node": "Validate Input",
"type": "main",
"index": 0
}
]
]
},
"Validate Input": {
"main": [
[
{
"node": "Check Idempotency",
"type": "main",
"index": 0
}
]
]
},
"Check Idempotency": {
"main": [
[
{
"node": "Already Executed?",
"type": "main",
"index": 0
}
]
]
},
"Already Executed?": {
"main": [
[
{
"node": "Respond Cached",
"type": "main",
"index": 0
}
],
[
{
"node": "Has Workflow ID?",
"type": "main",
"index": 0
}
]
]
},
"Has Workflow ID?": {
"main": [
[
{
"node": "Merge Workflow ID",
"type": "main",
"index": 0
}
],
[
{
"node": "Resolve Spec to Workflow",
"type": "main",
"index": 0
}
]
]
},
"Resolve Spec to Workflow": {
"main": [
[
{
"node": "Merge Workflow ID",
"type": "main",
"index": 0
}
]
]
},
"Merge Workflow ID": {
"main": [
[
{
"node": "Register Run",
"type": "main",
"index": 0
}
]
]
},
"Register Run": {
"main": [
[
{
"node": "Execute Target Workflow",
"type": "main",
"index": 0
}
]
]
},
"Execute Target Workflow": {
"main": [
[
{
"node": "Wait for Completion?",
"type": "main",
"index": 0
}
]
]
},
"Wait for Completion?": {
"main": [
[
{
"node": "Poll Execution Status",
"type": "main",
"index": 0
}
],
[
{
"node": "Update Run (Async)",
"type": "main",
"index": 0
}
]
]
},
"Poll Execution Status": {
"main": [
[
{
"node": "Update Run (Completed)",
"type": "main",
"index": 0
}
]
]
},
"Update Run (Completed)": {
"main": [
[
{
"node": "Respond Completed",
"type": "main",
"index": 0
}
]
]
},
"Update Run (Async)": {
"main": [
[
{
"node": "Respond Async",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"errorWorkflow": ""
},
"staticData": null,
"tags": [
{
"name": "system"
},
{
"name": "flow-runner"
}
]
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
httpHeaderAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
System :: Flow Runner. Uses httpRequest. Webhook trigger; 18 nodes.
Source: https://github.com/caiohomem/assistente/blob/67e7dba4370d71d1ca874da0957c0f4d27946ee6/n8n-workflows/flow-runner.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia
This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c
Sign PDF documents with legally-compliant digital signatures using X.509 certificates. Supports multiple PAdES signature levels (B, T, LT, LTA) with optional visible stamps.