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": "main-orchestrator",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "resume-gen",
"responseMode": "responseNode",
"options": {
"binaryPropertyName": "resume"
}
},
"id": "orch-001",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "cond-is-pdf",
"leftValue": "={{ ($binary?.resume?.mimeType || $binary?.data?.mimeType || '').toLowerCase().includes('pdf') }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "orch-002",
"name": "Is PDF?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
480,
300
]
},
{
"parameters": {
"operation": "pdf",
"binaryPropertyName": "resume"
},
"id": "orch-003",
"name": "Extract from File",
"type": "n8n-nodes-base.extractFromFile",
"typeVersion": 1,
"position": [
720,
180
]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "const item = items[0];\nconst binaryKey = Object.keys(item.binary || {})[0] || 'resume';\nconst binData = item.binary?.[binaryKey];\nconst text = binData?.data ? Buffer.from(binData.data, 'base64').toString('utf-8') : '';\nreturn [{ json: { text, body: item.json.body || {} } }];\n"
},
"id": "orch-004",
"name": "Read TXT Binary",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
720,
420
]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "const item = items[0];\nconst resumeText = (item.json.text || item.json.body?.resume || '').trim();\nconst webhookBody = $('Webhook').item.json.body || {};\nconst jdUrl = (webhookBody.jd_url || '').trim();\nconst jdText = (webhookBody.jd_text || '').trim();\nif (!resumeText) throw new Error('No resume text extracted.');\nif (!jdUrl && !jdText) throw new Error('Provide jd_url or jd_text.');\nreturn [{ json: { resume_text: resumeText, jd_url: jdUrl, jd_text: jdText } }];\n"
},
"id": "orch-005",
"name": "Prepare Inputs",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
960,
300
]
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:5678/webhook/jd-scraper",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { url: $json.jd_url, text: $json.jd_text } }}",
"options": {
"timeout": 45000
}
},
"id": "orch-006",
"name": "Call JD Scraper",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
1200,
300
],
"continueOnFail": true
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:5678/webhook/resume-parser",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { resume_text: $('Prepare Inputs').item.json.resume_text } }}",
"options": {
"timeout": 60000
}
},
"id": "orch-007",
"name": "Call Resume Parser",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
1440,
300
],
"continueOnFail": true
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// Build the exact JSON body for AI tailoring engine\nconst jdResult = $('Call JD Scraper').item.json;\nconst resumeResult = items[0].json;\n\nlet jd = Array.isArray(jdResult) ? jdResult[0] : jdResult;\nlet resume = Array.isArray(resumeResult) ? resumeResult[0] : resumeResult;\n\nconst jdRaw = typeof jd.jd_raw === 'string' ? jd.jd_raw : JSON.stringify(jd.jd_raw || '');\nif (!jdRaw.trim()) throw new Error('JD Scraper returned empty.');\n\nconst resumeJson = {\n contact: resume.contact || {},\n summary: resume.summary || '',\n skills: resume.skills || [],\n experience: resume.experience || [],\n projects: resume.projects || [],\n education: resume.education || []\n};\n\n// Store the pre-built JSON string to avoid expression serialization issues\nreturn [{ json: {\n _aiBody: JSON.stringify({ resume_json: resumeJson, jd_raw: jdRaw }),\n _latexBody: null,\n resume_json: resumeJson,\n jd_raw: jdRaw\n} }];\n"
},
"id": "orch-008",
"name": "Merge for AI",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1680,
300
]
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:5678/webhook/ai-tailoring-engine",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ $json }}",
"options": {
"timeout": 120000
}
},
"id": "orch-009",
"name": "Call AI Tailoring Engine",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
1920,
300
],
"continueOnFail": true
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// Build latex body from AI tailoring result\nconst data = items[0].json;\nconst body = JSON.stringify({ tailored_resume: data.tailored_resume });\nreturn [{ json: { ...data, _latexBody: body } }];\n"
},
"id": "orch-010a",
"name": "Prep LaTeX Body",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2100,
300
]
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:5678/webhook/latex-generator",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ $json }}",
"options": {
"timeout": 150000
}
},
"id": "orch-010",
"name": "Call LaTeX Generator",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
2280,
300
],
"continueOnFail": true
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "const latex = items[0].json || {};\nconst ai = $('Call AI Tailoring Engine').item.json || {};\n\nreturn [{ json: {\n pdf_base64: latex.pdf_base64 ?? null,\n tex_source: latex.tex_source ?? '',\n ats_score: ai.ats_score ?? null,\n matched_keywords: ai.matched_keywords ?? [],\n compile_error: latex.compile_error ?? null,\n generated_at: new Date().toISOString(),\n status: latex.pdf_base64 ? 'success' : 'partial'\n} }];\n"
},
"id": "orch-011",
"name": "Build Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2460,
300
]
},
{
"parameters": {
"respondWith": "allIncomingItems",
"options": {
"responseHeaders": {
"entries": [
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
]
}
}
},
"id": "orch-012",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
2640,
300
]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Is PDF?",
"type": "main",
"index": 0
}
]
]
},
"Is PDF?": {
"main": [
[
{
"node": "Extract from File",
"type": "main",
"index": 0
}
],
[
{
"node": "Read TXT Binary",
"type": "main",
"index": 0
}
]
]
},
"Extract from File": {
"main": [
[
{
"node": "Prepare Inputs",
"type": "main",
"index": 0
}
]
]
},
"Read TXT Binary": {
"main": [
[
{
"node": "Prepare Inputs",
"type": "main",
"index": 0
}
]
]
},
"Prepare Inputs": {
"main": [
[
{
"node": "Call JD Scraper",
"type": "main",
"index": 0
}
]
]
},
"Call JD Scraper": {
"main": [
[
{
"node": "Call Resume Parser",
"type": "main",
"index": 0
}
]
]
},
"Call Resume Parser": {
"main": [
[
{
"node": "Merge for AI",
"type": "main",
"index": 0
}
]
]
},
"Merge for AI": {
"main": [
[
{
"node": "Call AI Tailoring Engine",
"type": "main",
"index": 0
}
]
]
},
"Call AI Tailoring Engine": {
"main": [
[
{
"node": "Prep LaTeX Body",
"type": "main",
"index": 0
}
]
]
},
"Prep LaTeX Body": {
"main": [
[
{
"node": "Call LaTeX Generator",
"type": "main",
"index": 0
}
]
]
},
"Call LaTeX Generator": {
"main": [
[
{
"node": "Build Response",
"type": "main",
"index": 0
}
]
]
},
"Build Response": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"id": 6,
"active": true
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Main Orchestrator. Uses httpRequest. Scheduled trigger; 5 nodes.
Source: https://github.com/MoYousif4387/job-search-ai-system/blob/c1d4ac0641f4571797ddc8a9c441e862aeffed36/n8n-workflows/main-orchestrator.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.
Birthday Automation - Production (Fixed). Uses stopAndError, httpRequest, emailSend, bannerbear. Scheduled trigger; 86 nodes.
This template runs two scheduled workflows to govern Microsoft Entra ID (Azure AD) guest accounts by detecting stale users via Microsoft Graph, staging deletions in SharePoint with a 72-hour window, n
Jira-Allure-Auto-Qa. Uses httpRequest, jira. Scheduled trigger; 68 nodes.
Spotify-Sync-Surrealdb-V1. Uses httpRequest, n8n-nodes-surrealdb, spotify. Scheduled trigger; 62 nodes.
As n8n instances scale, teams often lose track of sub-workflows—who uses them, where they are referenced, and whether they can be safely updated. This leads to inefficiencies like unnecessary copies o