This workflow corresponds to n8n.io template #14381 — we link there as the canonical source.
This workflow follows the Agent → HTTP Request 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": "ica4EwxtFqquNriy",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Set Paperless Document Title w/Tag Removal",
"tags": [],
"nodes": [
{
"id": "dac1caa7-ca26-4712-bbcf-f26f04b2cd52",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-80,
832
],
"parameters": {
"width": 480,
"height": 656,
"content": "## Set Paperless Document Title w/Tag Removal\n\n### How it works\n\n1. The workflow is triggered by a webhook when a title needs updating.\n2. Validates the incoming URL provided in the webhook.\n3. Fetches document content based on the valid URL.\n4. Uses AI to generate a new document name.\n5. Removes unnecessary tags and updates the document title.\n\n### Setup steps\n\n- [ ] Configure the Webhook node to receive update requests.\n- [ ] Set up the API authentication details for all HTTP Request nodes.\n- [ ] Ensure the AI Agent has access to required models like OpenAI Chat.\n\n### Customization\n\nAdjustment of tags to remove can be customized in the \"Filter Out Tag to Remove\" code node."
},
"typeVersion": 1
},
{
"id": "41e686d7-717f-4e22-a0bd-bbb2738aedf0",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
928
],
"parameters": {
"color": 7,
"width": 640,
"height": 464,
"content": "## Trigger and validation\n\nStarts workflow on webhook and validates the URL."
},
"typeVersion": 1
},
{
"id": "03ff65d0-e543-4ab2-9abd-848f2508cbcb",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1152,
928
],
"parameters": {
"color": 7,
"width": 640,
"height": 368,
"content": "## Fetch and evaluate document\n\nFetches document content and checks if it needs processing."
},
"typeVersion": 1
},
{
"id": "e377cc84-6766-4b24-8db5-f59dfef5f4b2",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1584,
832
],
"parameters": {
"color": 7,
"width": 576,
"height": 480,
"content": "## AI document name generation\n\nGenerates a new document name using AI."
},
"typeVersion": 1
},
{
"id": "fb80dceb-53f1-4aa9-9d12-9cb1bd539856",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2176,
832
],
"parameters": {
"color": 7,
"width": 640,
"height": 272,
"content": "## Tag removal and update\n\nIdentifies and removes unnecessary tags, then updates the document."
},
"typeVersion": 1
},
{
"id": "7501a8b0-010d-4f12-a938-c35bce1553a3",
"name": "Fetch Document Content",
"type": "n8n-nodes-base.httpRequest",
"position": [
1200,
1040
],
"parameters": {
"url": "={{ $json.scheme }}://{{ $json.server }}/api/documents/{{ $json.documentId }}/",
"options": {
"response": {
"response": {
"fullResponse": true
}
}
},
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth"
},
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.3
},
{
"id": "eae50ac5-0899-497c-88ee-3c9c1b5ada13",
"name": "Apply Document Guardrails",
"type": "@n8n/n8n-nodes-langchain.guardrails",
"position": [
1648,
944
],
"parameters": {
"text": "={{ $json.body.content }}",
"operation": "sanitize",
"guardrails": {
"pii": {
"value": {
"type": "all"
}
}
}
},
"typeVersion": 2
},
{
"id": "29811062-625a-4362-a0f4-001a80d4d5ba",
"name": "Generate Title AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1872,
944
],
"parameters": {
"text": "={{ $json.guardrailsInput.substring(0, 10000) }}",
"options": {
"systemMessage": "Role: You are an expert Document Archivist and Information Architect. Your task is to analyze the text provided, which has been generated via OCR (Optical Character Recognition) from scanned documents.\n\nTask: Generate a concise, descriptive, and professional title for the document based on its primary subject matter, intent, and key entities (e.g., companies, dates, or specific project names).\n\nGuidelines:\n\n Contextual Accuracy: Prioritize formal headers, dates, and recurring keywords to determine the document type (e.g., Invoice, Technical Specification, Meeting Minutes, Contract).\n\n OCR Resilience: Ignore \"noise\" typical of OCR, such as garbled characters, misread page numbers, or fragmented headers.\n\n Format: Output only the suggested title. Limit the length to no more than 60 characters. Do not include introductory text like \"The title is...\" or \"I suggest...\"\n\n Naming Convention: Use a standard format: [YYYY-MM-DD] - [Document Type] - [Main Subject/Entity]. If a date is not found, omit it.\n\nTone: Professional and objective."
},
"promptType": "define"
},
"notesInFlow": false,
"typeVersion": 3.1,
"alwaysOutputData": false
},
{
"id": "c4e951f8-75b7-4c35-8663-2ec94dfd1f87",
"name": "OpenAI GPT-4 Mini",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1944,
1168
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4o Mini"
},
"options": {
"maxTokens": 4096
},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "be586407-249a-4843-a02b-aa7e120010d9",
"name": "Interrupt on Invalid URL",
"type": "n8n-nodes-base.stopAndError",
"position": [
976,
1232
],
"parameters": {
"errorMessage": "Input value for doc_url is not a url."
},
"typeVersion": 1
},
{
"id": "c81573f7-2c8c-4f90-b440-bed570249b73",
"name": "Set URL Components",
"type": "n8n-nodes-base.set",
"position": [
976,
1040
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "a734fa97-0bca-485b-8ce3-ae328c3d0e8d",
"name": "server",
"type": "string",
"value": "={{ $json.body['x-doc-url'].extractDomain() }}"
},
{
"id": "b2d29825-7452-4657-aed2-da4413f72cb7",
"name": "scheme",
"type": "string",
"value": "={{ $json.body['x-doc-url'].split(':')[0] }}"
},
{
"id": "853b2b68-2389-4a31-82c9-a95ad9a51f4e",
"name": "documentId",
"type": "string",
"value": "={{ (() => {\nconst path = $json.body['x-doc-url'].extractUrlPath().split('/');\nconst id = path[path.length - 2];\nreturn id;\n})() }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "9890ada3-e94a-462a-bead-4a9639b61701",
"name": "Check URL Validity",
"type": "n8n-nodes-base.if",
"position": [
752,
1136
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "187466b4-2c51-40ca-bb84-b53209fa24a8",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.body['x-doc-url'].isUrl() }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "07ecb804-889a-4f81-b687-048a4a5e0c29",
"name": "Fetch Removal Tag ID",
"type": "n8n-nodes-base.httpRequest",
"position": [
2224,
944
],
"parameters": {
"url": "={{ $('Set URL Components').first().json.scheme }}://{{ $('Set URL Components').first().json.server }}/api/tags/?name__iexact={{ $('When Title Update Requested').item.json.body['x-tag-to-remove'] }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth"
},
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.4
},
{
"id": "5b685cba-fc5a-4d95-8a86-c39f9806f4a1",
"name": "Execute Tag Removal",
"type": "n8n-nodes-base.code",
"position": [
2448,
944
],
"parameters": {
"jsCode": "// Using ?. to safely navigate and ?? to provide a default empty array\nconst tagIdToRemove = $('Fetch Removal Tag ID').first()?.json?.results?.[0]?.id;\nconst currentTags = $('Fetch Document Content').first()?.json?.body?.tags ?? [];\n\n// If tagIdToRemove is undefined, the filter simply returns the full currentTags array\nconst updatedTags = currentTags.filter(id => id !== tagIdToRemove);\n\nreturn {\n updatedTags: updatedTags\n};"
},
"typeVersion": 2
},
{
"id": "4b6ca323-c425-4f11-8cc9-17b67c26bb8e",
"name": "Terminate Process",
"type": "n8n-nodes-base.noOp",
"position": [
1648,
1136
],
"parameters": {},
"typeVersion": 1
},
{
"id": "4001cfee-0f64-4485-9482-b3676d6e31ab",
"name": "Apply Document Updates",
"type": "n8n-nodes-base.httpRequest",
"position": [
2672,
944
],
"parameters": {
"url": "={{ $('Set URL Components').first().json.scheme }}://{{ $('Set URL Components').first().json.server }}/api/documents/{{ $('Set URL Components').last().json.documentId }}/",
"method": "PATCH",
"options": {},
"sendBody": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "title",
"value": "={{ $('Generate Title AI Agent').first().json.output }}"
},
{
"name": "tags",
"value": "={{ $json.updatedTags }}"
}
]
},
"genericAuthType": "httpBasicAuth"
},
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.3
},
{
"id": "a5c92cd2-7a5f-43c0-a7eb-dc3361fa2726",
"name": "If Document Content Exists",
"type": "n8n-nodes-base.if",
"position": [
1424,
1040
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "5fbec441-1f29-4e12-8cc1-c2a48e814e2c",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.body.content }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "ce5ef9c8-ae58-478b-8e8d-9905321ad780",
"name": "When Title Update Requested",
"type": "n8n-nodes-base.webhook",
"position": [
528,
1136
],
"parameters": {
"path": "update-document-title",
"options": {},
"httpMethod": "POST",
"authentication": "headerAuth"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
}
],
"active": true,
"settings": {
"binaryMode": "separate",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "aea605f3-fc39-48ca-948d-159ec0695e03",
"connections": {
"OpenAI GPT-4 Mini": {
"ai_languageModel": [
[
{
"node": "Generate Title AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Check URL Validity": {
"main": [
[
{
"node": "Set URL Components",
"type": "main",
"index": 0
}
],
[
{
"node": "Interrupt on Invalid URL",
"type": "main",
"index": 0
}
]
]
},
"Set URL Components": {
"main": [
[
{
"node": "Fetch Document Content",
"type": "main",
"index": 0
}
]
]
},
"Execute Tag Removal": {
"main": [
[
{
"node": "Apply Document Updates",
"type": "main",
"index": 0
}
]
]
},
"Fetch Removal Tag ID": {
"main": [
[
{
"node": "Execute Tag Removal",
"type": "main",
"index": 0
}
]
]
},
"Fetch Document Content": {
"main": [
[
{
"node": "If Document Content Exists",
"type": "main",
"index": 0
}
]
]
},
"Generate Title AI Agent": {
"main": [
[
{
"node": "Fetch Removal Tag ID",
"type": "main",
"index": 0
}
]
]
},
"Apply Document Guardrails": {
"main": [
[
{
"node": "Generate Title AI Agent",
"type": "main",
"index": 0
}
]
]
},
"If Document Content Exists": {
"main": [
[
{
"node": "Apply Document Guardrails",
"type": "main",
"index": 0
}
],
[
{
"node": "Terminate Process",
"type": "main",
"index": 0
}
]
]
},
"When Title Update Requested": {
"main": [
[
{
"node": "Check URL Validity",
"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.
httpBasicAuthhttpHeaderAuthopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This template automatically generates a professional, structured title for newly-ingested Paperless-ngx documents using AI (OpenAI GPT), then removes a processing tag to mark the document as handled. A webhook fires when a document needs titling (e.g., from a Paperless…
Source: https://n8n.io/workflows/14381/ — 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.
|Overview |Sample| |-|-| |This template is the first of its kind: it automatically generates both the caption and the image for your Instagram posts by analysing your existing feed, with zero spreadsh
This workflow is designed for professionals, companies, and agencies that want to automate competitive analysis based on public reviews and opinions found on the Internet. It is especially useful for:
f1_bot_zoom. Uses stopAndError, httpRequest, emailSend, agent. Webhook trigger; 39 nodes.
⏺ 🚀 How it works
L&D_AgentsAI_ATIVO. Uses httpRequest, agent, googleCalendarTool, toolSerpApi. Webhook trigger; 93 nodes.