This workflow corresponds to n8n.io template #11737 — we link there as the canonical source.
This workflow follows the HTTP Request → OpenAI 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 →
{
"id": "",
"meta": {
"templateCredsSetupCompleted": false
},
"name": "AI Vendor / Partner Proposal Evaluation & Auto-Response System",
"tags": [],
"nodes": [
{
"id": "a1480026-7111-4bc7-b172-0e0fb97c7057",
"name": "Parse PDF",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-976,
272
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1.1
},
{
"id": "83f555ac-2138-469f-b6bb-48c95a49bd2a",
"name": "Clean Text",
"type": "n8n-nodes-base.code",
"position": [
-768,
272
],
"parameters": {
"jsCode": "// Get the PDF text from previous node\nconst pdfText = $json[\"text\"];\n\n// Remove repeated document titles\nlet cleanText = pdfText.replace(/Process Design Document \u2013 Process Vendor Invoices for Vendor for ACME Systems Inc\\./g, '');\n\n// Remove multiple new lines\ncleanText = cleanText.replace(/\\n\\s*\\n/g, '\\n');\n\n// Optionally remove page numbers (lines with only digits)\ncleanText = cleanText.replace(/^\\d+\\s*$/gm, '');\n\n// Trim spaces\ncleanText = cleanText.trim();\n\nreturn [{ json: { cleanText } }];\n"
},
"typeVersion": 2
},
{
"id": "88f1fc3d-947c-4044-a77f-353abea0cd27",
"name": "Proposal Upload",
"type": "n8n-nodes-base.webhook",
"position": [
-1392,
272
],
"parameters": {
"path": "vendor-proposal-upload",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2.1
},
{
"id": "174016b9-e99e-46a5-913e-d122a4eb9ccb",
"name": "Download Proposal PDF",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1184,
272
],
"parameters": {
"url": "={{ $json.body.proposal_pdf }}",
"options": {
"response": {
"response": {
"responseFormat": "file",
"outputPropertyName": "=data"
}
}
}
},
"typeVersion": 4.3
},
{
"id": "70fb4320-855e-45a4-8f58-c69729c8f71a",
"name": "Proposal Evaluation",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-544,
272
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {
"temperature": 0.3
},
"responses": {
"values": [
{
"role": "system",
"content": "=You are an expert vendor proposal evaluator and business analyst. \nYour task is to process text extracted from vendor proposal PDFs and summarize it in a structured, JSON-safe format for automation workflows. \n\nRules:\n1. Output **strictly JSON**, no extra text.\n2. Keep all keys exactly as defined in the user prompt.\n3. If some information is missing, return an empty string or empty array.\n4. Ignore repeated headers, page numbers, or metadata.\n5. Extract only **relevant proposal content**.\n"
},
{
"content": "=Evaluate the following vendor proposal text. \nExtract key details, summarize, and highlight risks or missing info.\n\nText to evaluate:\n{{ $json.cleanText }}\n\nOutput JSON format (strictly):\n\n{\n \"vendor_name\": \"string\", // Name of the vendor\n \"category\": \"string\", // Category or domain\n \"summary\": \"string\", // 2-3 sentence summary of proposal\n \"key_points\": [\"string\"], // Key highlights, objectives, products, services\n \"risks_or_concerns\": [\"string\"] // Any risks, missing info, or concerns\n}\n"
}
]
},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "7ae3248a-c6b0-48f1-bbf1-19e231f45e2f",
"name": "Parse OpenAI JSON",
"type": "n8n-nodes-base.code",
"position": [
-192,
272
],
"parameters": {
"jsCode": "// 1. Extract the raw text from OpenAI output\nconst rawText =\n $json.output[0].content[0].text;\n\n// 2. Parse JSON safely\nlet proposal;\ntry {\n proposal = JSON.parse(rawText);\n} catch (e) {\n throw new Error(\"OpenAI output is not valid JSON\");\n}\n\n// 3. Compute risk flag (one PDF = one decision)\nconst risk_flagged =\n Array.isArray(proposal.risks_or_concerns) &&\n proposal.risks_or_concerns.length > 0;\n\n// 4. Return EXACTLY ONE ITEM\nreturn [\n {\n json: {\n vendor_name: proposal.vendor_name,\n category: proposal.category,\n summary: proposal.summary,\n key_points: proposal.key_points,\n risks_or_concerns: proposal.risks_or_concerns,\n risk_flagged\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "b38e23c4-d4e0-4ebe-9b3e-05dd13fbfa73",
"name": "Risks?",
"type": "n8n-nodes-base.if",
"position": [
64,
272
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "afcaba50-19b6-4dd1-ab43-57e05ee289da",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.risk_flagged }}",
"rightValue": true
},
{
"id": "1dc3473a-f9e8-4754-a754-aafe2e053eab",
"operator": {
"type": "boolean",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.risk_flagged }}",
"rightValue": false
}
]
}
},
"typeVersion": 2.3
},
{
"id": "8b03df41-51c4-4d6d-82a7-e4bd06821bed",
"name": "Build Risk Summary",
"type": "n8n-nodes-base.code",
"position": [
464,
128
],
"parameters": {
"jsCode": "const data = $json;\n\nreturn [{\n json: {\n title: `\u26a0\ufe0f Risks Identified in ${data.vendor_name} Proposal`,\n vendor: data.vendor_name,\n category: data.category,\n summary: data.summary,\n risk_count: data.risks_or_concerns.length,\n risks: data.risks_or_concerns.map((risk, i) => `${i + 1}. ${risk}`),\n action_required: \"Manual review required before approval\"\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "fc94e5da-e21f-49b1-971b-e652f85211be",
"name": "Auto Approve Payload",
"type": "n8n-nodes-base.code",
"position": [
464,
448
],
"parameters": {
"jsCode": "return [{\n json: {\n vendor_name: $json.vendor_name,\n status: \"APPROVED\",\n message: \"No risks found. Proposal approved.\"\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "3a0abd17-34ba-4475-8964-11ec2d55f04f",
"name": "SEND ALERT",
"type": "n8n-nodes-base.slack",
"position": [
688,
128
],
"parameters": {
"text": "={{$json.title}}\n\nVendor: {{$json.vendor}}\nCategory: {{$json.category}}\n\nRisks:\n{{ $json.risks.join(\"\\n\") }}\n\nAction: {{$json.action_required}}\n",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "YOUR_SLACK_CHANNEL_ID",
"cachedResultName": "YOUR_SLACK_CHANNEL_NAME"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "0ab39a67-0562-4f1f-9383-e9011587b9de",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
704,
448
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={\n \"status\": \"approved\",\n \"vendor\": \"{{$json.vendor_name}}\",\n \"message\": \"No risks found. Proposal approved.\"\n}\n"
},
"typeVersion": 1.5
},
{
"id": "4babda99-1556-46f7-a78e-bf34268c8570",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1792,
-448
],
"parameters": {
"width": 352,
"height": 896,
"content": "## **AI Vendor / Partner Proposal Evaluation & Auto-Response System**\n\n\nThis workflow automates the end-to-end evaluation of vendor or partner proposal PDFs using AI. It accepts a proposal upload via webhook, downloads the PDF, extracts and cleans the text, and then uses OpenAI to analyze the proposal for key details and potential risks.\n\nThe system ensures **one PDF = one decision**, preventing duplicate or fragmented outputs. Based on AI-detected risks, the workflow either flags the proposal for manual review with a Slack alert or automatically approves it and responds back to the requester.\n\n### How it works\n\n1. A vendor proposal PDF is submitted through a webhook.\n2. The PDF is downloaded and text is extracted.\n3. The extracted text is cleaned to remove noise like headers and page numbers.\n4. OpenAI evaluates the proposal and returns structured JSON.\n5. A single risk flag is calculated for the entire proposal.\n6. If risks exist, a Slack alert is sent.\n7. If no risks exist, the proposal is auto-approved and a response is returned.\n\n### Setup steps\n\n* Configure webhook URL for proposal uploads\n* Add OpenAI API credentials\n* Connect Slack credentials for alerts\n* Deploy webhook and test with a sample PDF\n\n\n\n"
},
"typeVersion": 1
},
{
"id": "0f9e10c0-6d04-4ad2-84f9-982d8d1af5ff",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1424,
144
],
"parameters": {
"color": 7,
"width": 592,
"height": 288,
"content": "## Proposal Intake & PDF Processing\n\nHandles proposal submission, PDF download, and text extraction.\nEnsures the uploaded document is accessible and converted into raw text for downstream AI analysis.\n\n"
},
"typeVersion": 1
},
{
"id": "7c6879ff-b3c7-474e-88a0-311a52713e43",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-800,
128
],
"parameters": {
"color": 7,
"width": 528,
"height": 288,
"content": "## Text Cleanup & AI Analysis\n\nCleans extracted PDF text and sends it to OpenAI for structured evaluation.\nRemoves noise and ensures AI receives only relevant proposal content.\n\n"
},
"typeVersion": 1
},
{
"id": "17c77980-2279-4fc2-a195-078f7b4d142e",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-256,
128
],
"parameters": {
"color": 7,
"width": 528,
"height": 288,
"content": "## Structured Output & Risk Detection\n\nParses OpenAI output into valid JSON and computes a single risk flag for the entire proposal.\nGuarantees one input PDF produces exactly one decision.\n\n"
},
"typeVersion": 1
},
{
"id": "9d8b765a-b93c-479d-b15e-10b90d6b6726",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
352,
16
],
"parameters": {
"color": 7,
"width": 544,
"height": 256,
"content": "## Risk Identified \u2192 Alert & Review\n\nBuilds a structured risk summary and notifies stakeholders via Slack.\nUsed when the proposal contains missing information or potential concerns.\n"
},
"typeVersion": 1
},
{
"id": "d44cc869-2c8e-4076-9bd6-bf258179081b",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
352,
320
],
"parameters": {
"color": 7,
"width": 544,
"height": 272,
"content": "## No Risk \u2192 Auto Approval\n\nAutomatically approves proposals with no detected risks and sends a success response back to the requester.\n\n"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "",
"connections": {
"Risks?": {
"main": [
[
{
"node": "Build Risk Summary",
"type": "main",
"index": 0
}
],
[
{
"node": "Auto Approve Payload",
"type": "main",
"index": 0
}
]
]
},
"Parse PDF": {
"main": [
[
{
"node": "Clean Text",
"type": "main",
"index": 0
}
]
]
},
"Clean Text": {
"main": [
[
{
"node": "Proposal Evaluation",
"type": "main",
"index": 0
}
]
]
},
"Proposal Upload": {
"main": [
[
{
"node": "Download Proposal PDF",
"type": "main",
"index": 0
}
]
]
},
"Parse OpenAI JSON": {
"main": [
[
{
"node": "Risks?",
"type": "main",
"index": 0
}
]
]
},
"Build Risk Summary": {
"main": [
[
{
"node": "SEND ALERT",
"type": "main",
"index": 0
}
]
]
},
"Proposal Evaluation": {
"main": [
[
{
"node": "Parse OpenAI JSON",
"type": "main",
"index": 0
}
]
]
},
"Auto Approve Payload": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Download Proposal PDF": {
"main": [
[
{
"node": "Parse PDF",
"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.
openAiApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automate vendor and partner proposal evaluation from slow, manual PDF reviews into a fast, consistent, and AI-powered decision workflow.
Source: https://n8n.io/workflows/11737/ — 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.
Venafi Presentation - Watch Video
Automatically detects missed Zoom demos booked via Calendly and triggers AI-powered follow-up sequences.
AI-Powered Fake Review Detection Workflow Using n8n & Airtable. Uses httpRequest, airtable, openAi, slack. Webhook trigger; 27 nodes.
This workflow automates the end-to-end process of scheduling technical or behavioral interviews. It captures interview data via Webhook, creates a Google Calendar event with an integrated Google Meet
This workflow automatically scores and categorizes new GoHighLevel contacts using AI (GPT-4), then tags and assigns them to the appropriate team member based on their score. Hot leads also trigger a S