This workflow corresponds to n8n.io template #14667 — we link there as the canonical source.
This workflow follows the Agent → Documentdefaultdataloader recipe pattern — see all workflows that pair these two integrations.
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 →
{
"meta": {
"templateId": "13868",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "1708dc60-dae0-4ee2-a628-b71d39d2f549",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
5216,
5120
],
"parameters": {
"color": 7,
"height": 304,
"content": "## Job tracking\n\nLogs the application's journey into Google Sheets."
},
"typeVersion": 1
},
{
"id": "f36c601d-2fdf-4933-b74f-ef5ac9262917",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"position": [
5488,
4784
],
"parameters": {
"color": 7,
"width": 976,
"height": 624,
"content": "## Final application steps\n\nConcludes the application by creating a cover letter and notifying HR via email and Telegram."
},
"typeVersion": 1
},
{
"id": "17a1f8ac-d2c0-4900-b954-79a386482a58",
"name": "Sticky Note11",
"type": "n8n-nodes-base.stickyNote",
"position": [
2480,
5040
],
"parameters": {
"color": 7,
"width": 1776,
"height": 832,
"content": "## Miscellaneous\n\nHandles default data loading, Google Drive operations and initial setups."
},
"typeVersion": 1
},
{
"id": "a2d6c794-af73-44b2-8a7b-364d75b40fb5",
"name": "Save Profile Vectors to Pinecone",
"type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
"position": [
2784,
5152
],
"parameters": {
"mode": "insert",
"options": {
"pineconeNamespace": "resume-profile"
},
"pineconeIndex": {
"__rl": true,
"mode": "list",
"value": "resume-profile",
"cachedResultName": "resume-profile"
}
},
"typeVersion": 1.3
},
{
"id": "65b39149-b06c-4af9-9771-cdc9f5b3921a",
"name": "Load Document Data",
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"position": [
2816,
5488
],
"parameters": {
"options": {},
"dataType": "binary",
"textSplittingMode": "custom"
},
"typeVersion": 1.1
},
{
"id": "ed9f59f6-3594-49c9-a15f-8e582d1536b6",
"name": "Download File from Google Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
2528,
5152
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "my_resume.docx"
},
"options": {},
"operation": "download"
},
"typeVersion": 3
},
{
"id": "ce6c0f00-2d9d-4efb-8b5f-95e280e9ac54",
"name": "Create OpenAI Embeddings",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
2544,
5520
],
"parameters": {
"options": {}
},
"typeVersion": 1.2
},
{
"id": "31b6a50f-9e31-499a-a95a-b041e9a364bf",
"name": "Recursive Text Splitter",
"type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
"position": [
2816,
5712
],
"parameters": {
"options": {}
},
"typeVersion": 1
},
{
"id": "3045acf9-12bc-4bcf-903e-2f40b4115031",
"name": "Telegram URL Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
1712,
4272
],
"parameters": {
"updates": "={{ [\"message\"] }}",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "f77ba42e-36d7-4e54-bbc1-8b88aa85920c",
"name": "Analyze URL Contents",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
2016,
4272
],
"parameters": {
"text": "={{ $json.message.text }}",
"options": {
"systemMessage": "You are a Telegram-based AI job assistant inside an n8n workflow.\n\nYour job:\n1. Understand the user's message\n2. Reply in a natural, helpful, human-readable way\n3. Extract a job link if present\n4. Normalize the link so it starts with https://\n5. Return structured JSON for workflow routing\n\nRules:\n- Always respond politely and clearly in reply_message\n- Detect whether the user has shared a job link\n- A valid job link contains a domain and may or may not start with http/https\n- If the link does not start with http/https, prepend https://\n- If multiple links exist, pick the most relevant one\n- If no link is found, return job_link as an empty string\n\nReturn STRICT JSON only in this format:\n{\n \"job_link\": \"<normalized_link_or_empty>\",\n \"has_job_link\": true,\n \"reply_message\": \"<short friendly response>\"\n}\n\nIf no valid job link is found, return:\n{\n \"job_link\": \"\",\n \"has_job_link\": false,\n \"reply_message\": \"Please send a job link you want me to analyze.\"\n}\n\nNever return anything outside JSON. Keep reply_message short and friendly. Do not hallucinate links."
},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "1f214203-a7e1-4b06-8ce7-a33aacf8f7d9",
"name": "Construct Input Variables",
"type": "n8n-nodes-base.code",
"position": [
2400,
4272
],
"parameters": {
"jsCode": "const raw = $json.output;\n\ntry {\n const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;\n return [{ json: parsed }];\n} catch (error) {\n return [{\n json: {\n job_link: '',\n has_job_link: false,\n reply_message: 'Please send a valid job link you want me to analyze.',\n parse_error: String(error),\n raw_output: raw\n }\n }];\n}"
},
"typeVersion": 2
},
{
"id": "bc8a4b21-960f-46c6-906c-10c4acee39a1",
"name": "Send URL Confirmation on Telegram",
"type": "n8n-nodes-base.telegram",
"position": [
2608,
4288
],
"parameters": {
"text": "={{ $json.reply_message }}",
"chatId": "={{ $('Telegram URL Trigger').item.json.message.chat.id }}",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "a928d625-c849-4198-a9c3-784d373acc20",
"name": "Switch by URL Validity",
"type": "n8n-nodes-base.switch",
"position": [
2832,
4288
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "bb058ba2-f2c5-4bd7-9f6f-573dff4124c2",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $('Construct Input Variables').item.json.has_job_link }}",
"rightValue": ""
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "3316095c-a975-4d19-9584-15391f03128e",
"name": "Extract Content with Apify",
"type": "@apify/n8n-nodes-apify.apify",
"position": [
3056,
4288
],
"parameters": {
"actorId": {
"__rl": true,
"mode": "id",
"value": "=apify~web-scraper"
},
"timeout": {},
"customBody": "={{ ({\n breakpointLocation: 'NONE',\n browserLog: false,\n closeCookieModals: false,\n debugLog: false,\n downloadCss: true,\n downloadMedia: true,\n excludes: [\n {\n glob: '/**/*.{png,jpg,jpeg,pdf}'\n }\n ],\n headless: true,\n ignoreCorsAndCsp: false,\n ignoreSslErrors: false,\n injectJQuery: true,\n keepUrlFragments: false,\n linkSelector: 'a[href]',\n pageFunction: `async function pageFunction(context) {\n const $ = context.jQuery;\n const pageTitle = $('title').first().text();\n const h1 = $('h1').first().text();\n const first_h2 = $('h2').first().text();\n const random_text_from_the_page = $('p').first().text();\n\n context.log.info('URL: ' + context.request.url + ', TITLE: ' + pageTitle);\n\n return {\n url: context.request.url,\n pageTitle,\n h1,\n first_h2,\n random_text_from_the_page\n };\n }`,\n postNavigationHooks: `[\n async (crawlingContext) => {\n },\n ]`,\n preNavigationHooks: `[\n async (crawlingContext, gotoOptions) => {\n },\n ]`,\n proxyConfiguration: {\n useApifyProxy: true\n },\n respectRobotsTxtFile: true,\n runMode: 'PRODUCTION',\n startUrls: [\n {\n url: $json.job_link\n }\n ],\n useChrome: false,\n waitUntil: ['networkidle2']\n }) }}",
"actorSource": "store",
"authentication": "apifyOAuth2Api"
},
"typeVersion": 1
},
{
"id": "f155a0a0-f367-44c0-aeca-740b406d0316",
"name": "Transform Job Data Format",
"type": "n8n-nodes-base.code",
"position": [
3552,
4288
],
"parameters": {
"jsCode": "const data = $json;\n\nfunction stringifyValue(value) {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (Array.isArray(value)) return value.map(stringifyValue).join('\\n');\n if (typeof value === 'object') {\n return Object.entries(value)\n .map(([k, v]) => `${k}: ${stringifyValue(v)}`)\n .join('\\n');\n }\n return '';\n}\n\nconst combinedText = Object.entries(data)\n .map(([key, value]) => `${key}: ${stringifyValue(value)}`)\n .join('\\n\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n\nreturn [\n {\n json: {\n source_url: data.url || '',\n source_title: data.title || '',\n unified_job_text: combinedText\n }\n }\n];"
},
"typeVersion": 2
},
{
"id": "639361bd-0f36-480d-a746-9d4f0338e643",
"name": "OpenAI URL Parsing Agent",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1984,
4544
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini"
},
"options": {},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "8595c1bc-4d88-4677-a33e-63cf8d829e4d",
"name": "Retrieve Job Content with Apify",
"type": "@apify/n8n-nodes-apify.apify",
"position": [
3328,
4288
],
"parameters": {
"offset": {},
"options": {},
"resource": "Datasets",
"datasetId": "={{ $json.defaultDatasetId }}",
"authentication": "apifyOAuth2Api"
},
"typeVersion": 1
},
{
"id": "13183ba7-0956-44ef-a079-ae4fbb5e0787",
"name": "Assess Job-Fit Suitability",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
3872,
4288
],
"parameters": {
"text": "={{ $json.unified_job_text }}",
"options": {
"systemMessage": "You are a job-fit evaluator.\n\nYou will be given:\n1. Relevant resume context retrieved from a vector database (Pinecone)\n2. A job description extracted from a web page\n\nYour task:\n- Analyze whether the candidate is a good fit for the job\n- Use only the provided resume context tool named Resume Info\n- Be practical and realistic, not overly strict\n\nDecision rules:\n- If fit_score is 70 or higher, the candidate is a good fit\n- If fit_score is below 70, the candidate is not a good fit\n\nReturn ONLY valid JSON in this exact format:\n{\n \"is_fit\": true,\n \"fit_score\": 0,\n \"job_role\": \"\",\n \"company\": \"\",\n \"main_reasons_for_fit\": [],\n \"main_reasons_not_fit\": [],\n \"short_user_message\": \"\",\n \"next_step\": \"ask_approval\"\n}\n\nField rules:\n- fit_score must be an integer from 0 to 100\n- job_role should be extracted from the job description\n- company should be extracted if possible, otherwise return an empty string\n- main_reasons_for_fit should contain up to 4 short bullet-style points\n- main_reasons_not_fit should contain up to 4 short bullet-style points\n- short_user_message should briefly explain the outcome\n- next_step must be ask_approval if is_fit is true, otherwise reject_job\n\nImportant:\n- Do not hallucinate experience\n- Do not assume skills not present in the resume context\n- Keep reasoning concise\n- Focus on skills, experience, and role alignment"
},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "2621f263-f57b-4dfa-887d-9f3294d02516",
"name": "Compile Fit Analysis Report",
"type": "n8n-nodes-base.code",
"position": [
4272,
4288
],
"parameters": {
"jsCode": "const raw = $json.output || $json.text || $json.response || $json;\n\nlet parsed = raw;\n\nif (typeof raw === 'string') {\n parsed = JSON.parse(raw);\n}\n\nif (raw?.content && typeof raw.content === 'string') {\n parsed = JSON.parse(raw.content);\n}\n\nreturn [\n {\n json: parsed\n }\n];"
},
"typeVersion": 2
},
{
"id": "eded179b-fcd7-4546-99d8-e13372513710",
"name": "Decide on Fit Status",
"type": "n8n-nodes-base.switch",
"position": [
4528,
4288
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d56d410f-3ce0-4347-b29a-960cecc99560",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.is_fit }}",
"rightValue": true
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "2d5ab9ad-de4a-47d5-ab88-242d9df5895d",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.is_fit }}",
"rightValue": ""
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "3abf291c-2986-4d06-aa51-d3b29fdcfe61",
"name": "Send Rejection Notice on Telegram",
"type": "n8n-nodes-base.telegram",
"position": [
4832,
4608
],
"parameters": {
"text": "={{ 'Your Fit Score for this job is ' + $('Compile Fit Analysis Report').item.json.fit_score + '\\n' + $json.short_user_message }}",
"chatId": "={{ $('Receive Job Input').item.json.message.chat.id }}",
"additionalFields": {}
},
"typeVersion": 1
},
{
"id": "60845d88-3a97-4c23-b4aa-e39d933158a9",
"name": "Seek Job Approval via Telegram",
"type": "n8n-nodes-base.telegram",
"position": [
4336,
4960
],
"parameters": {
"chatId": "={{ $('Receive Job Input').item.json.message.chat.id }}",
"message": "={{ 'Your job fit-score for this role is ' + $json.fit_score + '!\\n' + $json.short_user_message }}",
"options": {},
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double",
"disapproveLabel": "\u274c Skip"
}
}
},
"typeVersion": 1
},
{
"id": "5d8b9ce7-3ab6-404c-ad0a-838ee7ba05df",
"name": "Route by Approval Status",
"type": "n8n-nodes-base.switch",
"position": [
4720,
5280
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "f7357332-4534-46af-9d0d-1e334d27cec6",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": true
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "da35c172-e645-412b-9aa9-19bb5e47394a",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": ""
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "9e22d5ba-a6d7-4dbf-9411-e2838550337f",
"name": "Prepare Application Kit",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
4608,
5856
],
"parameters": {
"text": "={{ $('Normalize Job Data').item.json.unified_job_text }}",
"options": {
"systemMessage": "={{ `You are a job application assistant for an n8n workflow.\n\nYou will be given:\n1. Relevant resume context retrieved from Pinecone\n2. Job data collected from a careers page or scraper\n3. Basic job metadata\n\nYour task:\nGenerate application materials for this role using ONLY the provided resume context.\n\nReturn ONLY valid JSON in this exact format:\n{\n \"url\": \"\",\n \"company\": \"\",\n \"role\": \"\",\n \"location\": \"\",\n \"fit_score\": 0,\n \"approval_status\": \"approved\",\n \"candidate_name\": \"\",\n \"cover_letter\": \"\",\n \"hr_email_subject\": \"\",\n \"hr_email_body\": \"\",\n \"resume_improvement_suggestions\": [],\n \"user_message\": \"\"\n}\n\nField rules:\n- url: copy exactly from input\n- company: copy from input if provided, otherwise extract if clearly available, else empty string\n- role: copy from input if provided, otherwise extract if clearly available, else empty string\n- location: copy from input if provided, otherwise extract if clearly available, else empty string\n- fit_score: copy exactly from input\n- approval_status: always return \"approved\"\n- candidate_name: derive from the resume context if clearly available, otherwise use ${$('Receive Job Input').item.json.message.chat.first_name || ''} ${$('Receive Job Input').item.json.message.chat.last_name || ''}\n\nGeneration rules:\n- cover_letter: professional and concise, 220 to 300 words, tailored to the company and role\n- hr_email_subject: short and professional\n- hr_email_body: concise recruiter email mentioning interest and strongest fit\n- resume_improvement_suggestions: 4 to 6 short actionable bullet points focused on this job\n- user_message: short user update mentioning company, role, and generated materials\n\nImportant rules:\n- Use ONLY the provided resume context\n- Do NOT invent experience, skills, or names\n- Keep outputs clean and directly usable\n- Return only valid JSON\n\nInput fields:\nurl: ${$json.source_url || ''}\ncompany: ${$('Compile Fit Analysis Report').item.json.company || ''}\nrole: ${$('Compile Fit Analysis Report').item.json.job_role || ''}\nlocation: ${$json.location || ''}\nfit_score: ${$('Compile Fit Analysis Report').item.json.fit_score || 0}\n\nJob data:\n${$('Normalize Job Data').item.json.unified_job_text || ''}` }}"
},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "9ecbb3d0-ed4d-4c59-89d0-3ef19d195565",
"name": "Telegram Status Update",
"type": "n8n-nodes-base.telegram",
"position": [
4336,
5856
],
"parameters": {
"text": "Great \ud83d\udc4d Starting your application process for this role.\n\nI will now:\n- Create a tracker entry\n- Tailor your resume\n- Generate a cover letter\n- Draft an email for the recruiter\n\nI\u2019ll update you once everything is ready \ud83d\ude80",
"chatId": "={{ $('Receive Job Input').item.json.message.chat.id }}",
"additionalFields": {}
},
"typeVersion": 1
},
{
"id": "9c3c521b-a10f-4a9d-b48a-8bb765e6733e",
"name": "Create Material Summary Report",
"type": "n8n-nodes-base.code",
"position": [
5056,
5584
],
"parameters": {
"jsCode": "const raw = $json.output || $json.text || $json.response || $json;\n\nlet parsed = raw;\n\nif (typeof raw === 'string') {\n parsed = JSON.parse(raw);\n}\n\nif (raw?.content && typeof raw.content === 'string') {\n parsed = JSON.parse(raw.content);\n}\n\nreturn [\n {\n json: parsed\n }\n];"
},
"typeVersion": 2
},
{
"id": "82c5ac83-7ecc-4cd4-9c3e-3ee8ac9eb3ae",
"name": "Add Entry to Job Tracker Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
5264,
5248
],
"parameters": {
"columns": {
"value": {
"Role": "={{ $('Compile Fit Analysis Report').item.json.job_role }}",
"Company": "={{ $('Compile Fit Analysis Report').item.json.company }}",
"Job Url": "={{ $json.url }}",
"Location": "={{ $json.location }}",
"Fit Score": "={{ $('Compile Fit Analysis Report').item.json.fit_score }}",
"Approval Status": "={{ $json.approval_status }}",
"Resume Improvement Suggestions": "={{ $json.resume_improvement_suggestions }}"
},
"schema": [
{
"id": "Company",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Company",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Role",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Role",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Job Url",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Job Url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Location",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Fit Score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Fit Score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Approval Status",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Approval Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Resume Improvement Suggestions",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Resume Improvement Suggestions",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "",
"cachedResultName": "Jobs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "Application Tracker"
}
},
"typeVersion": 4.7
},
{
"id": "efd25510-24d3-4594-90d4-933a3f4c6ba1",
"name": "Draft Cover Letter in Google Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
5920,
5248
],
"parameters": {
"name": "cover_letter",
"content": "={{ $('Create Material Summary Report').item.json.cover_letter }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "Cover Letter"
},
"operation": "createFromText"
},
"typeVersion": 3
},
{
"id": "ab2d2a74-7b72-47a6-be39-b694263e868e",
"name": "Compose Email to HR",
"type": "n8n-nodes-base.gmail",
"position": [
6128,
5248
],
"parameters": {
"message": "={{ $('Create Material Summary Report').item.json.hr_email_body }}",
"options": {},
"subject": "={{ $('Create Material Summary Report').item.json.hr_email_subject }}",
"resource": "draft"
},
"typeVersion": 2.2
},
{
"id": "590c2238-4711-4513-bcda-672beefbb82d",
"name": "Telegram Final Job Notification",
"type": "n8n-nodes-base.telegram",
"position": [
6320,
5248
],
"parameters": {
"text": "={{ $('Create Material Summary Report').item.json.user_message }}",
"chatId": "={{ $('Receive Job Input').item.json.message.chat.id }}",
"additionalFields": {}
},
"typeVersion": 1
},
{
"id": "04edd03a-15f0-4086-9be6-6a54ff78d0f9",
"name": "Save Resume Data to Pinecone",
"type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
"position": [
4656,
6224
],
"parameters": {
"mode": "retrieve-as-tool",
"options": {
"pineconeNamespace": "resume-profile"
},
"pineconeIndex": {
"__rl": true,
"mode": "list",
"value": "resume-profile",
"cachedResultName": "resume-profile"
},
"toolDescription": "Work with the data in pinecone vector store to provide answer the the queries "
},
"typeVersion": 1.3
},
{
"id": "9bd8f59d-829b-49a7-b89a-7c2e72d10e51",
"name": "Generate Resume Embeddings",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
4112,
5680
],
"parameters": {
"options": {}
},
"typeVersion": 1.2
},
{
"id": "af7b2749-7b18-440c-9dd9-7d9bb52e6440",
"name": "Send Acknowledgment Message",
"type": "n8n-nodes-base.telegram",
"position": [
5536,
4896
],
"parameters": {
"text": "Noted, Please share another job link ",
"chatId": "={{ $('Receive Job Input').item.json.message.chat.id }}",
"additionalFields": {}
},
"typeVersion": 1
},
{
"id": "39e27186-adc2-40cb-8d83-7e0933ef44a0",
"name": "Produce Embeddings for Resume",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
4064,
5264
],
"parameters": {
"options": {}
},
"typeVersion": 1.2
},
{
"id": "b226ef66-b777-47b7-be60-4535d11dfa7e",
"name": "GPT-5 Chat for Compatibility",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
3856,
4528
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini"
},
"options": {},
"builtInTools": {}
},
"typeVersion": 1.3
},
{
"id": "738ae90a-e563-4114-bdc6-c7bc960760da",
"name": "GPT-5 Chat for Application Kit",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
4528,
6064
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini"
},
"options": {},
"builtInTools": {}
},
"typeVersion": 1.3
},
{
"id": "d6f74b0e-7e05-4510-b463-2cd872961592",
"name": "Save Detailed Resume to Pinecone",
"type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
"position": [
3936,
4656
],
"parameters": {
"mode": "retrieve-as-tool",
"options": {
"pineconeNamespace": "resume-profile"
},
"pineconeIndex": {
"__rl": true,
"mode": "list",
"value": "resume-profile",
"cachedResultName": "resume-profile"
},
"toolDescription": "Work with the data in vector store for analysing the query by the agent"
},
"typeVersion": 1.3
},
{
"id": "0574efd9-aa67-46e1-ac65-244badf40af8",
"name": "Sticky Note16",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
4144
],
"parameters": {
"width": 480,
"height": 1040,
"content": "# Job Application Automation Workflow\n\n## How it works\n\n1. The workflow is triggered when a user sends a job link via Telegram. \n2. An AI agent processes the message to extract and normalize the job URL. \n3. The system acknowledges the user and validates whether a valid job link was provided. \n4. If valid, the workflow scrapes the job page using Apify and extracts relevant job details. \n5. The scraped data is cleaned and standardized into a unified job description format. \n6. Another AI agent evaluates the candidate\u2019s fit for the job using resume data from a vector database. \n7. Based on the fit score: \n - If not a good fit \u2192 a rejection message is sent via Telegram \n - If a good fit \u2192 the user is asked for approval to proceed \n8. Upon approval: \n - Application materials (cover letter, email, etc.) are generated using AI \n - A job entry is added to Google Sheets (application tracker) \n - A cover letter file is created in Google Drive \n - A draft email to HR is generated in Gmail \n9. Finally, the user receives a Telegram update confirming completion of the process. \n\n---\n\n## Setup steps\n\n- [ ] Configure Telegram Bot API for receiving and sending messages \n- [ ] Set up OpenAI API credentials for AI agents and embeddings \n- [ ] Connect Apify for job page scraping \n- [ ] Configure Pinecone (or vector DB) for resume retrieval \n- [ ] Connect Google Sheets for application tracking \n- [ ] Set up Google Drive for file creation \n- [ ] Configure Gmail API for drafting recruiter emails \n\n---\n\n## Customization\n\n- Modify AI prompts to adjust job parsing, fit evaluation, and content generation \n- Customize fit score thresholds and decision logic \n- Adjust scraping logic based on different job platforms \n- Extend tracker fields in Google Sheets as needed \n- Personalize generated emails and cover letters "
},
"typeVersion": 1
},
{
"id": "d4b6bd64-cae6-4fdd-9d3a-e788ca612489",
"name": "Sticky Note29",
"type": "n8n-nodes-base.stickyNote",
"position": [
1664,
4144
],
"parameters": {
"color": 7,
"height": 304,
"content": "## Telegram URL reception\n\nTriggers when a URL is received via Telegram."
},
"typeVersion": 1
},
{
"id": "3dd8e5ec-4b58-4c03-b1f1-3335be7c4c82",
"name": "Sticky Note30",
"type": "n8n-nodes-base.stickyNote",
"position": [
1936,
4160
],
"parameters": {
"color": 7,
"width": 1040,
"height": 528,
"content": "## URL analysis and validation\n\nAI analyzes the URL to build and confirm job data inputs."
},
"typeVersion": 1
},
{
"id": "2917eef9-eba6-4a4b-a7b5-7a9b314f63c1",
"name": "Sticky Note31",
"type": "n8n-nodes-base.stickyNote",
"position": [
3008,
4160
],
"parameters": {
"color": 7,
"height": 304,
"content": "## Job data extraction\n\nExtracts job content if the URL is valid."
},
"typeVersion": 1
},
{
"id": "55754cd9-cf37-4feb-aeee-7ea0eea27ca4",
"name": "Sticky Note32",
"type": "n8n-nodes-base.stickyNote",
"position": [
3280,
4160
],
"parameters": {
"color": 7,
"width": 416,
"height": 304,
"content": "## Data formatting and evaluation\n\nFormats the extracted data and evaluates job compatibility using AI."
},
"typeVersion": 1
},
{
"id": "6b4849d6-55a5-4799-b947-aa2113e9798a",
"name": "Sticky Note33",
"type": "n8n-nodes-base.stickyNote",
"position": [
3808,
4176
],
"parameters": {
"color": 7,
"width": 608,
"height": 624,
"content": "## Job compatibility evaluation\n\nAI evaluates the job compatibility, generating a fit report."
},
"typeVersion": 1
},
{
"id": "46814b4d-0956-44c1-bda2-3d6fc530e4cc",
"name": "Sticky Note34",
"type": "n8n-nodes-base.stickyNote",
"position": [
4480,
4160
],
"parameters": {
"color": 7,
"width": 496,
"height": 624,
"content": "## Fit outcome determination\n\nDecides the outcome based on the fit report and notifies the rejection via Telegram."
},
"typeVersion": 1
},
{
"id": "326aeaba-cb33-4a00-af6f-aeb2fec8a259",
"name": "Sticky Note35",
"type": "n8n-nodes-base.stickyNote",
"position": [
4288,
4848
],
"parameters": {
"color": 7,
"width": 576,
"height": 592,
"content": "## Job approval process\n\nSends and directs approval requests based on evaluation."
},
"typeVersion": 1
},
{
"id": "94d99364-8ae2-4020-8a24-e33bf0176e42",
"name": "Sticky Note36",
"type": "n8n-nodes-base.stickyNote",
"position": [
4288,
5472
],
"parameters": {
"color": 7,
"width": 912,
"height": 896,
"content": "## Application material creation\n\nAI generates and manages application kits post-approval."
},
"typeVersion": 1
}
],
"connections": {
"Load Document Data": {
"ai_document": [
[
{
"node": "Save Profile Vectors to Pinecone",
"type": "ai_document",
"index": 0
}
]
]
},
"Compose Email to HR": {
"main": [
[
{
"node": "Telegram Final Job Notification",
"type": "main",
"index": 0
}
]
]
},
"Analyze URL Contents": {
"main": [
[
{
"node": "Construct Input Variables",
"type": "main",
"index": 0
}
]
]
},
"Decide on Fit Status": {
"main": [
[
{
"node": "Seek Job Approval via Telegram",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Rejection Notice on Telegram",
"type": "main",
"index": 0
}
]
]
},
"Telegram URL Trigger": {
"main": [
[
{
"node": "Analyze URL Contents",
"type": "main",
"index": 0
}
]
]
},
"Switch by URL Validity": {
"main": [
[
{
"node": "Extract Content with Apify",
"type": "main",
"index": 0
}
]
]
},
"Telegram Status Update": {
"main": [
[
{
"node": "Prepare Application Kit",
"type": "main",
"index": 0
}
]
]
},
"Prepare Application Kit": {
"main": [
[
{
"node": "Create Material Summary Report",
"type": "main",
"index": 0
}
]
]
},
"Recursive Text Splitter": {
"ai_textSplitter": [
[
{
"node": "Load Document Data",
"type": "ai_textSplitter",
"index": 0
}
]
]
},
"Create OpenAI Embeddings": {
"ai_embedding": [
[
{
"node": "Save Profile Vectors to Pinecone",
"type": "ai_embedding",
"index": 0
}
]
]
},
"OpenAI URL Parsing Agent": {
"ai_languageModel": [
[
{
"node": "Analyze URL Contents",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Route by Approval Status": {
"main": [
[
{
"node": "Telegram Status Update",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Acknowledgment Message",
"type": "main",
"index": 0
}
]
]
},
"Construct Input Variables": {
"main": [
[
{
"node": "Send URL Confirmation on Telegram",
"type": "main",
"index": 0
}
]
]
},
"Transform Job Data Format": {
"main": [
[
{
"node": "Assess Job-Fit Suitability",
"type": "main",
"index": 0
}
]
]
},
"Assess Job-Fit Suitability": {
"main": [
[
{
"node": "Compile Fit Analysis Report",
"type": "main",
"index": 0
}
]
]
},
"Extract Content with Apify": {
"main": [
[
{
"node": "Retrieve Job Content with Apify",
"type": "main",
"index": 0
}
]
]
},
"Generate Resume Embeddings": {
"ai_embedding": [
[
{
"node": "Save Resume Data to Pinecone",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Compile Fit Analysis Report": {
"main": [
[
{
"node": "Decide on Fit Status",
"type": "main",
"index": 0
}
]
]
},
"GPT-5 Chat for Compatibility": {
"ai_languageModel": [
[
{
"node": "Assess Job-Fit Suitability",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Save Resume Data to Pinecone": {
"ai_tool": [
[
{
"node": "Prepare Application Kit",
"type": "ai_tool",
"index": 0
}
]
]
},
"Produce Embeddings for Resume": {
"ai_embedding": [
[
{
"node": "Save Detailed Resume to Pinecone",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Create Material Summary Report": {
"main": [
[
{
"node": "Add Entry to Job Tracker Sheets",
"type": "main",
"index": 0
}
]
]
},
"GPT-5 Chat for Application Kit": {
"ai_languageModel": [
[
{
"node": "Prepare Application Kit",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Seek Job Approval via Telegram": {
"main": [
[
{
"node": "Route by Approval Status",
"type": "main",
"index": 0
}
]
]
},
"Add Entry to Job Tracker Sheets": {
"main": [
[
{
"node": "Draft Cover Letter in Google Drive",
"type": "main",
"index": 0
}
]
]
},
"Download File from Google Drive": {
"main": [
[
{
"node": "Save Profile Vectors to Pinecone",
"type": "main",
"index": 0
}
]
]
},
"Retrieve Job Content with Apify": {
"main": [
[
{
"node": "Transform Job Data Format",
"type": "main",
"index": 0
}
]
]
},
"Save Detailed Resume to Pinecone": {
"ai_tool": [
[
{
"node": "Assess Job-Fit Suitability",
"type": "ai_tool",
"index": 0
}
]
]
},
"Send URL Confirmation on Telegram": {
"main": [
[
{
"node": "Switch by URL Validity",
"type": "main",
"index": 0
}
]
]
},
"Draft Cover Letter in Google Drive": {
"main": [
[
{
"node": "Compose Email to HR",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
openAiApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automates the early-stage job application process using AI.
Source: https://n8n.io/workflows/14667/ — 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.
Your AI workforce is ready. Are you?
This comprehensive workflow bundle is designed as a powerful starter kit, enabling you to build a multi-functional AI assistant on Telegram. It seamlessly integrates AI-powered voice interactions, an
This intelligent chatbot leverages cutting-edge financial APIs and AI-driven analysis to deliver comprehensive stock research reports. Get instant access to professional-grade investment analysis that
This advanced n8n workflow automates the full lead enrichment, qualification, and personalized outreach process tailored specifically for the B2B real estate sector. Integrating top platforms like Api
This n8n template automatically classifies incoming emails (Sales, Support, Internal, Finance, Promotions) and routes them to a dedicated OpenAI LLM Agent for processing. Depending on the category, th