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": "UFRO Orquestador PP3 Workflow - Corrected",
"nodes": [
{
"parameters": {
"path": "identify-and-answer",
"httpMethod": "POST",
"options": {
"allowedOrigins": "*"
}
},
"id": "webhook-trigger",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
100,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"rightValue": ""
},
"conditions": [
{
"id": "has-image",
"leftValue": "={{ $json.files && $json.files.image !== undefined }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"combineConditions": "any"
},
"id": "check-image",
"name": "Check Image",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
300,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ { error: 'No image provided', status: 400 } }}",
"responseCode": 400,
"options": {
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
}
},
"id": "error-no-image",
"name": "Error: No Image",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
500,
180
]
},
{
"parameters": {
"method": "POST",
"url": "http://54.205.31.20:5000/verify",
"sendBody": true,
"contentType": "form",
"bodyParameters": {
"parameters": [
{
"name": "image",
"value": "={{ $json.files.image.data }}"
}
]
},
"options": {
"timeout": 8000,
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "pp2-verification-1",
"name": "PP2-1 Verification",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
600,
200
]
},
{
"parameters": {
"method": "POST",
"url": "http://52.201.69.13:5000/verify",
"sendBody": true,
"contentType": "form",
"bodyParameters": {
"parameters": [
{
"name": "image",
"value": "={{ $json.files.image.data }}"
}
]
},
"options": {
"timeout": 8000,
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "pp2-verification-2",
"name": "PP2-2 Verification",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
600,
300
]
},
{
"parameters": {
"method": "POST",
"url": "http://example-pp2-3.com:5000/verify",
"sendBody": true,
"contentType": "form",
"bodyParameters": {
"parameters": [
{
"name": "image",
"value": "={{ $json.files.image.data }}"
}
]
},
"options": {
"timeout": 8000,
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "pp2-verification-3",
"name": "PP2-3 Verification",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
600,
400
]
},
{
"parameters": {
"mode": "combine",
"combineBy": "multiplex"
},
"id": "merge-pp2-results",
"name": "Merge PP2 Results",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [
800,
300
]
},
{
"parameters": {
"jsCode": "const THRESHOLD = 0.75;\nconst MARGIN = 0.2;\n\n// Procesar todos los resultados de PP2\nconst items = $input.all();\nconst allCandidates = [];\n\n// Extraer candidatos de todas las respuestas PP2\nitems.forEach((item, index) => {\n const data = item.json;\n if (data && !data.error) {\n if (data.candidates && Array.isArray(data.candidates)) {\n allCandidates.push(...data.candidates);\n } else if (data.name && data.score !== undefined) {\n // Formato directo\n allCandidates.push({ name: data.name, score: data.score, service: `PP2-${index+1}` });\n } else if (data.is_me === true && data.score) {\n // Otro formato posible\n allCandidates.push({ name: `User-${index+1}`, score: data.score, service: `PP2-${index+1}` });\n }\n }\n});\n\n// Agrupar por nombre y tomar el mejor score\nconst candidateMap = {};\nallCandidates.forEach(candidate => {\n const name = candidate.name;\n if (!candidateMap[name] || candidateMap[name].score < candidate.score) {\n candidateMap[name] = candidate;\n }\n});\n\nconst finalCandidates = Object.values(candidateMap).sort((a, b) => b.score - a.score);\n\n// Aplicar l\u00f3gica de fusi\u00f3n\nlet decision, identity, confidence;\n\nif (finalCandidates.length === 0) {\n decision = 'unknown';\n identity = null;\n confidence = 0;\n} else {\n const topCandidate = finalCandidates[0];\n const secondCandidate = finalCandidates[1];\n \n if (topCandidate.score >= THRESHOLD) {\n if (!secondCandidate || (topCandidate.score - secondCandidate.score) >= MARGIN) {\n decision = 'identified';\n identity = {\n name: topCandidate.name,\n score: topCandidate.score\n };\n confidence = topCandidate.score;\n } else {\n decision = 'ambiguous';\n identity = {\n name: topCandidate.name,\n score: topCandidate.score\n };\n confidence = topCandidate.score - (secondCandidate ? secondCandidate.score : 0);\n }\n } else {\n decision = 'unknown';\n identity = null;\n confidence = topCandidate.score;\n }\n}\n\n// Agregar informaci\u00f3n original de entrada para el siguiente nodo\nconst originalData = items[0] ? items[0].json : {};\n\nreturn {\n ...originalData,\n pp2_results: {\n decision: decision,\n identity: identity,\n candidates: finalCandidates.slice(0, 5),\n confidence: confidence,\n fusion_params: {\n threshold: THRESHOLD,\n margin: MARGIN\n },\n total_services: items.length,\n successful_services: items.filter(item => item.json && !item.json.error).length\n }\n};"
},
"id": "fusion-pp2",
"name": "Fusion PP2 Results",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1000,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"rightValue": ""
},
"conditions": [
{
"id": "has-question",
"leftValue": "={{ $json.query && $json.query.question && $json.query.question.trim() !== '' }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"combineConditions": "any"
},
"id": "check-question",
"name": "Check Question",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1200,
300
]
},
{
"parameters": {
"method": "POST",
"url": "http://52.201.69.13:5000/api/chat",
"sendBody": true,
"contentType": "json",
"body": "={{ JSON.stringify({ message: $json.query.question }) }}",
"options": {
"timeout": 15000,
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "pp1-normativa",
"name": "PP1 Normativa Query",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
1400,
250
]
},
{
"parameters": {
"mode": "append"
},
"id": "merge-final-results",
"name": "Merge Final Results",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [
1600,
300
]
},
{
"parameters": {
"jsCode": "const startTime = Date.now();\nconst items = $input.all();\n\n// El primer item tiene los resultados de PP2 fusion\nconst pp2Data = items[0] ? items[0].json : {};\nconst pp2Results = pp2Data.pp2_results || {};\n\n// El segundo item (si existe) tiene los resultados de PP1\nlet pp1Results = null;\nif (items.length > 1 && items[1] && items[1].json && items[1].json.result) {\n const pp1Data = items[1].json.result;\n pp1Results = {\n text: pp1Data.answer || 'No answer provided',\n citations: pp1Data.sources || [],\n confidence: pp1Data.metrics ? pp1Data.metrics.confidence : 0.8,\n provider: pp1Data.provider || 'unknown'\n };\n}\n\n// Construir respuesta final seg\u00fan especificaci\u00f3n PP3\nconst response = {\n request_id: Math.random().toString(36).substring(7),\n timestamp: new Date().toISOString(),\n decision: pp2Results.decision || 'unknown',\n identity: pp2Results.identity || null,\n candidates: pp2Results.candidates || [],\n normativa_answer: pp1Results,\n timing_ms: Date.now() - startTime,\n source: 'n8n-workflow',\n fusion_params: pp2Results.fusion_params || { threshold: 0.75, margin: 0.2 },\n pp2_summary: {\n queried: pp2Results.total_services || 0,\n successful: pp2Results.successful_services || 0,\n timeouts: (pp2Results.total_services || 0) - (pp2Results.successful_services || 0)\n },\n pp1_used: pp1Results !== null\n};\n\nreturn response;"
},
"id": "final-response",
"name": "Final Response Builder",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1800,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": {
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
]
}
}
},
"id": "webhook-response",
"name": "Webhook Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
2000,
300
]
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "Check Image",
"type": "main",
"index": 0
}
]
]
},
"Check Image": {
"main": [
[
{
"node": "PP2-1 Verification",
"type": "main",
"index": 0
},
{
"node": "PP2-2 Verification",
"type": "main",
"index": 0
},
{
"node": "PP2-3 Verification",
"type": "main",
"index": 0
}
],
[
{
"node": "Error: No Image",
"type": "main",
"index": 0
}
]
]
},
"PP2-1 Verification": {
"main": [
[
{
"node": "Merge PP2 Results",
"type": "main",
"index": 0
}
]
]
},
"PP2-2 Verification": {
"main": [
[
{
"node": "Merge PP2 Results",
"type": "main",
"index": 1
}
]
]
},
"PP2-3 Verification": {
"main": [
[
{
"node": "Merge PP2 Results",
"type": "main",
"index": 2
}
]
]
},
"Merge PP2 Results": {
"main": [
[
{
"node": "Fusion PP2 Results",
"type": "main",
"index": 0
}
]
]
},
"Fusion PP2 Results": {
"main": [
[
{
"node": "Check Question",
"type": "main",
"index": 0
}
]
]
},
"Check Question": {
"main": [
[
{
"node": "PP1 Normativa Query",
"type": "main",
"index": 0
}
],
[
{
"node": "Merge Final Results",
"type": "main",
"index": 0
}
]
]
},
"PP1 Normativa Query": {
"main": [
[
{
"node": "Merge Final Results",
"type": "main",
"index": 1
}
]
]
},
"Merge Final Results": {
"main": [
[
{
"node": "Final Response Builder",
"type": "main",
"index": 0
}
]
]
},
"Final Response Builder": {
"main": [
[
{
"node": "Webhook Response",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
{
"createdAt": "2025-11-29T00:00:00.000Z",
"updatedAt": "2025-11-29T00:00:00.000Z",
"id": "ufro-orquestador-v2",
"name": "UFRO Orquestador V2"
}
],
"triggerCount": 1,
"updatedAt": "2025-11-29T00:00:00.000Z",
"versionId": "2.0.0",
"meta": {
"description": "UFRO Orquestador PP3 Workflow - Fixed version with proper sequential flow and parallel PP2 calls",
"author": "UFRO Computer Science Department",
"created": "2025-11-29T00:00:00.000Z",
"version": "2.0.0",
"tags": [
"ufro",
"identity",
"normativa",
"pp2",
"pp1",
"orquestador",
"fixed"
]
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
UFRO Orquestador PP3 Workflow - Corrected. Uses httpRequest. Webhook trigger; 13 nodes.
Source: https://github.com/nonShade/orquestador-MCP/blob/ff8c2361acfda66656b0642e3a3c8ac8b1cc444e/n8n/pp3_workflow.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 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.
📡 This workflow serves as the central Alpha Vantage API fetcher for Tesla trading indicators, delivering cleaned 20-point JSON outputs for three timeframes: , , and . It is required by the following a