{
  "id": "jjHhqwplpaGh6V3b",
  "name": "Extract invoice data from PDF with Claude AI and create vendor bill in Odoo 18",
  "tags": [],
  "nodes": [
    {
      "id": "0bd4b266-d85d-40c5-bbea-278d23dba904",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -976,
        768
      ],
      "parameters": {
        "color": "#FFF5D6",
        "width": 940,
        "height": 1072,
        "content": "## Extract Invoice Data from PDF with Claude AI and Create Vendor Bill in Odoo 18\n\nThis workflow automates **accounts payable**: upload a PDF invoice, let Claude AI extract the key fields, and automatically create a vendor bill (incoming invoice) in Odoo 18.\n\n## Who is this for?\nSmall and medium businesses using Odoo 18 who want to automate invoice data entry. Finance teams, bookkeepers, or anyone processing incoming invoices manually.\n\n## How it works\n1. Receive a PDF invoice via webhook (file upload)\n2. Convert the PDF to base64 for AI processing\n3. Claude AI extracts: vendor name, invoice number, date, amounts, tax rate\n4. Authenticate with Odoo 18 via JSON-RPC API\n5. Check for duplicate invoices (by invoice number)\n6. Find or create the vendor (res.partner) in Odoo\n7. Create a **draft** vendor bill (account.move) in Odoo\n8. Return a structured JSON response with the result\n\nThe invoice is created in **draft status** so you can review and confirm it manually in Odoo before posting.\n\n## Extracted fields\n`vendor`, `invoice_number`, `invoice_date`, `total_amount`, `currency`, `net_amount`, `tax_rate`, `tax_amount`\n\n## Setup\n- [ ] Open the **Configuration** node and enter your Odoo URL, database, user, and password\n- [ ] Create an **HTTP Header Auth** credential named `Anthropic API Key` with header name `x-api-key` and your Anthropic API key as value\n- [ ] Activate the workflow and send a test PDF\n\n## Test with curl\n```\ncurl -X POST https://your-n8n-instance.com/webhook/invoice-process -F \"data=@invoice.pdf\"\n```\n\n## Requirements\n- Odoo 18 with Invoicing module installed\n- Anthropic API key (Claude Sonnet 4.5 recommended)\n- n8n 2.x (self-hosted or cloud)\n\n## How to customize\n- Change the AI model in the **Configuration** node (e.g. `claude-haiku-4-5-20251001` for lower cost)\n- Modify the extraction prompt in **Prepare Claude Request** to add custom fields\n- Add a file storage step after invoice creation (e.g. Google Drive, S3, WebDAV)\n- Connect an email trigger instead of the webhook for fully automated processing\n\n## Note on data privacy\nThis workflow sends PDF documents to the Anthropic API for data extraction. Ensure you have a [Data Processing Agreement (DPA)](https://www.anthropic.com/legal/data-processing-addendum) with Anthropic and comply with your local data protection regulations (e.g. GDPR) before processing documents containing personal data.\n\n**Author:** Florian Eiche \u2014 [eiche-digital.de](https://eiche-digital.de)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c3c7da18-0bac-49d8-9562-f768a3b4b244",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        1232
      ],
      "parameters": {
        "color": "#737373",
        "width": 1340,
        "height": 312,
        "content": "## 1. PDF Upload & AI Extraction\nThe webhook receives a PDF file upload. The file is converted to base64, then sent to Claude AI with a structured extraction prompt. Claude returns JSON with all invoice fields."
      },
      "typeVersion": 1
    },
    {
      "id": "45f83c7f-4d07-47f9-945d-bc6a24de23e1",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1360,
        1232
      ],
      "parameters": {
        "color": "#737373",
        "width": 1172,
        "height": 312,
        "content": "## 2. Odoo Authentication & Duplicate Check\nAuthenticate via JSON-RPC, then search for existing invoices with the same reference number. If a duplicate is found, the workflow returns a clean response instead of creating a duplicate."
      },
      "typeVersion": 1
    },
    {
      "id": "10c75ce5-79a5-4600-a7c8-0d20f7b327a2",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2544,
        1232
      ],
      "parameters": {
        "color": "#737373",
        "width": 1404,
        "height": 568,
        "content": "## 3. Vendor Lookup & Creation\nSearch for the vendor by name in Odoo. If found, use the existing partner. If not, create a new vendor (res.partner) with `supplier_rank: 1`."
      },
      "typeVersion": 1
    },
    {
      "id": "b75880da-c3df-4e65-b7cb-d366d1da377b",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3968,
        1232
      ],
      "parameters": {
        "color": "#737373",
        "width": 1044,
        "height": 568,
        "content": "## 4. Invoice Creation & Response\nCreate a draft vendor bill (account.move with move_type `in_invoice`) in Odoo. The invoice is created with one line containing the net amount. Returns a JSON response with the Odoo invoice ID."
      },
      "typeVersion": 1
    },
    {
      "id": "bf398631-cba8-45af-9934-38ef17a3d88c",
      "name": "Receive Invoice PDF",
      "type": "n8n-nodes-base.webhook",
      "position": [
        64,
        1376
      ],
      "parameters": {
        "path": "invoice-process",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "057afa8e-248a-452e-8894-96ece1c0a752",
      "name": "PDF to Base64",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        320,
        1376
      ],
      "parameters": {
        "options": {},
        "operation": "binaryToPropery"
      },
      "typeVersion": 1
    },
    {
      "id": "eb9426eb-cc78-473c-9bab-21aa3a736b99",
      "name": "Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        592,
        1376
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"odooUrl\": \"https://your-odoo-instance.com\",\n  \"odooDb\": \"your_database_name\",\n  \"odooUser\": \"admin\",\n  \"odooPassword\": \"your_password_here\",\n  \"anthropicModel\": \"claude-sonnet-4-5-20250929\"\n}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "67de80c2-861b-4127-8f1e-bd5cc6b3a6d4",
      "name": "Prepare Claude Request",
      "type": "n8n-nodes-base.code",
      "position": [
        864,
        1376
      ],
      "parameters": {
        "jsCode": "// Build Anthropic API request with PDF as base64 document\nconst base64Item = $('PDF to Base64').first().json;\nconst pdfBase64 = base64Item.data;\n\nif (!pdfBase64 || pdfBase64.length < 100) {\n  throw new Error('No valid PDF data received. Length: ' + (pdfBase64 ? pdfBase64.length : 0));\n}\n\nconst config = $('Configuration').first().json;\n\nconst requestBody = {\n  model: config.anthropicModel || 'claude-sonnet-4-5-20250929',\n  max_tokens: 1024,\n  messages: [{\n    role: 'user',\n    content: [\n      {\n        type: 'document',\n        source: {\n          type: 'base64',\n          media_type: 'application/pdf',\n          data: pdfBase64\n        }\n      },\n      {\n        type: 'text',\n        text: 'Extract the following fields from this invoice and return ONLY valid JSON, no markdown, no explanation:\\n\\n{\\n  \"vendor\": \"Name of the vendor/sender\",\\n  \"invoice_number\": \"Invoice number\",\\n  \"invoice_date\": \"YYYY-MM-DD\",\\n  \"total_amount\": 0.00,\\n  \"currency\": \"EUR\",\\n  \"net_amount\": 0.00,\\n  \"tax_rate\": 19,\\n  \"tax_amount\": 0.00\\n}\\n\\nIf a field is not found, set it to null.'\n      }\n    ]\n  }]\n};\n\nreturn [{ json: { requestBody } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "5fba2aef-0212-4817-b5d4-c89e9011ee95",
      "name": "Claude AI Extract",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        1152,
        1376
      ],
      "parameters": {
        "url": "https://api.anthropic.com/v1/messages",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.requestBody) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "4fffd0e5-cbd0-4ecf-a400-b4bdf41d29c8",
      "name": "Parse Extraction",
      "type": "n8n-nodes-base.code",
      "position": [
        1392,
        1376
      ],
      "parameters": {
        "jsCode": "// Parse and validate Claude AI response\nconst response = $input.first().json;\n\nif (response.error) {\n  throw new Error('Claude API error: ' + (response.error.message || JSON.stringify(response.error)));\n}\n\nconst text = response.content?.[0]?.text || '';\n\nlet invoice;\ntry {\n  const cleaned = text.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n  invoice = JSON.parse(cleaned);\n} catch (e) {\n  throw new Error('Claude response is not valid JSON: ' + text.substring(0, 300));\n}\n\n// Validate required fields\nconst required = ['vendor', 'invoice_number', 'invoice_date', 'total_amount'];\nconst missing = required.filter(f => !invoice[f] && invoice[f] !== 0);\nif (missing.length > 0) {\n  throw new Error('Missing required fields: ' + missing.join(', '));\n}\n\n// Normalize numeric values\ninvoice.total_amount = parseFloat(invoice.total_amount);\ninvoice.net_amount = invoice.net_amount ? parseFloat(invoice.net_amount) : invoice.total_amount;\ninvoice.tax_amount = invoice.tax_amount ? parseFloat(invoice.tax_amount) : 0;\ninvoice.tax_rate = invoice.tax_rate ? parseFloat(invoice.tax_rate) : 0;\ninvoice.currency = invoice.currency || 'EUR';\n\nreturn [{ json: invoice }];"
      },
      "typeVersion": 2
    },
    {
      "id": "3011122b-d5df-4492-a4ae-9703aed98373",
      "name": "Odoo Authenticate",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        1648,
        1376
      ],
      "parameters": {
        "url": "={{ $('Configuration').first().json.odooUrl }}/jsonrpc",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ jsonrpc: '2.0', method: 'call', params: { service: 'common', method: 'authenticate', args: [$('Configuration').first().json.odooDb, $('Configuration').first().json.odooUser, $('Configuration').first().json.odooPassword, {}] }, id: 1 }) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "72c9312e-7ed7-4131-a1d5-b342cf5b3386",
      "name": "Prepare Duplicate Check",
      "type": "n8n-nodes-base.code",
      "position": [
        1904,
        1376
      ],
      "parameters": {
        "jsCode": "// Verify Odoo auth and prepare duplicate check\nconst authResult = $input.first().json;\nif (!authResult.result || authResult.error) {\n  throw new Error('Odoo authentication failed: ' + JSON.stringify(authResult.error || 'uid is null'));\n}\n\nconst uid = authResult.result;\nconst config = $('Configuration').first().json;\nconst invoice = $('Parse Extraction').first().json;\n\n// Search for existing invoice with same reference number\nconst dupCheckBody = {\n  jsonrpc: '2.0',\n  method: 'call',\n  params: {\n    service: 'object',\n    method: 'execute_kw',\n    args: [\n      config.odooDb,\n      uid,\n      config.odooPassword,\n      'account.move',\n      'search_read',\n      [[['ref', '=', invoice.invoice_number], ['move_type', '=', 'in_invoice']]],\n      { fields: ['id', 'ref', 'partner_id', 'state', 'amount_total'], limit: 1 }\n    ]\n  },\n  id: 10\n};\n\nreturn [{ json: { uid, dupCheckBody, invoice } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "f3fe614e-b5d0-4a65-bf9d-124db82c9384",
      "name": "Search Duplicate Invoice",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2144,
        1376
      ],
      "parameters": {
        "url": "={{ $('Configuration').first().json.odooUrl }}/jsonrpc",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.dupCheckBody) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "50f05a19-ad7d-4596-befd-5612e8781bba",
      "name": "Duplicate Found?",
      "type": "n8n-nodes-base.if",
      "position": [
        2384,
        1376
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition-duplicate-exists",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.result.length }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "ebbb50ce-d57a-4876-b44f-4557ef378cd5",
      "name": "Handle Duplicate",
      "type": "n8n-nodes-base.code",
      "position": [
        2624,
        1376
      ],
      "parameters": {
        "jsCode": "// Duplicate found \u2014 return clean response\nconst dupResult = $('Search Duplicate Invoice').first().json.result[0];\nconst invoice = $('Prepare Duplicate Check').first().json.invoice;\n\nreturn [{\n  json: {\n    success: false,\n    duplicate: true,\n    message: 'Invoice ' + invoice.invoice_number + ' already exists in Odoo.',\n    existing_invoice: {\n      odoo_id: dupResult.id,\n      status: dupResult.state,\n      amount: dupResult.amount_total,\n      vendor: dupResult.partner_id ? dupResult.partner_id[1] : null\n    },\n    extracted_data: invoice\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "abac0d06-aaea-43d7-bf2c-3cc833de45a0",
      "name": "Prepare Vendor Search",
      "type": "n8n-nodes-base.code",
      "position": [
        2624,
        1536
      ],
      "parameters": {
        "jsCode": "// No duplicate \u2014 prepare vendor search\nconst prev = $('Prepare Duplicate Check').first().json;\nconst config = $('Configuration').first().json;\n\nconst searchBody = {\n  jsonrpc: '2.0',\n  method: 'call',\n  params: {\n    service: 'object',\n    method: 'execute_kw',\n    args: [\n      config.odooDb,\n      prev.uid,\n      config.odooPassword,\n      'res.partner',\n      'search_read',\n      [[['name', 'ilike', prev.invoice.vendor], ['supplier_rank', '>', 0]]],\n      { fields: ['id', 'name'], limit: 1 }\n    ]\n  },\n  id: 2\n};\n\nreturn [{ json: { uid: prev.uid, searchBody, invoice: prev.invoice } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "eaff093f-d675-4a21-bd52-76df146eb9b6",
      "name": "Search Vendor",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2864,
        1536
      ],
      "parameters": {
        "url": "={{ $('Configuration').first().json.odooUrl }}/jsonrpc",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.searchBody) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "daeb5b81-3552-4797-bfa7-0b1bc8c26d1b",
      "name": "Vendor Exists?",
      "type": "n8n-nodes-base.if",
      "position": [
        3104,
        1376
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition-vendor-exists",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.result.length }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "ffd976ba-0a8c-4774-9adf-592736a0fcfd",
      "name": "Use Existing Vendor",
      "type": "n8n-nodes-base.code",
      "position": [
        3344,
        1360
      ],
      "parameters": {
        "jsCode": "// Use existing vendor\nconst partnerId = $json.result[0].id;\nconst partnerName = $json.result[0].name;\nconst prev = $('Prepare Vendor Search').first().json;\n\nreturn [{\n  json: {\n    partnerId,\n    partnerName,\n    uid: prev.uid,\n    invoice: prev.invoice\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "c34dd409-5f06-4417-8cf4-e3537d607158",
      "name": "Prepare Create Vendor",
      "type": "n8n-nodes-base.code",
      "position": [
        3344,
        1488
      ],
      "parameters": {
        "jsCode": "// Vendor not found \u2014 prepare creation\nconst config = $('Configuration').first().json;\nconst prev = $('Prepare Vendor Search').first().json;\n\nconst createBody = {\n  jsonrpc: '2.0',\n  method: 'call',\n  params: {\n    service: 'object',\n    method: 'execute_kw',\n    args: [\n      config.odooDb,\n      prev.uid,\n      config.odooPassword,\n      'res.partner',\n      'create',\n      [{ name: prev.invoice.vendor, supplier_rank: 1, company_type: 'company' }]\n    ]\n  },\n  id: 3\n};\n\nreturn [{ json: { createBody, uid: prev.uid, invoice: prev.invoice } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "29db158d-d227-450f-a8e0-53eaa894a00f",
      "name": "Create Vendor in Odoo",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3584,
        1488
      ],
      "parameters": {
        "url": "={{ $('Configuration').first().json.odooUrl }}/jsonrpc",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.createBody) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "25137c82-5c80-4a18-82c0-9011da543f5e",
      "name": "Get New Vendor ID",
      "type": "n8n-nodes-base.code",
      "position": [
        3792,
        1488
      ],
      "parameters": {
        "jsCode": "// Extract new vendor ID from create response\nconst result = $input.first().json;\nif (!result.result) {\n  throw new Error('Failed to create vendor: ' + JSON.stringify(result.error || result));\n}\n\nconst prev = $('Prepare Create Vendor').first().json;\n\nreturn [{\n  json: {\n    partnerId: result.result,\n    partnerName: prev.invoice.vendor,\n    uid: prev.uid,\n    invoice: prev.invoice\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "a33d9edb-8a89-413e-8e64-8fd330a2720a",
      "name": "Prepare Invoice",
      "type": "n8n-nodes-base.code",
      "position": [
        4048,
        1360
      ],
      "parameters": {
        "jsCode": "// Prepare Odoo vendor bill (account.move)\nconst data = $input.first().json;\nconst config = $('Configuration').first().json;\n\nconst invoiceBody = {\n  jsonrpc: '2.0',\n  method: 'call',\n  params: {\n    service: 'object',\n    method: 'execute_kw',\n    args: [\n      config.odooDb,\n      data.uid,\n      config.odooPassword,\n      'account.move',\n      'create',\n      [{\n        move_type: 'in_invoice',\n        partner_id: data.partnerId,\n        ref: data.invoice.invoice_number,\n        invoice_date: data.invoice.invoice_date,\n        invoice_line_ids: [\n          [0, 0, {\n            name: 'Invoice ' + data.invoice.invoice_number + ' - ' + data.invoice.vendor,\n            quantity: 1,\n            price_unit: data.invoice.net_amount\n          }]\n        ]\n      }]\n    ]\n  },\n  id: 4\n};\n\nreturn [{\n  json: {\n    invoiceBody,\n    partnerId: data.partnerId,\n    partnerName: data.partnerName,\n    uid: data.uid,\n    invoice: data.invoice\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "696ad174-97fd-493f-acee-5475b99ca5be",
      "name": "Create Invoice in Odoo",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        4288,
        1504
      ],
      "parameters": {
        "url": "={{ $('Configuration').first().json.odooUrl }}/jsonrpc",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.invoiceBody) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "19a84d9f-9c13-4ed6-942a-5118bb66a8aa",
      "name": "Build Response",
      "type": "n8n-nodes-base.code",
      "position": [
        4528,
        1360
      ],
      "parameters": {
        "jsCode": "// Verify invoice creation and build success response\nconst result = $input.first().json;\nif (!result.result) {\n  throw new Error('Failed to create invoice: ' + JSON.stringify(result.error || result));\n}\n\nconst prev = $('Prepare Invoice').first().json;\n\nreturn [{\n  json: {\n    success: true,\n    odoo_invoice_id: result.result,\n    partner_id: prev.partnerId,\n    partner_name: prev.partnerName,\n    invoice: prev.invoice\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "3ccdd767-939e-4d60-b867-71eb57bac30e",
      "name": "Success Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        4768,
        1360
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}"
      },
      "typeVersion": 1
    },
    {
      "id": "dcedaa35-36c5-4ac0-b990-caf9cc6e7b72",
      "name": "Duplicate Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2864,
        1376
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}"
      },
      "typeVersion": 1
    },
    {
      "id": "d511e2fd-8ca9-441c-8c16-9059f6170ae3",
      "name": "Error Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1808,
        1744
      ],
      "parameters": {
        "options": {
          "responseCode": 500
        },
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ success: false, error: $json.error?.message || $json.message || 'Unknown error', node: $json.node || 'unknown' }) }}"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "9e93180c-b647-4acd-a020-827012ae57ec",
  "connections": {
    "Configuration": {
      "main": [
        [
          {
            "node": "Prepare Claude Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PDF to Base64": {
      "main": [
        [
          {
            "node": "Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Vendor": {
      "main": [
        [
          {
            "node": "Vendor Exists?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Response": {
      "main": [
        [
          {
            "node": "Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Vendor Exists?": {
      "main": [
        [
          {
            "node": "Use Existing Vendor",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Create Vendor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Invoice": {
      "main": [
        [
          {
            "node": "Create Invoice in Odoo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Duplicate Found?": {
      "main": [
        [
          {
            "node": "Handle Duplicate",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Vendor Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handle Duplicate": {
      "main": [
        [
          {
            "node": "Duplicate Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Extraction": {
      "main": [
        [
          {
            "node": "Odoo Authenticate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude AI Extract": {
      "main": [
        [
          {
            "node": "Parse Extraction",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get New Vendor ID": {
      "main": [
        [
          {
            "node": "Prepare Invoice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Odoo Authenticate": {
      "main": [
        [
          {
            "node": "Prepare Duplicate Check",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Invoice PDF": {
      "main": [
        [
          {
            "node": "PDF to Base64",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Use Existing Vendor": {
      "main": [
        [
          {
            "node": "Prepare Invoice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Vendor in Odoo": {
      "main": [
        [
          {
            "node": "Get New Vendor ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Create Vendor": {
      "main": [
        [
          {
            "node": "Create Vendor in Odoo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Vendor Search": {
      "main": [
        [
          {
            "node": "Search Vendor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Invoice in Odoo": {
      "main": [
        [
          {
            "node": "Build Response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Claude Request": {
      "main": [
        [
          {
            "node": "Claude AI Extract",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Duplicate Check": {
      "main": [
        [
          {
            "node": "Search Duplicate Invoice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Duplicate Invoice": {
      "main": [
        [
          {
            "node": "Duplicate Found?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}