This workflow corresponds to n8n.io template #14318 — we link there as the canonical source.
This workflow follows the Form Trigger → Google Drive 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 →
{
"meta": {
"templateCredsSetupCompleted": false
},
"name": "Invoice Classification Workflow (powered by easybits)",
"tags": [
{
"name": "AI"
},
{
"name": "AI Classification"
},
{
"name": "Classification"
},
{
"name": "Document Processing"
},
{
"name": "easybits"
}
],
"nodes": [
{
"id": "8f5c0ee5-d505-4bb2-9ffa-8723519e14e8",
"name": "Extract from File",
"type": "n8n-nodes-base.extractFromFile",
"position": [
224,
16
],
"parameters": {
"options": {},
"operation": "binaryToPropery",
"binaryPropertyName": "image"
},
"typeVersion": 1.1
},
{
"id": "0b1bbec4-90f6-43df-83a5-291f20df0afe",
"name": "On form submission",
"type": "n8n-nodes-base.formTrigger",
"position": [
-64,
16
],
"parameters": {
"options": {},
"formTitle": "Image Upload",
"formFields": {
"values": [
{
"fieldType": "file",
"fieldLabel": "image"
}
]
}
},
"typeVersion": 2.5
},
{
"id": "07e1cb4d-563e-4eb3-bfea-6abf4de90910",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"position": [
512,
16
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "540141e7-42d3-4011-b681-8335d9105044",
"name": "data",
"type": "string",
"value": "=data:{{ $('On form submission').first().binary.image.mimeType }};base64,{{ $json.data }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "ed7ca29a-3556-420e-aff1-5e5375b14d40",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-144,
-160
],
"parameters": {
"color": 7,
"width": 256,
"height": 352,
"content": "## \ud83d\udccb Form Upload\nAccepts a file upload via a **web form**. Supports **PDF, PNG, and JPEG**."
},
"typeVersion": 1
},
{
"id": "f0a40bb8-4d2f-4a13-92e9-4d09176075b1",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
144,
-160
],
"parameters": {
"color": 7,
"width": 256,
"height": 352,
"content": "## \ud83d\udcc4 Extract to Base64\nConverts the uploaded **binary file** into a base64-encoded string stored in `data`."
},
"typeVersion": 1
},
{
"id": "493e2722-9c17-49ed-9a2b-5deb701f0211",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
432,
-160
],
"parameters": {
"color": 7,
"width": 256,
"height": 352,
"content": "## \ud83d\udd17 Build Data URI\nDynamically reads the **MIME type** from the uploaded file and prepends it as a base64 data URI."
},
"typeVersion": 1
},
{
"id": "6eb8b59f-56b2-4318-bc56-04e91da5877c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1008,
-160
],
"parameters": {
"color": 7,
"width": 256,
"height": 352,
"content": "## \ud83d\udd0d Parse Result\nExtracts **document_type** and **confidence_score** from the easybits API response into separate fields for downstream routing."
},
"typeVersion": 1
},
{
"id": "1e9361a2-9e7f-4301-a790-4a6c8afbae78",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1040,
-688
],
"parameters": {
"width": 864,
"height": 1408,
"content": "# \ud83d\udcc4 Invoice Classification Workflow\n(powered by easybits)\n\n## What This Workflow Does\nUpload a document (PDF, PNG, JPEG) via a web form and let **easybits Extractor** classify it into one of your defined categories. Based on the classification result and a confidence score, the document is automatically sorted into the correct **Google Drive** folder. Low-confidence or unrecognized documents are flagged for manual review via **Slack**.\n\n## How It Works\n1. User uploads a file through the hosted web form\n2. The binary file is converted to base64 and sent to easybits\n3. easybits returns a **document_type** and **confidence_score**\n4. The classification result is merged with the original file binary\n5. If confidence > 0.5 \u2192 routed to the matching Google Drive folder\n6. If confidence \u2264 0.5 or no category match \u2192 uploaded to **Needs Review** folder + Slack alert\n\n**Supported categories:**\n`medical_invoice` \u00b7 `restaurant_invoice` \u00b7 `hotel_invoice` \u00b7 `trades_invoice` \u00b7 `telecom_invoice`\n\n---\n\n## Setup Guide\n\n### 1. Set Up Your easybits Extractor Pipeline\n1. Go to **extractor.easybits.tech** and create a new pipeline\n2. Add two fields to the mapping: **document_class** and **confidence_score**\n3. In each field's description, paste the corresponding classification or confidence prompt that tells the model how to analyze the document\n4. The classification prompt should return exactly one category label \u2013 or `null` if uncertain\n5. The confidence prompt should return a decimal number between 0.0 and 1.0\n6. Save & test the pipeline, then copy your **Pipeline ID** and **API Key**\n\n### 2. Set Up Google Drive\n1. Create a folder in Google Drive for each category: **Medical**, **Restaurant**, **Hotel**, **Trades**, **Telecom**, and **Needs Review**\n2. In n8n, go to **Settings \u2192 Credentials** and create a **Google Drive OAuth2** credential\n3. This requires a **Client ID** and **Client Secret** from the Google Cloud Console (APIs & Services \u2192 Credentials \u2192 OAuth 2.0 Client ID)\n4. Make sure the **Google Drive API** is enabled in your Google Cloud project\n5. Open each of the 6 Google Drive upload nodes in this workflow and select the correct target folder\n\n### 3. Set Up Slack\n1. In n8n, go to **Settings \u2192 Credentials** and create a **Slack API** credential\n2. You'll need a Slack Bot Token \u2013 create a Slack App at **api.slack.com/apps**, add the `chat:write` scope, and install it to your workspace\n3. Create a channel for review notifications (e.g. `#n8n-invoice-review`)\n4. Invite the bot to that channel\n5. Open the **Review Message** node and select the correct channel\n\n### 4. Connect the easybits Node\n1. Open the **easybits Extractor (Classification)** node\n2. Replace the pipeline URL with your own: `https://extractor.easybits.tech/api/pipelines/YOUR_PIPELINE_ID`\n3. Create a **Bearer Auth** credential using your easybits API Key and assign it to the node\n\n### 5. Activate & Test\n1. Click **Active** in the top-right corner of n8n\n2. Open the form URL and upload a test document\n3. Check the execution log to verify the classification result\n4. Confirm the file lands in the correct Google Drive folder\n5. Test with an unrecognized document to verify the Slack notification fires"
},
"typeVersion": 1
},
{
"id": "e7f53509-9468-4238-b41f-092866d3532d",
"name": "easybits Extractor (Classification)",
"type": "n8n-nodes-base.httpRequest",
"position": [
800,
16
],
"parameters": {
"url": "https://extractor.easybits.tech/api/pipelines/YOUR_PIPELINE_ID",
"method": "POST",
"options": {},
"jsonBody": "={\n \"files\": [\n \"{{ $json.data }}\"\n ]\n} ",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "httpBearerAuth"
},
"typeVersion": 4.3
},
{
"id": "c012a3af-1ded-4b54-b5dc-1db970f419a3",
"name": "Parse Result",
"type": "n8n-nodes-base.set",
"position": [
1088,
16
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "5ee1b814-1ab6-4e23-be71-3aa095ff29b8",
"name": "=document_type",
"type": "string",
"value": "={{ $json.data.document_class }}"
},
{
"id": "dee6e7d6-7934-49df-a295-5e718080a56f",
"name": "confidence_score",
"type": "number",
"value": "={{ $json.data.confidence_score }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "f976eacd-fbe6-4458-8d30-c712583ee6df",
"name": "Category Router",
"type": "n8n-nodes-base.switch",
"position": [
2016,
-144
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "26fbb5c8-4207-438c-a1d5-3e867665a0cd",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.document_type }}",
"rightValue": "medical_invoice"
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1bd8eb0a-fc71-4e30-9264-ee6ad382428a",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.document_type }}",
"rightValue": "restaurant_invoice"
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "4d8ff66a-28cb-4a83-ad70-14b92b07b9bd",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.document_type }}",
"rightValue": "hotel_invoice"
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "8b8edf86-8b30-4db8-b047-16b707a0cda6",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.document_type }}",
"rightValue": "trades_invoice"
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "40c59cfe-cf3d-41eb-92f6-826dcf47ca60",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.document_type }}",
"rightValue": "telecom_invoice"
}
]
}
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"typeVersion": 3.4
},
{
"id": "29586299-5500-4e41-b4fa-d1e886f214dd",
"name": "Confidence Check",
"type": "n8n-nodes-base.if",
"position": [
1712,
16
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "dcbdfbf2-a398-41d1-8d1c-32167bd3b047",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.confidence_score }}",
"rightValue": 0.5
}
]
}
},
"typeVersion": 2.3
},
{
"id": "e6ab1f14-9b14-4430-96ee-662440f29cb5",
"name": "Upload to Review Folder",
"type": "n8n-nodes-base.googleDrive",
"position": [
2304,
624
],
"parameters": {
"name": "={{ $('On form submission').first().binary.image.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "YOUR_NEEDS_REVIEW_FOLDER_ID"
},
"inputDataFieldName": "image"
},
"typeVersion": 3
},
{
"id": "710bf76e-47a2-4a17-8bba-80520da84196",
"name": "Upload to Telecom Folder",
"type": "n8n-nodes-base.googleDrive",
"position": [
2304,
224
],
"parameters": {
"name": "={{ $('On form submission').first().binary.image.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "YOUR_TELECOM_FOLDER_ID"
},
"inputDataFieldName": "image"
},
"typeVersion": 3
},
{
"id": "d412f0e2-3b97-4766-bf34-aa5643b5ea4e",
"name": "Upload to Trades Folder",
"type": "n8n-nodes-base.googleDrive",
"position": [
2304,
16
],
"parameters": {
"name": "={{ $('On form submission').first().binary.image.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "YOUR_TRADES_FOLDER_ID"
},
"inputDataFieldName": "image"
},
"typeVersion": 3
},
{
"id": "43c6a87b-c9bc-4507-8cee-55b01bf0118c",
"name": "Upload to Hotel Folder",
"type": "n8n-nodes-base.googleDrive",
"position": [
2304,
-192
],
"parameters": {
"name": "={{ $('On form submission').first().binary.image.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "YOUR_HOTEL_FOLDER_ID"
},
"inputDataFieldName": "image"
},
"typeVersion": 3
},
{
"id": "3d3204ef-5e3c-4d60-8f39-a8825a5af10b",
"name": "Upload to Restaurant Folder",
"type": "n8n-nodes-base.googleDrive",
"position": [
2304,
-384
],
"parameters": {
"name": "={{ $('On form submission').first().binary.image.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "YOUR_RESTAURANT_FOLDER_ID"
},
"inputDataFieldName": "image"
},
"typeVersion": 3
},
{
"id": "e68ac860-5d62-4ca9-ac22-2feb73ae4aa7",
"name": "Upload to Medical Folder",
"type": "n8n-nodes-base.googleDrive",
"position": [
2304,
-576
],
"parameters": {
"name": "={{ $('On form submission').first().binary.image.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "YOUR_MEDICAL_FOLDER_ID"
},
"inputDataFieldName": "image"
},
"typeVersion": 3
},
{
"id": "49d86462-b774-48a2-a2b3-18945573d2f1",
"name": "Review Message",
"type": "n8n-nodes-base.slack",
"position": [
2592,
624
],
"parameters": {
"text": "=\ud83d\udd0d *Invoice needs manual classification*\n- Document Category: {{ $('Parse Result').item.json.document_type }}\n- Confidence: {{ $('Parse Result').item.json.confidence_score }}\n- File: {{ $('On form submission').first().binary.image.fileName }}\n- Google Drive: {{ $json.webViewLink }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SLACK_CHANNEL_ID"
},
"otherOptions": {}
},
"typeVersion": 2.4
},
{
"id": "0e5b6999-9a36-409b-96b1-04ae1bcaea6b",
"name": "Attach Original File",
"type": "n8n-nodes-base.merge",
"position": [
1392,
416
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "c99f2a8b-81f7-429b-a364-7e0de118e778",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
720,
-160
],
"parameters": {
"color": 7,
"width": 256,
"height": 352,
"content": "## \ud83d\ude80 Send to easybits\nPOSTs the data URI to the **easybits Extractor API** pipeline for processing."
},
"typeVersion": 1
},
{
"id": "461b7856-9216-422a-9fb0-9285dd1c6c23",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1296,
240
],
"parameters": {
"color": 7,
"width": 288,
"height": 352,
"content": "## \ud83d\udd17 Attach Original File\nMerges the classification result (JSON) with the original binary file from the form upload using **Combine by Position**, so downstream nodes have both the data and the file."
},
"typeVersion": 1
},
{
"id": "92bf3850-00d1-48e6-b0c4-675dac4ca2fa",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
1616,
-160
],
"parameters": {
"color": 7,
"width": 288,
"height": 352,
"content": "## \u2705 Confidence Check\nRoutes based on the **confidence_score**:\n- **> 0.5** \u2192 Category Router\n- **\u2264 0.5** \u2192 Needs Review folder + Slack notification"
},
"typeVersion": 1
},
{
"id": "7bbd0e06-db14-417a-8104-91f915c833ea",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
1936,
-448
],
"parameters": {
"color": 7,
"width": 256,
"height": 592,
"content": "## \ud83d\uddc2\ufe0f Category Router\nRoutes the invoice to the correct Google Drive folder based on **document_type**:\n\n1. `medical_invoice`\n2. `restaurant_invoice`\n3. `hotel_invoice`\n4. `trades_invoice`\n5. `telecom_invoice`\n6. Fallback \u2192 Needs Review"
},
"typeVersion": 1
},
{
"id": "fdd6cc26-733d-4d3c-bc21-045f77ce2f1d",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
2224,
-752
],
"parameters": {
"color": 7,
"width": 256,
"height": 1168,
"content": "## \ud83d\udce4 Upload to Google Drive Folders\nUploads the invoice to the **Medical** folder in Google Drive."
},
"typeVersion": 1
},
{
"id": "8a3e3022-72ef-4fa3-af18-4c2bae0f34dd",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"position": [
2224,
448
],
"parameters": {
"color": 7,
"width": 256,
"height": 352,
"content": "## \u26a0\ufe0f Upload to Review Folder\nUploads unclassified or low-confidence invoices to the **Needs Review** folder in Google Drive."
},
"typeVersion": 1
},
{
"id": "fade8cd4-bccb-4dd5-82d9-b99e936fdea8",
"name": "Sticky Note11",
"type": "n8n-nodes-base.stickyNote",
"position": [
2512,
448
],
"parameters": {
"color": 7,
"width": 256,
"height": 352,
"content": "## \ud83d\udcac Slack Notification\nSends a message to `#n8n-invoice-review` with the **document type**, **confidence score**, **file name**, and a direct **Google Drive link** so the team can manually classify the invoice."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"timeSavedMode": "fixed",
"availableInMCP": false,
"executionOrder": "v1"
},
"connections": {
"Edit Fields": {
"main": [
[
{
"node": "easybits Extractor (Classification)",
"type": "main",
"index": 0
}
]
]
},
"Parse Result": {
"main": [
[
{
"node": "Attach Original File",
"type": "main",
"index": 0
}
]
]
},
"Category Router": {
"main": [
[
{
"node": "Upload to Medical Folder",
"type": "main",
"index": 0
}
],
[
{
"node": "Upload to Restaurant Folder",
"type": "main",
"index": 0
}
],
[
{
"node": "Upload to Hotel Folder",
"type": "main",
"index": 0
}
],
[
{
"node": "Upload to Trades Folder",
"type": "main",
"index": 0
}
],
[
{
"node": "Upload to Telecom Folder",
"type": "main",
"index": 0
}
],
[
{
"node": "Upload to Review Folder",
"type": "main",
"index": 0
}
]
]
},
"Confidence Check": {
"main": [
[
{
"node": "Category Router",
"type": "main",
"index": 0
}
],
[
{
"node": "Upload to Review Folder",
"type": "main",
"index": 0
}
]
]
},
"Extract from File": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"On form submission": {
"main": [
[
{
"node": "Extract from File",
"type": "main",
"index": 0
},
{
"node": "Attach Original File",
"type": "main",
"index": 1
}
]
]
},
"Attach Original File": {
"main": [
[
{
"node": "Confidence Check",
"type": "main",
"index": 0
}
]
]
},
"Upload to Review Folder": {
"main": [
[
{
"node": "Review Message",
"type": "main",
"index": 0
}
]
]
},
"easybits Extractor (Classification)": {
"main": [
[
{
"node": "Parse Result",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Upload a document (PDF, PNG, JPEG) via a web form and let easybits Extractor classify it into one of your defined categories. Based on the classification result and a confidence score, the document is automatically sorted into the correct Google Drive folder. Low-confidence or…
Source: https://n8n.io/workflows/14318/ — 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.
Expenses Tracker (video). Uses httpRequest, splitInBatches, googleSheets, googleDrive. Event-driven trigger; 21 nodes.
Type in Slack. Walk away. Get a professional PDF report and a structured Excel fix sheet delivered to Google Drive and posted back in your Slack thread — fully automated, zero manual work.
Automatically transform any website URL into a complete portfolio entry with professional screenshots and AI-generated Upwork project descriptions. Freelancers building their Upwork/portfolio from pas
The Recap AI - Reverse Engineer Short Form AI Video. Uses formTrigger, httpRequest, slack. Event-driven trigger; 22 nodes.
Who’s it for? 👥