{
  "id": "zewdHLI58e4MieOE",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Automate RFP Answers with OpenAI Assistants, Google Docs, Gmail and Slack",
  "tags": [],
  "nodes": [
    {
      "id": "01c725a6-9dab-4f19-a2c0-146204e61031",
      "name": "Get RFP Data",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1936,
        1440
      ],
      "parameters": {
        "options": {},
        "operation": "pdf"
      },
      "typeVersion": 1
    },
    {
      "id": "d2f7aa99-022a-4e2b-83bd-052bd6480be8",
      "name": "Item List Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserItemList",
      "position": [
        3072,
        1568
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "90f811aa-3cc9-4fd0-8b25-9d7197360f19",
      "name": "For Each Question...",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        3456,
        1408
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "19f5ef2b-d668-4ad2-a968-38c767746157",
      "name": "Set Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        2112,
        1440
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={\n \"doc_title\": \"{{ $('Wait for Request').item.json.body.title }}\",\n \"doc_filename\": \"{{ $('Wait for Request').item.json.body.id }} | {{ $('Wait for Request').item.json.body.title }} | {{ $now.format('yyyyMMddhhmmss') }}| RFP Response\",\n \"reply_to\": \"{{ $('Wait for Request').item.json.body.reply_to }}\"\n}\n"
      },
      "typeVersion": 3.3
    },
    {
      "id": "e385b913-6bc9-40ef-b222-20cbed4cbd84",
      "name": "Create new RFP Response Document",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        2320,
        1440
      ],
      "parameters": {
        "title": "={{ $json.doc_filename }}",
        "folderId": "=1y0I8MH32maIWCJh767mRE_NMHC6A3bUu"
      },
      "typeVersion": 2
    },
    {
      "id": "b73d36f4-dd79-4c92-8e60-b62fcb4cc2b2",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2896,
        1568
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "5e095a9e-a5af-44ae-a59a-e325a2ed5804",
      "name": "Send Chat Notification",
      "type": "n8n-nodes-base.slack",
      "position": [
        4736,
        1408
      ],
      "parameters": {
        "text": "=RFP document \"{{ $('Set Variables').item.json.title }}\" completed!",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "RFP-channel"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "ceb5e37d-1771-453f-b760-b8f5dcc4bce3",
      "name": "Send Email Notification",
      "type": "n8n-nodes-base.gmail",
      "position": [
        4544,
        1408
      ],
      "parameters": {
        "sendTo": "={{ $('Set Variables').item.json.reply_to }}",
        "message": "=Your RFP document \"{{ $('Set Variables').item.json.title }}\" is now complete!",
        "options": {},
        "subject": "=RFP Questionnaire \"{{ $('Set Variables').item.json.title }}\" Completed!",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "9269adf0-506d-448a-97b0-b067a3b19750",
      "name": "Add Metadata to Response Doc",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        2528,
        1440
      ],
      "parameters": {
        "actionsUi": {
          "actionFields": [
            {
              "text": "=Title: {{ $('Set Variables').item.json.doc_title }}\nDate generated: {{ $now.format(\"yyyy-MM-dd @ hh:mm\") }}\nRequested by: {{ $('Set Variables').item.json.reply_to }}\nExecution Id: http://localhost:5678/workflow/{{ $workflow.id }}/executions/{{ $execution.id }}\n\n---\n\n",
              "action": "insert"
            }
          ]
        },
        "operation": "update",
        "documentURL": "={{ $json.id }}"
      },
      "typeVersion": 2
    },
    {
      "id": "e9ff7b3d-2ad7-42e1-bc2b-b90dce8319ed",
      "name": "Record Question & Answer in Response Doc",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        4128,
        1520
      ],
      "parameters": {
        "actionsUi": {
          "actionFields": [
            {
              "text": "={{ $runIndex+1 }}. {{ $json.content }}\n{{ $json.output }}\n\n",
              "action": "insert"
            }
          ]
        },
        "operation": "update",
        "documentURL": "={{ $('Create new RFP Response Document').item.json.id }}"
      },
      "typeVersion": 2
    },
    {
      "id": "fc96dc9b-1ea3-485d-acb9-45d15b648148",
      "name": "Answer Question with Context",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        3808,
        1520
      ],
      "parameters": {
        "text": "={{ $json.response.text }}",
        "prompt": "define",
        "options": {},
        "resource": "assistant",
        "assistantId": {
          "__rl": true,
          "mode": "list",
          "value": "asst_QBI5lLKOsjktr3DRB4MwrgZd",
          "cachedResultName": "Nexus Digital Solutions Bot"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "36644f17-d1dc-44e8-b298-d3b37d6580b6",
      "name": "Wait for Request",
      "type": "n8n-nodes-base.webhook",
      "position": [
        1744,
        1440
      ],
      "parameters": {
        "path": "35e874df-2904-494e-a9f5-5a3f20f517f8",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "4bad5af5-f52b-4e10-ba21-fa0b0474ecfb",
      "name": "Extract Questions From RFP",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        2896,
        1408
      ],
      "parameters": {
        "text": "=You have been given a RFP document as part of a tender process of a buyer. Please extract all questions intended for the supplier. You must ensure the questions extracted are exactly has they are written in the RFP document.\n\n<RFP>{{ $('Get RFP Data').item.json.text }}<RFP>",
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.4
    },
    {
      "id": "b706f5ee-e845-4c7e-a647-5bb2b232106f",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1104,
        800
      ],
      "parameters": {
        "color": 7,
        "width": 520,
        "height": 1368,
        "content": "## Automate RFP Answers with OpenAI Assistants, Google Docs, Gmail and Slack\n\nAutomatically turns an incoming RFP PDF into a complete response document. Every extracted question is answered by a trained OpenAI Assistant, recorded into a Google Doc, and the finished document is delivered by email and Slack.\n\n**Perfect for:** Sales engineers, bid managers, and proposal teams who respond to RFPs and RFIs on a recurring basis.\n\n---\n\n## How it works\n\n1. **Wait for Request**: Receives the RFP submission (PDF, title, and reply to address) via webhook.\n2. **Get RFP Data**: Extracts the raw text from the uploaded RFP PDF.\n3. **Set Variables**: Builds the document title, filename, and reply to address from the webhook payload.\n4. **Create new RFP Response Document**: Creates a new Google Doc in the target Drive folder to hold the response.\n5. **Add Metadata to Response Doc**: Inserts a header block with title, generation date, requester, and execution link.\n6. **Extract Questions From RFP**: Reads the full RFP text and pulls out every question addressed to the supplier, using the *OpenAI Chat Model* for reasoning and the *Item List Output Parser* to return a clean list.\n7. **For Each Question...**: Loops through the extracted questions one at a time.\n8. **Answer Question with Context**: Sends each question to a pretrained OpenAI Assistant (\"Nexus Digital Solutions Bot\") that answers using the company's own knowledge.\n9. **Record Question & Answer in Response Doc**: Appends the numbered question and answer into the Google Doc, then loops back for the next question.\n10. **Send Email Notification**: Once every question is answered, emails the requester that the response document is ready. *(runs on loop completion)*\n11. **Send Chat Notification**: Posts a matching completion message to the RFP Slack channel.\n\n---\n\n## Setup (~10 minutes)\n\n1. **Webhook**: Note the generated URL on the *Wait for Request* node and point your RFP intake form or system to it.\n2. **Google Docs**: Connect your account in *Create new RFP Response Document* and *Add Metadata to Response Doc*, and set the target folder ID.\n3. **OpenAI**: Add your API key in *OpenAI Chat Model*, and set your own Assistant ID in *Answer Question with Context*.\n4. **Gmail**: Connect your account in *Send Email Notification*.\n5. **Slack**: Connect your account and set the target channel in *Send Chat Notification*.\n> The OpenAI Assistant used in *Answer Question with Context* must already be trained on your company's RFP knowledge; this workflow does not build that Assistant for you."
      },
      "typeVersion": 1
    },
    {
      "id": "efe41ae8-9fba-465f-8fe5-8a6184b28c28",
      "name": "Section 1 - Intake & Document Setup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1648,
        1184
      ],
      "parameters": {
        "color": 5,
        "width": 1073,
        "height": 518,
        "content": "## 1\ufe0f\u20e3 Intake & Document Setup\n\nThe **Wait for Request** webhook receives the incoming RFP along with its title and reply to address, and **Get RFP Data** pulls the raw text out of the attached PDF. **Set Variables** assembles the document title and filename, then **Create new RFP Response Document** and **Add Metadata to Response Doc** spin up a fresh Google Doc with a header block ready to receive answers."
      },
      "typeVersion": 1
    },
    {
      "id": "189033d0-aa77-4f69-ac23-13ab9749f3ca",
      "name": "Section 2 - Question Extraction",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2768,
        1184
      ],
      "parameters": {
        "color": 3,
        "width": 588,
        "height": 584,
        "content": "## 2\ufe0f\u20e3 Question Extraction\n\n**Extract Questions From RFP** reads the entire RFP text and identifies every question meant for the supplier, exactly as written. It relies on the **OpenAI Chat Model** for the reasoning and the **Item List Output Parser** to return the questions as a clean, structured list ready for looping."
      },
      "typeVersion": 1
    },
    {
      "id": "c681b8a9-3d50-45d0-8e04-03c5e1a23dc6",
      "name": "Section 3 - Answer Loop",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3408,
        1184
      ],
      "parameters": {
        "color": 6,
        "width": 968,
        "height": 608,
        "content": "## 3\ufe0f\u20e3 Answer Loop\n\n**For Each Question...** walks through the extracted list one item at a time. **Answer Question with Context** hands each question to a pretrained OpenAI Assistant that answers from the company's own knowledge, and **Record Question & Answer in Response Doc** writes the numbered question and answer straight into the Google Doc before the loop moves on."
      },
      "typeVersion": 1
    },
    {
      "id": "a59c3630-36ba-4ef4-8587-c3f03d9106b2",
      "name": "Section 4 - Completion & Notifications",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4416,
        1232
      ],
      "parameters": {
        "color": 4,
        "width": 592,
        "height": 376,
        "content": "## 4\ufe0f\u20e3 Completion & Notifications\n\nOnce the loop finishes, **Send Email Notification** emails the original requester that their RFP response is ready, and **Send Chat Notification** posts the same completion update to the team's RFP Slack channel."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "0580416c-49f3-4222-8a1b-2c2a7beb8d97",
  "nodeGroups": [],
  "connections": {
    "Get RFP Data": {
      "main": [
        [
          {
            "node": "Set Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Variables": {
      "main": [
        [
          {
            "node": "Create new RFP Response Document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Request": {
      "main": [
        [
          {
            "node": "Get RFP Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Extract Questions From RFP",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "For Each Question...": {
      "main": [
        [
          {
            "node": "Send Email Notification",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Answer Question with Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Item List Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Extract Questions From RFP",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Send Email Notification": {
      "main": [
        [
          {
            "node": "Send Chat Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Questions From RFP": {
      "main": [
        [
          {
            "node": "For Each Question...",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Metadata to Response Doc": {
      "main": [
        [
          {
            "node": "Extract Questions From RFP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Answer Question with Context": {
      "main": [
        [
          {
            "node": "Record Question & Answer in Response Doc",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create new RFP Response Document": {
      "main": [
        [
          {
            "node": "Add Metadata to Response Doc",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Record Question & Answer in Response Doc": {
      "main": [
        [
          {
            "node": "For Each Question...",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}