This workflow corresponds to n8n.io template #17198 — we link there as the canonical source.
This workflow follows the Emailreadimap → 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": "WpsYeuYFlRv22h1v",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Zoho Books invoices from email attachments",
"tags": [],
"nodes": [
{
"id": "dfd1e32a-2f0a-497a-8d3f-bfd2e4083881",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
11776,
2656
],
"parameters": {
"width": 480,
"height": 896,
"content": "## Create Zoho Books invoices from email attachments with OpenAI OCR\n\n### How it works\n\nThis workflow monitors an IMAP inbox for emails with attachments, extracts the attached invoice files, and prepares them for OCR. It routes PDFs and images through OpenAI OCR, combines the extracted text with Zoho Books reference data, then uses OpenAI to parse structured invoice details. Valid invoices are matched with customer data and posted as new documents to Zoho Books.\n\n### Setup steps\n\n- Configure the IMAP email credentials for the incoming mailbox trigger.\n- Configure OpenAI credentials for the OCR and invoice parsing nodes.\n- Configure Zoho Books API credentials or OAuth authentication for the HTTP Request nodes.\n- Set the workflow constants, including Zoho data center, organization ID, fallback customer ID, and whether sender email should be used for customer lookup.\n- Verify the Zoho Books endpoints, required scopes, and payload format for taxes, currencies, customers, and document creation.\n\n### Customization\n\nAdjust the file type routing, OpenAI OCR/parsing prompts, customer matching filters, fallback customer behavior, and invoice payload-building code to match your Zoho Books setup and invoice formats."
},
"typeVersion": 1
},
{
"id": "5c561bf2-0300-4eaa-9961-6a51b020ec44",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
12336,
3056
],
"parameters": {
"color": 7,
"width": 416,
"height": 320,
"content": "## Receive email settings\n\nStarts the workflow when an email arrives and defines reusable constants for Zoho Books and customer lookup behavior."
},
"typeVersion": 1
},
{
"id": "8b99c6ec-380c-499c-8ad9-9aa1563f9448",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
12784,
3056
],
"parameters": {
"color": 7,
"width": 640,
"height": 320,
"content": "## Prepare email attachments\n\nFilters incoming emails to only those with attachments, splits out each attachment, and prepares the files for downstream OCR and data lookups."
},
"typeVersion": 1
},
{
"id": "45b27760-287c-462e-b442-e0b502b2df5b",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
13520,
3008
],
"parameters": {
"color": 7,
"width": 800,
"height": 464,
"content": "## Route and OCR files\n\nRoutes prepared attachments by file type, sends PDFs or images to the appropriate OpenAI OCR node, and merges the OCR text results."
},
"typeVersion": 1
},
{
"id": "56c43240-ffc5-4a5b-bccf-7601ee857bfc",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
13392,
2656
],
"parameters": {
"color": 7,
"width": 704,
"height": 304,
"content": "## Fetch reference data\n\nRetrieves taxes and currencies from Zoho Books and formats them for use during invoice parsing."
},
"typeVersion": 1
},
{
"id": "12cdd4f6-2364-42ee-b9fa-b26c1264cbff",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
14416,
2976
],
"parameters": {
"color": 7,
"width": 448,
"height": 320,
"content": "## Parse invoice text\n\nCombines OCR output with the prepared Zoho Books tax and currency data, then asks OpenAI to extract structured invoice information."
},
"typeVersion": 1
},
{
"id": "64f5798a-4f19-4071-bdd4-db54298073d2",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
15024,
2976
],
"parameters": {
"color": 7,
"width": 416,
"height": 320,
"content": "## Validate invoice DTO\n\nMaps the AI parsing result into an invoice DTO and filters out invoices that are not considered valid."
},
"typeVersion": 1
},
{
"id": "280a9771-199e-4410-8d95-bb10de80c022",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
14128,
3504
],
"parameters": {
"color": 7,
"width": 480,
"height": 304,
"content": "## Fetch customer records\n\nFetches customer records from Zoho Books and splits the returned list into individual customer items."
},
"typeVersion": 1
},
{
"id": "a7208a8b-5145-4b26-a73e-4c1bd6c82887",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
14736,
3344
],
"parameters": {
"color": 7,
"width": 480,
"height": 320,
"content": "## Match customer data\n\nFilters customer records to find relevant matches and aggregates the selected customer information for invoice creation."
},
"typeVersion": 1
},
{
"id": "e2c52772-26c4-4656-a61d-e0b520f1345f",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
15472,
3024
],
"parameters": {
"color": 7,
"width": 640,
"height": 304,
"content": "## Create Zoho document\n\nMerges the validated invoice with matched customer data, builds the final Zoho Books document payload, and posts it to Zoho Books."
},
"typeVersion": 1
},
{
"id": "6213843f-d4e0-43aa-8ca6-c7c760802471",
"name": "OpenAI OCR for PDF Files",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
13792,
3136
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-nano",
"cachedResultName": "GPT-4.1-NANO"
},
"options": {},
"responses": {
"values": [
{
"role": "system",
"content": "=Extract all visible text from the image exactly as it appears.\n\nRules:\n- Preserve layout using line breaks\n- Read top-to-bottom, left-to-right\n- Include numbers, symbols, and special characters\n- If text is unclear, include your best guess\n- Do not summarize or explain anything\n\nReturn ONLY the raw text."
},
{
"type": "file",
"fileName": "={{ $input.item.binary[Object.keys($input.item.binary)[0]].fileName }}",
"fileType": "base64",
"binaryPropertyName": "={{ Object.keys($input.item.binary)[0] }}"
}
]
},
"builtInTools": {}
},
"typeVersion": 2.1
},
{
"id": "001944fd-e0e4-4164-b8ca-e6d8017d5b42",
"name": "OpenAI OCR for Image Files",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
13792,
3296
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini",
"cachedResultName": "GPT-4.1-MINI"
},
"options": {},
"responses": {
"values": [
{
"role": "system",
"content": "Extract all visible text from the image exactly as it appears.\n\nRules:\n- Preserve layout using line breaks\n- Read top-to-bottom, left-to-right\n- Include numbers, symbols, and special characters\n- If text is unclear, include your best guess\n- Do not summarize or explain anything\n\nReturn ONLY the raw text."
},
{
"type": "image",
"imageType": "base64",
"binaryPropertyName": "={{ Object.keys($input.item.binary)[0] }}"
}
]
},
"builtInTools": {}
},
"typeVersion": 2.1
},
{
"id": "3d213c84-6e4f-42fc-be4c-61c555588ac0",
"name": "Route by Document Type",
"type": "n8n-nodes-base.switch",
"position": [
13568,
3216
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "PDF",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "083bc6b0-086f-40e0-8991-a33e2af70953",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $input.item.binary[Object.keys($input.item.binary)[0]].fileName.split(\".\").last()==='pdf' }}",
"rightValue": "pdf"
}
]
},
"renameOutput": true
},
{
"outputKey": "Image",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "2df665f3-0068-48b5-958e-8cc0a68e3f34",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ ['jpeg', 'jpg', 'png', 'webp'].includes($input.item.binary[Object.keys($input.item.binary)[0]].fileName.split(\".\").last()) }}",
"rightValue": ""
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "2c9325a5-c2bd-4c9d-8d43-e51f173f9953",
"name": "Prepare Files for Scanning",
"type": "n8n-nodes-base.code",
"position": [
13280,
3216
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const oldKey = Object.keys($input.item.binary)[0];\nconst binary = $input.item.binary;\n\n// Set MIME type\nconst extension = binary[oldKey].fileExtension?.toLowerCase();\n\nif (extension === \"pdf\") {\n binary[oldKey].mimeType = \"application/pdf\";\n} else if ([\"png\", \"jpg\", \"jpeg\"].includes(extension)) {\n binary[oldKey].mimeType = extension === \"jpg\"\n ? \"image/jpeg\"\n : `image/${extension}`;\n}\n\n// Rename binary property to \"attachment\"\nbinary.attachment = binary[oldKey];\ndelete binary[oldKey];\n\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "8ecfa948-7587-4a46-9a0a-a7eb4358c42c",
"name": "Prepare Invoice Data",
"type": "n8n-nodes-base.set",
"position": [
15072,
3136
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "60848c24-bbd6-4acb-a51f-65d2748d14d3",
"name": "is_valid_invoice",
"type": "boolean",
"value": "={{ $json.output[0].content[0].text.is_valid_invoice }}"
},
{
"id": "9d437827-c1fb-4fff-be49-bcd0cb7922ac",
"name": "invoice_data",
"type": "object",
"value": "={{\n {\n ...$json.output[0].content[0].text.invoice_data,\n currency_id: $('Format ZBooks Data').first().json.currencies.find((c) => c.currency_code === $json.output[0].content[0].text.currency_code ?? \"USD\" ).currency_id,\n currency_code: $json.output[0].content[0].text.currency_code ?? \"USD\"\n }\n}}"
},
{
"id": "f80e0a46-1e8e-4154-a8ab-b0ce320b0d16",
"name": "customer_data",
"type": "object",
"value": "={{ $json.output[0].content[0].text.customer_data }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "8ae34aa8-378c-4b23-90f4-f17a82808fc9",
"name": "Retrieve Customers from ZBooks",
"type": "n8n-nodes-base.httpRequest",
"position": [
14176,
3632
],
"parameters": {
"url": "=https://www.zohoapis.{{ $('Configure Workflow Constants').item.json.zoho_data_center }}/books/v3/contacts?organization_id={{ $('Configure Workflow Constants').item.json.zbooks_org_id }}",
"options": {
"pagination": {
"pagination": {
"parameters": {
"parameters": [
{
"name": "page",
"value": "={{ $response.body.page_context.page+1 }}"
}
]
},
"completeExpression": "={{ !$response.body.page_context.has_more_page }}",
"paginationCompleteWhen": "other"
}
}
},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "oAuth2Api",
"queryParameters": {
"parameters": [
{
"name": "contact_type",
"value": "customer"
},
{
"name": "filter_by",
"value": "Status.Active"
}
]
}
},
"executeOnce": true,
"typeVersion": 4.4
},
{
"id": "0e6e0f02-b7b2-408c-b69a-31e32b401299",
"name": "Separate Customer Entries",
"type": "n8n-nodes-base.splitOut",
"position": [
14464,
3632
],
"parameters": {
"options": {},
"fieldToSplitOut": "contacts"
},
"executeOnce": false,
"typeVersion": 1
},
{
"id": "32a08dfe-2c06-431c-a0c7-487c40a8b0cc",
"name": "Filter by Customer Criteria",
"type": "n8n-nodes-base.filter",
"position": [
14784,
3504
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "5bcb0f26-f8f3-47e0-9d5d-4edd98f66aa5",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.contact_type }}",
"rightValue": "customer"
},
{
"id": "809b6b3b-32f8-4d5c-a98a-065d37484c42",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.status }}",
"rightValue": "active"
}
]
}
},
"executeOnce": false,
"typeVersion": 2.3
},
{
"id": "b2b2ad4d-71d3-4842-b855-1de1d662ce23",
"name": "Combine Invoice and Customer Data",
"type": "n8n-nodes-base.merge",
"position": [
15520,
3152
],
"parameters": {
"mode": "chooseBranch"
},
"typeVersion": 3.2
},
{
"id": "dd32036c-dbb1-4be4-8199-4ec421ecdcc7",
"name": "Combine Tax and Account Information",
"type": "n8n-nodes-base.merge",
"position": [
14464,
3136
],
"parameters": {
"mode": "chooseBranch",
"useDataOfInput": 2
},
"typeVersion": 3.2
},
{
"id": "b5497ada-e4be-4ace-a5b3-67b7afbe51bd",
"name": "Separate Email Attachments",
"type": "n8n-nodes-base.splitOut",
"position": [
13056,
3216
],
"parameters": {
"options": {},
"fieldToSplitOut": "$binary"
},
"typeVersion": 1
},
{
"id": "2b72bbde-5224-4bb0-a975-3aa20b403af3",
"name": "Email IMAP Trigger",
"type": "n8n-nodes-base.emailReadImap",
"position": [
12384,
3216
],
"parameters": {
"format": "resolved",
"options": {
"forceReconnect": 10,
"trackLastMessageId": true
}
},
"typeVersion": 2.1
},
{
"id": "1874a16c-cb96-4fcf-83f8-268ea530b099",
"name": "Filter Emails for Attachments",
"type": "n8n-nodes-base.filter",
"position": [
12832,
3216
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "37de41fd-1d41-4cbc-9182-38cead4b2f8e",
"operator": {
"type": "object",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('Configure Workflow Constants').item.binary }}",
"rightValue": "Yes"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "7fe89cc0-882c-438f-90de-281372251243",
"name": "Retrieve Taxes from ZBooks",
"type": "n8n-nodes-base.httpRequest",
"position": [
13440,
2784
],
"parameters": {
"url": "=https://www.zohoapis.{{ $('Configure Workflow Constants').item.json.zoho_data_center }}/books/v3/settings/taxes?organization_id={{ $('Configure Workflow Constants').item.json.zbooks_org_id }}",
"options": {
"pagination": {
"pagination": {
"parameters": {
"parameters": [
{
"name": "page",
"value": "={{ $response.body.page_context.page+1 }}"
}
]
},
"completeExpression": "={{ !$response.body.page_context.has_more_page }}",
"paginationCompleteWhen": "other"
}
}
},
"authentication": "genericCredentialType",
"genericAuthType": "oAuth2Api"
},
"executeOnce": true,
"typeVersion": 4.3
},
{
"id": "9b2aff3a-0df4-4e28-9464-2fd95305f59b",
"name": "OpenAI Invoice Text Analysis",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
14720,
3136
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5.4-mini",
"cachedResultName": "GPT-5.4-MINI"
},
"options": {
"textFormat": {
"textOptions": {
"type": "json_object"
}
}
},
"responses": {
"values": [
{
"role": "system",
"content": "=Taxes: {{ JSON.stringify($('Retrieve Taxes from ZBooks').all().map((r) => {\n return [\n ...r.json.taxes\n .filter((t) => t.status === 'Active' && !t.is_inactive && t.tax_type === 'tax')\n .map((t) => ({tax_id: t.tax_id, tax_name: t.tax_name, description: t.description, tax_percentage: t.tax_percentage}))\n ]\n })) }}\n\nYou are an expert financial document parser specialized in sales invoices, outgoing invoices, customer billing documents, service invoices, and accounts receivable documents.\n\nYour task is to extract structured data from raw invoice text and return ONLY valid JSON.\n\nThe output must be suitable for creating a Zoho Books invoice.\n\n==================================================\nPRIMARY TASK\n==================================================\n\n1. Determine whether the attachment is a valid CUSTOMER invoice / sales invoice\n2. If valid, extract structured invoice data\n3. Extract customer information separately\n4. If not valid or insufficient data, return:\n - is_valid_invoice = false\n - invoice_data = null where needed\n - customer_data = null where needed\n\nExamples of INVALID documents:\n- offers / proposals\n- reminders without invoice details\n- payment confirmations\n- bank statements\n- delivery notes\n- contracts\n- letters / emails\n- random attachments\n- OCR text with insufficient financial data\n\n==================================================\nSTRICT OUTPUT RULES\n==================================================\n\n- Return ONLY valid JSON\n- No markdown\n- No explanations\n- No comments\n- No extra text\n- Use null for missing values\n- Never hallucinate values\n- Never invent IDs\n- Never guess invoice numbers\n- Never infer totals without evidence\n\n- Dates format: YYYY-MM-DD\n- Monetary values must be numbers only\n- No currency symbols\n- No thousand separators\n- Preserve decimal precision\n\nExample:\n254.10\n\n==================================================\nVALIDITY RULES\n==================================================\n\nSet \"is_valid_invoice\" = true ONLY if the document contains enough evidence of being a sales invoice.\n\nMinimum required indicators:\n- invoice number OR clear identifier\n- invoice date\n- customer / billed party\n- at least one line item OR clear service description\n\nIf fewer than 3 indicators are present:\n- set is_valid_invoice = false\n\n==================================================\nOUTPUT STRUCTURE\n==================================================\n\n{\n \"is_valid_invoice\": boolean,\n \"currency_code\": string,\n \"invoice_data\": {\n \"invoice_number\": string | null,\n \"reference_number\": string | null,\n \"date\": string | null,\n \"due_date\": string | null,\n \"payment_terms\": number | null,\n \"terms\": string | null,\n \"line_items\": [\n {\n \"name\": string | null,\n \"description\": string | null,\n \"quantity\": number | null,\n \"rate\": number | null,\n \"tax_id\": string | null,\n \"unit\": string | null\n }\n ],\n \"adjustment\": double | null,\n \"adjustment_description\": string | null,\n },\n \"customer_data\": {\n \"contact_name\": string | null,\n \"email\": string | null,\n \"phone\": string | null\n },\n}\n\n==================================================\nCURRENCY CODE RULES\n==================================================\nIf the currency used at invoice is ambigious - use null. Else - use ISO 4217 (three letter format) to specify what currency does the invoice contain.\n\n==================================================\nINVOICE DATA EXTRACTION RULES\n==================================================\n\ninvoice_number:\nExtract from:\n- Invoice\n- Invoice No\n- Factuurnummer\n- Invoice Number\n\nreference_number:\nExtract:\n- PO number\n- purchase order\n- reference\n- contract reference\n- customer reference\n\ndate:\nInvoice issue date\n\ndue_date:\nPayment due date\n\npayment_terms:\nIf due date and date both exist, calculate number of days difference\n\nterms:\nExtract payment terms text / legal footer text\n\nadjustment:\nIf there is additional fee/discount and it can't be part of line item - add it as adjustment (amount), and adjustment_description - explaining the reason for the adjustment, which appears on the invoice documents to explain why the adjustment was applied. Examples: \"Rounding adjustment\", \"Handling fee\", \"Early payment discount\", \"Shipping\", etc.\n\n==================================================\nCUSTOMER DATA RULES\n==================================================\n\ncustomer_name:\nThe billed party / recipient of the invoice\n\naddress:\nFull billing address if present\n\nvat_number:\nCustomer VAT / BTW number\n\nemail:\nBilling contact email\n\nphone:\nBilling phone number\n\n==================================================\nLINE ITEMS RULES\n==================================================\n\nAt least one line item required if available\n\nExtract:\n- name\n- description\n- quantity\n- rate\n- tax_id\n- unit\n\nExamples:\n\"Consulting services 10 hrs \u20ac125\"\n\u2192 quantity = 10\n\u2192 rate = 125\n\u2192 unit = \"hrs\"\n\nIf only total exists:\nquantity = 1\nrate = total\n\n==================================================\nFINAL VALIDATION\n==================================================\n\nBefore returning JSON:\n\n1. Ensure JSON is valid\n2. Ensure is_valid_invoice is correctly set\n3. Preserve attachment_id unchanged\n4. Use null for unavailable fields\n5. Output JSON only"
},
{
"content": "={{ $json.output[0].content[0].text }}"
}
]
},
"builtInTools": {}
},
"typeVersion": 2.1
},
{
"id": "465bc47b-dbe3-4739-bb13-86fc73bd4998",
"name": "Validate Invoice Status",
"type": "n8n-nodes-base.filter",
"position": [
15296,
3136
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "4ef87135-7ab0-4eeb-94de-2d6305cf9067",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.is_valid_invoice }}",
"rightValue": false
}
]
}
},
"typeVersion": 2.3
},
{
"id": "465fe556-ea4b-4bcd-b406-8f381cce97e7",
"name": "Retrieve Currencies from ZBooks",
"type": "n8n-nodes-base.httpRequest",
"position": [
13680,
2784
],
"parameters": {
"url": "=https://www.zohoapis.{{ $('Configure Workflow Constants').item.json.zoho_data_center }}/books/v3/settings/currencies?organization_id={{ $('Configure Workflow Constants').item.json.zbooks_org_id }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "oAuth2Api"
},
"executeOnce": true,
"typeVersion": 4.4
},
{
"id": "c4a85516-0916-4237-8b21-43108873171b",
"name": "Format ZBooks Data",
"type": "n8n-nodes-base.set",
"position": [
13952,
2784
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "8f8e3d82-0832-49e2-90fe-2b392dc967b0",
"name": "taxes",
"type": "array",
"value": "={{\n $('Retrieve Taxes from ZBooks').all().map((r) => {\n return [\n ...r.json.taxes\n .filter((t) => t.status === 'Active' && !t.is_inactive && t.tax_type === 'tax')\n .map((t) => ({tax_id: t.tax_id, tax_name: t.tax_name, description: t.description, tax_percentage: t.tax_percentage}))\n ]\n })\n}}"
},
{
"id": "49cc2d72-f249-4328-8840-2e127d2b7de1",
"name": "currencies",
"type": "array",
"value": "={{ $json.currencies }}"
}
]
}
},
"executeOnce": true,
"typeVersion": 3.4
},
{
"id": "9d1a614c-805b-47f4-b186-b6f8279a188b",
"name": "Aggregate Customer Information",
"type": "n8n-nodes-base.aggregate",
"position": [
15072,
3504
],
"parameters": {
"include": "specifiedFields",
"options": {},
"aggregate": "aggregateAllItemData",
"fieldsToInclude": "contact_id, contact_name, email, phone",
"destinationFieldName": "customers"
},
"executeOnce": false,
"typeVersion": 1
},
{
"id": "d975b438-c84f-406d-a78e-f91a05282e7e",
"name": "Assemble Invoice Details",
"type": "n8n-nodes-base.code",
"position": [
15744,
3152
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const priorities = [];\nconst fromEmail = $('Configure Workflow Constants').item.json.from.value[0].address;\n\nif (\n $('Configure Workflow Constants').item.json.useSenderForCustomerLookup &&\n !$('Configure Workflow Constants').item.json.customerLookupIgnoreList[0].includes(fromEmail)\n) priorities.push({ field: 'email', value: fromEmail });\n\npriorities.push(\n { field: 'contact_name', value: $('Prepare Invoice Data').item.json.customer_data.contact_name },\n { field: 'phone', value: $('Prepare Invoice Data').item.json.customer_data.phone?.replace(/\\D/g, '') },\n { field: 'email', value: $('Prepare Invoice Data').item.json.customer_data.email },\n)\nconsole.log({priorities})\nfunction findContact() {\n for (const p of priorities) {\n const match = $('Aggregate Customer Information').first().json.customers.find((v) => {\n if (p.field === 'phone') v[p.field] = v[p.field].toString()?.replace(/\\D/g, '');\n return v[p.field] && v[p.field].toString().toLowerCase() === p.value?.toString()?.toLowerCase();\n });\n if (match) return match;\n }\n return null;\n}\n\nconst matchedContact = findContact();\nconst customer_id = matchedContact ? matchedContact.contact_id : $('Configure Workflow Constants').item.json.unknown_customer_static_id;\n\nreturn {\n json: {\n data: {\n ...$json.invoice_data,\n customer_id,\n notes: \"Generated by n8n.\"\n },\n },\n binary: {data: $('Prepare Files for Scanning').item.binary.attachment}\n};"
},
"typeVersion": 2
},
{
"id": "bcef5494-67a9-46ec-aeff-356fa28f6a9d",
"name": "Configure Workflow Constants",
"type": "n8n-nodes-base.set",
"position": [
12608,
3216
],
"parameters": {
"options": {
"stripBinary": false
},
"assignments": {
"assignments": [
{
"id": "80e23792-e42a-44ba-ade1-57c8ac000b9d",
"name": "zoho_data_center",
"type": "string",
"value": "com"
},
{
"id": "7fe5d870-e119-488d-9131-dfe9afd94dae",
"name": "unknown_customer_static_id",
"type": "string",
"value": ""
},
{
"id": "f50161c3-9e60-4061-91e3-65f84c225bc5",
"name": "zbooks_org_id",
"type": "string",
"value": ""
},
{
"id": "d0952ef3-6163-4840-a469-8e70ea206a8d",
"name": "useSenderForCustomerLookup",
"type": "boolean",
"value": true
},
{
"id": "6551db82-2a4b-4035-bfbd-1f96137c003c",
"name": "customerLookupIgnoreList",
"type": "array",
"value": "={{ ['example@example.com'] }}"
}
]
},
"includeOtherFields": true
},
"executeOnce": false,
"typeVersion": 3.4
},
{
"id": "69ff5a9a-28fc-46a2-8cd5-97ec24f14b2d",
"name": "Submit Document to ZBooks",
"type": "n8n-nodes-base.httpRequest",
"position": [
15968,
3152
],
"parameters": {
"url": "=https://www.zohoapis.{{ $('Configure Workflow Constants').item.json.zoho_data_center }}/books/v3/invoices?organization_id={{ $('Configure Workflow Constants').item.json.zbooks_org_id }}",
"method": "POST",
"options": {},
"sendBody": true,
"sendQuery": true,
"contentType": "multipart-form-data",
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "JSONString",
"value": "={{ JSON.stringify($json.data) }}"
},
{
"name": "attachment",
"parameterType": "formBinaryData",
"inputDataFieldName": "data"
}
]
},
"genericAuthType": "oAuth2Api",
"queryParameters": {
"parameters": [
{
"name": "ignore_auto_number_generation",
"value": "true"
}
]
}
},
"typeVersion": 4.4
},
{
"id": "fb64afbe-843a-406e-8326-195aa9eee87b",
"name": "Combine OCR Outputs",
"type": "n8n-nodes-base.merge",
"position": [
14176,
3152
],
"parameters": {},
"typeVersion": 3.2
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "5a53407b-d69c-4225-842d-29a57a6e3fd9",
"connections": {
"Email IMAP Trigger": {
"main": [
[
{
"node": "Configure Workflow Constants",
"type": "main",
"index": 0
}
]
]
},
"Format ZBooks Data": {
"main": [
[
{
"node": "Combine Tax and Account Information",
"type": "main",
"index": 0
}
]
]
},
"Combine OCR Outputs": {
"main": [
[
{
"node": "Combine Tax and Account Information",
"type": "main",
"index": 1
}
]
]
},
"Prepare Invoice Data": {
"main": [
[
{
"node": "Validate Invoice Status",
"type": "main",
"index": 0
}
]
]
},
"Route by Document Type": {
"main": [
[
{
"node": "OpenAI OCR for PDF Files",
"type": "main",
"index": 0
}
],
[
{
"node": "OpenAI OCR for Image Files",
"type": "main",
"index": 0
}
]
]
},
"Validate Invoice Status": {
"main": [
[
{
"node": "Combine Invoice and Customer Data",
"type": "main",
"index": 0
}
]
]
},
"Assemble Invoice Details": {
"main": [
[
{
"node": "Submit Document to ZBooks",
"type": "main",
"index": 0
}
]
]
},
"OpenAI OCR for PDF Files": {
"main": [
[
{
"node": "Combine OCR Outputs",
"type": "main",
"index": 0
}
]
]
},
"Separate Customer Entries": {
"main": [
[
{
"node": "Filter by Customer Criteria",
"type": "main",
"index": 0
}
]
]
},
"OpenAI OCR for Image Files": {
"main": [
[
{
"node": "Combine OCR Outputs",
"type": "main",
"index": 1
}
]
]
},
"Prepare Files for Scanning": {
"main": [
[
{
"node": "Route by Document Type",
"type": "main",
"index": 0
},
{
"node": "Retrieve Customers from ZBooks",
"type": "main",
"index": 0
},
{
"node": "Retrieve Taxes from ZBooks",
"type": "main",
"index": 0
}
]
]
},
"Retrieve Taxes from ZBooks": {
"main": [
[
{
"node": "Retrieve Currencies from ZBooks",
"type": "main",
"index": 0
}
]
]
},
"Separate Email Attachments": {
"main": [
[
{
"node": "Prepare Files for Scanning",
"type": "main",
"index": 0
}
]
]
},
"Filter by Customer Criteria": {
"main": [
[
{
"node": "Aggregate Customer Information",
"type": "main",
"index": 0
}
]
]
},
"Configure Workflow Constants": {
"main": [
[
{
"node": "Filter Emails for Attachments",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Invoice Text Analysis": {
"main": [
[
{
"node": "Prepare Invoice Data",
"type": "main",
"index": 0
}
]
]
},
"Filter Emails for Attachments": {
"main": [
[
{
"node": "Separate Email Attachments",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Customer Information": {
"main": [
[
{
"node": "Combine Invoice and Customer Data",
"type": "main",
"index": 1
}
]
]
},
"Retrieve Customers from ZBooks": {
"main": [
[
{
"node": "Separate Customer Entries",
"type": "main",
"index": 0
}
]
]
},
"Retrieve Currencies from ZBooks": {
"main": [
[
{
"node": "Format ZBooks Data",
"type": "main",
"index": 0
}
]
]
},
"Combine Invoice and Customer Data": {
"main": [
[
{
"node": "Assemble Invoice Details",
"type": "main",
"index": 0
}
]
]
},
"Combine Tax and Account Information": {
"main": [
[
{
"node": "OpenAI Invoice Text Analysis",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow monitors an IMAP inbox for emails with invoice attachments, uses OpenAI to OCR and extract structured invoice data, looks up customers and tax/currency settings in Zoho Books, and then creates a new Zoho Books invoice with the original attachment included. Triggers…
Source: https://n8n.io/workflows/17198/ — 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.
This workflow automatically runs when a new email is received in the user's Gmail account. It sends the email content to OpenAI (GPT-4.1-mini), which intelligently determines whether the message requi
Use cases are many: Perfect for freelancers managing client invoices, small businesses handling supplier bills, accounting departments processing high invoice volumes, or anyone who wants to eliminate
Supercharge your sales and marketing efforts with this powerful automation that transforms a list of LinkedIn profiles into a fully enriched, personalized outreach campaign. This workflow is designed
This workflow automatically analyzes incoming emails using AI, categorizes them, routes them to the appropriate department, logs the results in Excel 365, and sends notifications to the responsible te
Sales teams, marketers, and business development professionals who need to automatically enrich their CRM records with detailed company information from LinkedIn profiles. Perfect for anyone doing B2B