AutomationFlowsAI & RAG › Triage Tickets by Ranking Next Actions with Vectorprime via Webhook

Triage Tickets by Ranking Next Actions with Vectorprime via Webhook

ByFaisal Khan @vectorprime on n8n.io

Ranks “best next actions” for an incoming ticket/incident using the VectorPrime Decision Kernel (deterministic + auditable), then returns a clean JSON result you can route to Slack, a backlog tool, or email.

Webhook trigger★★★★☆ complexity20 nodesHTTP Request
AI & RAG Trigger: Webhook Nodes: 20 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #12962 — we link there as the canonical source.

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
{
  "nodes": [
    {
      "id": "d6a74e08-2432-47ee-895b-76c58b4e81a1",
      "name": "Normalize + Build Options",
      "type": "n8n-nodes-base.code",
      "position": [
        -1232,
        -144
      ],
      "parameters": {
        "jsCode": "// Normalize + Build Options (must return 1 item)\n\nconst raw = $json?.body ?? $json ?? {};\n\n// Accept either direct VP payload OR simple webhook payload\nconst decision_id = raw.decision_id ?? raw.decisionId ?? raw.id ?? \"REQ-0000\";\nconst prompt = raw.prompt ?? raw.title ?? raw.message ?? \"No prompt provided\";\n\nlet options = raw.options;\n\n// If options came in as a string, try to parse (common beginner mistake)\nif (typeof options === \"string\") {\n  try {\n    options = JSON.parse(options);\n  } catch (e) {\n    options = null;\n  }\n}\n\n// Force options to be an array of {id,label}\nif (!Array.isArray(options)) {\n  return [\n    {\n      json: {\n        ok: false,\n        error: \"invalid_options\",\n        hint: \"options must be an array like: [{ id:'a', label:'Option A' }]\",\n        got_type: typeof raw.options,\n        got_value: raw.options,\n      },\n    },\n  ];\n}\n\nconst cleanOptions = options\n  .map((o, idx) => ({\n    id: String(o?.id ?? idx),\n    label: String(o?.label ?? o?.name ?? o?.text ?? `Option ${idx + 1}`),\n  }))\n  .filter((o) => o.label.trim().length > 0);\n\nif (cleanOptions.length < 2) {\n  return [\n    {\n      json: {\n        ok: false,\n        error: \"not_enough_options\",\n        hint: \"Provide at least 2 options.\",\n        got: cleanOptions,\n      },\n    },\n  ];\n}\n\n// Build the exact backend payload\nconst vp_payload = {\n  decision_id,\n  prompt,\n  options: cleanOptions,\n};\n\nreturn [\n  {\n    json: {\n      ok: true,\n      vp_payload,\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "8d43eb7e-c6d7-4baf-bf48-b910dee72293",
      "name": "VectorPrime Rank (HTTP)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -848,
        -144
      ],
      "parameters": {
        "url": "https://vectorprime-kernel-backend.onrender.com/v1/kernel/rank",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.vp_payload) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3,
      "continueOnFail": true
    },
    {
      "id": "a4689d97-8bca-49dd-bc9d-d018bf168c26",
      "name": "Parse VP Result",
      "type": "n8n-nodes-base.code",
      "position": [
        -656,
        -144
      ],
      "parameters": {
        "jsCode": "// Parse VP Result \u2014 robust for n8n HTTP Request node variations\n\nconst statusCode =\n  $json.statusCode ??\n  $json.status ??\n  null;\n\n// In many n8n configs, the HTTP node returns the JSON body directly as $json\n// In other configs, it returns { body: {...}, statusCode: 200 }\nconst body =\n  $json.body ??\n  $json;\n\n// Decide \u201cok\u201d based on the actual response shape coming back from VectorPrime\nconst ok =\n  (statusCode !== null && statusCode >= 200 && statusCode < 300) ||\n  (body && typeof body === \"object\" && Array.isArray(body.ranking));\n\nreturn [\n  {\n    json: {\n      ok,\n      statusCode,\n      vp: body,\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "c068883f-9050-40e8-88d3-283d157e08cb",
      "name": "VP OK?",
      "type": "n8n-nodes-base.if",
      "position": [
        -480,
        -144
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "802ee7cd-b166-4d44-8ad5-0ba93e31a032",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{$json.ok}}",
              "rightValue": "true"
            }
          ]
        },
        "looseTypeValidation": "={{ true }}"
      },
      "typeVersion": 2.2
    },
    {
      "id": "f50f17cf-8cd3-41cd-a245-84c972c929ab",
      "name": "Respond Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        880,
        48
      ],
      "parameters": {
        "options": {
          "responseCode": 400,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "3e8b5857-ea14-4e28-a851-c9ff351fe241",
      "name": "Create Audit Log",
      "type": "n8n-nodes-base.code",
      "position": [
        416,
        -160
      ],
      "parameters": {
        "jsCode": "// Create an audit log object (great for reviewers + real-world usage).\nconst now = new Date().toISOString();\n\nreturn [{\n  json: {\n    ok: true,\n    audited_at: now,\n    decision_id: $json.decision_id,\n    engine_used: $json.engine_used,\n    top_id: $json.top_id,\n    top_probability: $json.top_probability,\n    ranking: $json.ranking,\n    request: $json.request,\n    route_action: $json.route_action ?? $json.route,\n    // Keep a copy of the VectorPrime payload + raw response for debugging.\n    vp_payload: $json.vp_payload,\n    vp_raw: $json.vp_raw,\n    // Optional: demo payloads\n    slack_message: $json.slack_message,\n    backlog_record: $json.backlog_record,\n    email: ($json.email_to ? { to: $json.email_to, subject: $json.email_subject, body: $json.email_body } : undefined),\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "3bccd42c-62d2-428e-af4a-65aa87dca227",
      "name": "Respond Success",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        880,
        -160
      ],
      "parameters": {
        "options": {
          "responseCode": 200,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "bb7022e2-ab9b-4e03-a832-3d2297256888",
      "name": "Webhook1",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1440,
        -144
      ],
      "parameters": {
        "path": "bf574f34-f8be-44dd-a154-206e4388d1d7",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        },
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "026a302f-f0ee-48b6-a4c8-d2f81d8761d1",
      "name": "Slack Alert Payload",
      "type": "n8n-nodes-base.set",
      "position": [
        -208,
        -160
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "21e3b2e7-c1e7-418b-afc0-2bf3ddc2989b",
      "name": "Backlog Record",
      "type": "n8n-nodes-base.set",
      "position": [
        32,
        -160
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "5e230414-cca8-431f-90a5-f8239c086095",
      "name": "Email Draft",
      "type": "n8n-nodes-base.set",
      "position": [
        208,
        -160
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "8e499f17-70e9-467c-8ae5-133e66ae5410",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1760,
        -1088
      ],
      "parameters": {
        "width": 1456,
        "height": 480,
        "content": "## What this template does\nThis workflow helps you triage incoming tickets/incidents by returning a prioritized list of \u201cnext actions\u201d. It receives a JSON payload via a webhook, validates it, calls an external ranking endpoint, then responds with a clean audit-friendly JSON result. You can keep the workflow as-is (webhook \u2192 ranked output), or connect the optional \u201cSlack / backlog / email draft\u201d steps to your own tools later.\n\n## How it works\n1) Webhook receives a ticket/incident JSON payload.\n2) Normalize step validates the payload and builds `vp_payload` (decision_id, prompt, options[]).\n3) HTTP Request sends `vp_payload` to the ranking endpoint.\n4) Parse step validates the response and sets `ok=true/false`.\n5) If ok=true \u2192 optional payload builders + audit log \u2192 respond success.\n6) If ok=false \u2192 respond with a safe error JSON.\n\n## Setup steps\n1) Create an API key at https://vectorprime.tech\n2) In n8n \u2192 Credentials, create \u201cHeader Auth\u201d:\n   - Header Name: Authorization\n   - Header Value: Bearer vp_YOUR_KEY_HERE\n3) Open \u201cVectorPrime Rank (HTTP)\u201d and select that credential.\n4) Test using the Production URL from Webhook1."
      },
      "typeVersion": 1
    },
    {
      "id": "eca935c6-c75f-4b02-9bee-fb560e32fcdf",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        640,
        -160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "55386b15-7ba5-48e1-8ceb-4e8b275fbba8",
              "name": "request",
              "type": "object",
              "value": "={{$node[\"Webhook1\"].json.body}}"
            },
            {
              "id": "7a6c880f-a5bd-4959-83fb-3c115a694c91",
              "name": "vp",
              "type": "object",
              "value": "={{$node[\"Parse VP Result\"].json}}"
            },
            {
              "id": "1d2e098e-361c-4315-8376-7975583d62d7",
              "name": "audited_at",
              "type": "string",
              "value": "={{$node[\"Create Audit Log\"].json.audited_at}}"
            },
            {
              "id": "5f0e7be6-e72f-4d36-bed3-eaf95c8f6466",
              "name": "ok",
              "type": "boolean",
              "value": true
            },
            {
              "id": "451c3c6e-9530-49e6-bc08-ebb3688e6bed",
              "name": "decision_id",
              "type": "string",
              "value": "={{$node[\"Webhook1\"].json.body.decision_id}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a74f9d02-bcb3-4604-851c-4062026be6c4",
      "name": "Normalize OK?",
      "type": "n8n-nodes-base.if",
      "position": [
        -1056,
        -144
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "83878efe-9a4b-4587-8f07-810e200ebfc7",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{$json.ok}}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": "={{ false }}"
      },
      "typeVersion": 2.3
    },
    {
      "id": "e3462824-2f8f-4f21-b071-6228a55926a2",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1456,
        -432
      ],
      "parameters": {
        "color": 7,
        "width": 150,
        "height": 256,
        "content": "## Input (Webhook)\nReceives POST JSON with:\n- decision_id (string)\n- prompt (string)\n- options (array, 2+ items)"
      },
      "typeVersion": 1
    },
    {
      "id": "cb1b7d64-3bc4-49ad-a7ed-2e08154cda1d",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1232,
        -384
      ],
      "parameters": {
        "color": 7,
        "width": 278,
        "height": 208,
        "content": "## Normalize\nValidates input and builds `vp_payload`.\nReturns error JSON if options are missing/invalid."
      },
      "typeVersion": 1
    },
    {
      "id": "630ed7bf-51e2-43c8-bc7c-ceccfc4a4249",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -880,
        -384
      ],
      "parameters": {
        "color": 7,
        "width": 150,
        "height": 224,
        "content": "## Rank (HTTP)\nCalls the ranking endpoint using your Header Auth credential.\nBody must be JSON so options stay an array."
      },
      "typeVersion": 1
    },
    {
      "id": "4c4a3d9e-2de8-4440-ae61-b40b735d68a6",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -672,
        -400
      ],
      "parameters": {
        "color": 7,
        "width": 294,
        "height": 224,
        "content": "## Validate + Route\nParses response and routes:\n- ok=true \u2192 success path\n- ok=false \u2192 error response"
      },
      "typeVersion": 1
    },
    {
      "id": "a9877458-9efa-4551-ad85-16337dcc1fb6",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        -400
      ],
      "parameters": {
        "color": 7,
        "width": 1200,
        "height": 416,
        "content": "## Output + Audit\nBuilds optional payload drafts, writes audit log, and responds with JSON."
      },
      "typeVersion": 1
    },
    {
      "id": "cb23a11e-d142-4cd3-9170-24210664d0dc",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -880,
        -576
      ],
      "parameters": {
        "color": "#E41B1B",
        "width": 150,
        "height": 192,
        "content": "\u26a0\ufe0f Warning\nDo not send options via \u201cFields below\u201d.\nSend the body as JSON so options remain an array (prevents 422 errors)."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "VP OK?": {
      "main": [
        [
          {
            "node": "Slack Alert Payload",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook1": {
      "main": [
        [
          {
            "node": "Normalize + Build Options",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Respond Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Draft": {
      "main": [
        [
          {
            "node": "Create Audit Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize OK?": {
      "main": [
        [
          {
            "node": "VectorPrime Rank (HTTP)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Backlog Record": {
      "main": [
        [
          {
            "node": "Email Draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse VP Result": {
      "main": [
        [
          {
            "node": "VP OK?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Audit Log": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Alert Payload": {
      "main": [
        [
          {
            "node": "Backlog Record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "VectorPrime Rank (HTTP)": {
      "main": [
        [
          {
            "node": "Parse VP Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize + Build Options": {
      "main": [
        [
          {
            "node": "Normalize OK?",
            "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.

Pro

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

About this workflow

Ranks “best next actions” for an incoming ticket/incident using the VectorPrime Decision Kernel (deterministic + auditable), then returns a clean JSON result you can route to Slack, a backlog tool, or email.

Source: https://n8n.io/workflows/12962/ — 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

This workflow automates end-to-end social media publishing powered by Late API. It generates text content with Google Gemini, creates branded visuals with Kie.ai, uploads media to Late, and publishes

HTTP Request
AI & RAG

This workflow is perfect for app developers, SaaS founders, and mobile growth teams who need constant UGC-style video ads without hiring creators or agencies. If you're spending $500+ per creator and

HTTP Request, Google Drive
AI & RAG

AI Background Generation with Nano Banana (Gemini Image). Uses httpRequest, googleDrive. Webhook trigger; 35 nodes.

HTTP Request, Google Drive
AI & RAG

This template is for developers, teams, and automation enthusiasts who want a private, PIN-protected Telegram chatbot that answers questions from their own documents — without relying on external AI A

Postgres, Telegram, HTTP Request +2
AI & RAG

Elevate your digital presence with high-fidelity cinematic video automation. This workflow orchestrates the complex, asynchronous rendering process of OpenAI Sora—transforming static product images or

HTTP Request, N8N Nodes Uploadtourl