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.
Inquiry-Agent. Uses @digitalocean/n8n-nodes-digitalocean-gradient-serverless-inference, stopAndError, googleDocs, gmail. Event-driven trigger; 88 nodes.
Alfred (funcional). Uses gmailTool, googleCalendarTool, gmail, embeddingsOpenAi. Event-driven trigger; 83 nodes.
Your AI workforce is ready. Are you?
Inquiry-Agent. Uses @digitalocean/n8n-nodes-digitalocean-gradient-serverless-inference, stopAndError, googleDocs, gmail. Event-driven trigger; 80 nodes.
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