Skip to content

In n8n, copy this file and paste it onto the canvas, or use Import from File.

{
  "name": "07 - Invoice and Receipt Extractor (starter)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "receipt",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "m07-webhook",
      "name": "Receipt API",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        100
      ],
      "webhookId": "course-07-receipt"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "b1",
              "leftValue": "={{ Object.values($binary ?? {}).some(f => f.mimeType === 'application/pdf') }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "m07-haspdf",
      "name": "Has PDF?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        220,
        100
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ { error: 'upload a PDF as multipart form-data, e.g. curl -F file=@receipt.pdf' } }}",
        "options": {
          "responseCode": 400
        }
      },
      "id": "m07-400",
      "name": "Respond No PDF",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        440,
        260
      ]
    },
    {
      "parameters": {
        "operation": "pdf",
        "binaryPropertyName": "={{ Object.keys($binary).find(k => $binary[k].mimeType === 'application/pdf') }}",
        "options": {
          "joinPages": true,
          "maxPages": 5
        }
      },
      "id": "m07-extract",
      "name": "Extract PDF Text",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1.1,
      "position": [
        440,
        0
      ]
    },
    {
      "parameters": {
        "content": "## Your task\n1. Run the workflow with `curl -F file=@assets/sample-receipt.pdf` and look at **Extract PDF Text**'s output.\n2. Add an **Information Extractor** (schema from a JSON example) + **OpenAI Chat Model** to pull vendor, invoice_number, date, currency, subtotal, tax, total, category, line_items.\n3. Clean the values (numbers, uppercase currency, `needs_review` flag).\n4. Unless `?dry_run=true`, append to an **Expenses** Google Sheet. Respond with the result.\n\nTest: `WITH_CREDS=1 ./test/test.sh`",
        "height": 260,
        "width": 420
      },
      "id": "starter-task-note",
      "name": "Your Task",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -340
      ]
    }
  ],
  "connections": {
    "Receipt API": {
      "main": [
        [
          {
            "node": "Has PDF?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has PDF?": {
      "main": [
        [
          {
            "node": "Extract PDF Text",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond No PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract PDF Text": {
      "main": [
        []
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  }
}