AutomationFlowsAI & RAG › Customer Embedding RAG Chat (webhook-based)

Customer Embedding RAG Chat (webhook-based)

Customer Embedding RAG Chat (Webhook-based). Uses httpRequest, postgres. Webhook trigger; 8 nodes.

Webhook trigger★★★★☆ complexity8 nodesHTTP RequestPostgres
AI & RAG Trigger: Webhook Nodes: 8 Complexity: ★★★★☆ Added:

This workflow follows the HTTP Request → Postgres 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 →

Download .json
{
  "name": "Customer Embedding RAG Chat (Webhook-based)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "customer-embedding-chat",
        "responseMode": "responseNode",
        "options": {
          "binaryPropertyName": "data"
        }
      },
      "id": "webhook-trigger",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Extract and validate chat input from webhook\nconst body = $json.body || $json;\nconst chatInput = body.chatInput || body.message;\nconst sessionId = body.sessionId || `session-${Date.now()}`;\nconst metadata = body.metadata || {};\n\n// Validate required fields\nif (!chatInput) {\n  throw new Error('chatInput is required');\n}\n\nif (!metadata.customerId) {\n  throw new Error('customerId is required in metadata');\n}\n\n// Extract customer information\nconst customerId = metadata.customerId;\nconst widgetId = metadata.widgetId || 'default';\nconst companyName = metadata.companyName || '';\n\n// Prepare for vector search\nreturn [{\n  json: {\n    chatInput,\n    sessionId,\n    customerId,\n    widgetId,\n    companyName,\n    metadata,\n    timestamp: new Date().toISOString(),\n    // Chat context for webhook response\n    isWebhookChat: true,\n    responseFormat: 'json'\n  }\n}];"
      },
      "id": "extract-webhook-data",
      "name": "Extract Webhook Data",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/embeddings",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "Bearer {{ $env.OPENAI_API_KEY }}"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "text-embedding-ada-002"
            },
            {
              "name": "input",
              "value": "={{ $json.chatInput }}"
            }
          ]
        },
        "options": {
          "timeout": 30000
        }
      },
      "id": "generate-query-embedding",
      "name": "Generate Query Embedding",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT * FROM search_customer_embeddings(\n  ARRAY{{ $json.data[0].embedding }}::vector(1536),\n  '{{ $('Extract Webhook Data').item(0).json.customerId }}',\n  0.7,\n  5\n);",
        "additionalFields": {}
      },
      "id": "vector-search",
      "name": "Vector Search Documents",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        900,
        300
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Build RAG context from search results\nconst searchResults = $json;\nconst chatData = $('Extract Webhook Data').item(0).json;\nconst embeddingData = $('Generate Query Embedding').item(0).json;\n\n// Process search results\nlet contextText = '';\nlet sourceCount = 0;\nlet hasRelevantContent = false;\n\nif (searchResults && Array.isArray(searchResults) && searchResults.length > 0) {\n  sourceCount = searchResults.length;\n  hasRelevantContent = true;\n  \n  // Build context from search results\n  const contexts = searchResults.map(result => {\n    const similarity = Math.round((result.similarity || 0) * 100);\n    return `[Kaynak ${similarity}% benzerlik]: ${result.content}`;\n  });\n  \n  contextText = contexts.join('\\n\\n');\n} else {\n  contextText = 'Belirli bir kaynak bulunamad\u0131. Genel bilgilerimle yan\u0131tlayaca\u011f\u0131m.';\n}\n\n// Prepare context for AI\nconst systemPrompt = `Sen ${chatData.companyName || '\u015firketin'} m\u00fc\u015fteri hizmetleri asistan\u0131s\u0131n. T\u00fcrk\u00e7e yan\u0131t ver.\n\nMevcut bilgiler:\n${contextText}\n\nKullan\u0131c\u0131 sorusu: ${chatData.chatInput}\n\nYan\u0131t\u0131n:\n- T\u00fcrk\u00e7e olmal\u0131\n- Dostane ve profesyonel ton kullan\n- Mevcut bilgilere dayal\u0131 yan\u0131t ver\n- E\u011fer bilgi yoksa, nazik\u00e7e belirt`;\n\nreturn [{\n  json: {\n    systemPrompt,\n    userQuery: chatData.chatInput,\n    contextText,\n    hasRelevantContent,\n    sourceCount,\n    searchResultCount: sourceCount,\n    customerId: chatData.customerId,\n    widgetId: chatData.widgetId,\n    sessionId: chatData.sessionId,\n    timestamp: chatData.timestamp,\n    tokensUsed: embeddingData.usage?.total_tokens || 0\n  }\n}];"
      },
      "id": "build-rag-context",
      "name": "Build RAG Context",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "Bearer {{ $env.OPENAI_API_KEY }}"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "gpt-3.5-turbo"
            },
            {
              "name": "messages",
              "value": "={{ [{ \"role\": \"system\", \"content\": $json.systemPrompt }] }}"
            },
            {
              "name": "max_tokens",
              "value": 500
            },
            {
              "name": "temperature",
              "value": 0.7
            }
          ]
        },
        "options": {
          "timeout": 60000
        }
      },
      "id": "generate-ai-response",
      "name": "Generate AI Response",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1340,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Format final webhook response\nconst aiResponse = $json;\nconst contextData = $('Build RAG Context').item(0).json;\nconst chatData = $('Extract Webhook Data').item(0).json;\n\n// Extract AI response text\nconst responseText = aiResponse.choices?.[0]?.message?.content || '\u00dczg\u00fcn\u00fcm, yan\u0131t olu\u015fturamad\u0131m.';\n\n// Generate follow-up prompts based on context\nconst followUpPrompts = [];\nif (contextData.hasRelevantContent) {\n  followUpPrompts.push(\n    'Bu konuda daha detayl\u0131 bilgi alabilir miyim?',\n    'Ba\u015fka hangi konularda yard\u0131mc\u0131 olabilirsiniz?',\n    'Bu bilgiyle ilgili \u00f6rnek verebilir misiniz?'\n  );\n} else {\n  followUpPrompts.push(\n    'Ba\u015fka bir konuda yard\u0131m edebilir misiniz?',\n    'Size hangi konularda soru sorabilirim?',\n    'Daha spesifik bir soru sorabilir miyim?'\n  );\n}\n\n// Prepare webhook response (ChatTrigger format compatible)\nconst webhookResponse = {\n  output: responseText,\n  followUpPrompts: followUpPrompts,\n  metadata: {\n    sessionId: chatData.sessionId,\n    customerId: chatData.customerId,\n    widgetId: chatData.widgetId,\n    hasRelevantContent: contextData.hasRelevantContent,\n    sourceCount: contextData.sourceCount,\n    responseTime: Date.now() - new Date(chatData.timestamp).getTime(),\n    tokensUsed: (contextData.tokensUsed || 0) + (aiResponse.usage?.total_tokens || 0),\n    timestamp: new Date().toISOString(),\n    // Webhook specific\n    responseType: 'webhook-chat',\n    success: true\n  }\n};\n\nreturn [{ json: webhookResponse }];"
      },
      "id": "format-webhook-response",
      "name": "Format Webhook Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1560,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}"
      },
      "id": "webhook-response",
      "name": "Webhook Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        1780,
        300
      ]
    }
  ],
  "connections": {
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Extract Webhook Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Webhook Data": {
      "main": [
        [
          {
            "node": "Generate Query Embedding",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Query Embedding": {
      "main": [
        [
          {
            "node": "Vector Search Documents",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Vector Search Documents": {
      "main": [
        [
          {
            "node": "Build RAG Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build RAG Context": {
      "main": [
        [
          {
            "node": "Generate AI Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate AI Response": {
      "main": [
        [
          {
            "node": "Format Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Webhook Response": {
      "main": [
        [
          {
            "node": "Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true
  },
  "staticData": {},
  "tags": [],
  "triggerCount": 1,
  "updatedAt": "2025-09-29T15:17:43.099Z",
  "versionId": "1.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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Customer Embedding RAG Chat (Webhook-based). Uses httpRequest, postgres. Webhook trigger; 8 nodes.

Source: https://github.com/botfusions/n8n-rag-chatbot/blob/4d40b60fe6cc672aae3d91444e1dd19556703a2a/webhook-customer-embedding-chat.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Chatbot-Query-Qdrant. Uses httpRequest, postgres. Webhook trigger; 7 nodes.

HTTP Request, Postgres
AI & RAG

Kreativ: RAG Ingestion Pipeline. Uses httpRequest, postgres. Webhook trigger; 5 nodes.

HTTP Request, Postgres
AI & RAG

Camila IA. Uses postgres, crypto, redis, agent. Webhook trigger; 92 nodes.

Postgres, Crypto, Redis +13
AI & RAG

HeyDinastia. Uses executeCommand, httpRequest, youTube, postgres. Webhook trigger; 66 nodes.

Execute Command, HTTP Request, YouTube +15
AI & RAG

Corvus 3.2 Beta. Uses httpRequest, agent, lmChatOpenAi, vectorStoreSupabase. Webhook trigger; 48 nodes.

HTTP Request, Agent, OpenAI Chat +5