AutomationFlowsData & Sheets › Verify Polish Vat Taxpayers From Google Sheets with the Biała Lista API

Verify Polish Vat Taxpayers From Google Sheets with the Biała Lista API

BySEVENEDGE @sevenedge on n8n.io

This workflow reads contractor NIP numbers from Google Sheets and checks each one against Poland’s Ministry of Finance VAT “white list” API to verify VAT active status and (optionally) whether a provided bank account is registered, returning a results table plus an…

Event trigger★★★★☆ complexity11 nodesGoogle SheetsHTTP Request
Data & Sheets Trigger: Event Nodes: 11 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #17494 — we link there as the canonical source.

This workflow follows the Google Sheets → 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 →

Download .json
{
  "id": "7z3tSI3Nr3nosLV2",
  "name": "Verify Polish VAT taxpayers (Bia\u0142a lista) from Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "f28aad5c-d64d-4104-8af1-d71887ccd195",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        -160
      ],
      "parameters": {
        "width": 480,
        "height": 864,
        "content": "## Verify Polish VAT taxpayers (Bia\u0142a lista) from Google Sheets\n\n### How it works\n\nThis workflow verifies Polish VAT taxpayers from a Google Sheets contractor list against the Ministry of Finance Bia\u0142a lista API. It can be started manually or on a weekday schedule, reads contractor data, normalizes and validates NIP numbers, calls the API, and turns the response into a plain verdict.\n\n### Setup steps\n\n- Configure Google Sheets credentials for the Read contractors node and select the spreadsheet/range containing contractor data.\n- Update the Settings node with the correct whiteListApi endpoint and the column names for NIP, contractor name, and bank account.\n- Confirm the weekday schedule time and timezone on the Every weekday 7:00 trigger, or use the manual trigger for ad hoc checks.\n- Review the Prepare NIPs and Evaluate results code nodes if your sheet uses different formatting or you need different output fields.\n\n### Customization\n\nAdjust the Settings node to point to different sheet columns or API environments, change the schedule frequency, or extend the evaluation code to write results back to Google Sheets, send alerts, or include bank-account matching."
      },
      "typeVersion": 1
    },
    {
      "id": "58b29a33-d9ee-4ca4-b06c-418026fd00eb",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        800,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 496,
        "content": "## Start and configure\n\nContains the manual and weekday scheduled triggers, then centralizes runtime settings such as the Bia\u0142a lista API URL and spreadsheet column names."
      },
      "typeVersion": 1
    },
    {
      "id": "3f707231-6f1b-4b48-ae65-8f83f4bc5f2b",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1248,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 336,
        "content": "## Read and prepare NIPs\n\nReads contractor rows from Google Sheets and normalizes the NIP values from the configured column, including checksum validation before lookup."
      },
      "typeVersion": 1
    },
    {
      "id": "4d4efb7c-b9d6-4913-b85e-8209ef87db48",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1712,
        -64
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 320,
        "content": "## Check and evaluate taxpayers\n\nQueries the Ministry of Finance white list API for each prepared NIP and converts the response into a clear taxpayer verification verdict."
      },
      "typeVersion": 1
    },
    {
      "id": "1e04ee2a-f68a-4b4f-9af6-f0cc866ded05",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        864,
        16
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "915efa21-7453-4a57-8766-07401849272b",
      "name": "Schedule Weekdays at 7am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        864,
        176
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 7 * * 1-5"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "12cde684-d93a-4eb3-ae19-252a2575b98c",
      "name": "Set API and Columns",
      "type": "n8n-nodes-base.set",
      "position": [
        1072,
        96
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "0",
              "name": "whiteListApi",
              "type": "string",
              "value": "https://wl-api.mf.gov.pl/api/search/nip/"
            },
            {
              "id": "1",
              "name": "nipColumn",
              "type": "string",
              "value": "NIP"
            },
            {
              "id": "2",
              "name": "nameColumn",
              "type": "string",
              "value": "Company"
            },
            {
              "id": "3",
              "name": "accountColumn",
              "type": "string",
              "value": "Bank account"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d5dceeb9-c10c-426e-a4a5-9790056e95db",
      "name": "Read Contractors from Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Select your spreadsheet and worksheet here.",
      "position": [
        1296,
        96
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "bc02ed65-7f8e-4f79-884e-9f6935ca1e47",
      "name": "Normalize and Validate NIPs",
      "type": "n8n-nodes-base.code",
      "position": [
        1520,
        96
      ],
      "parameters": {
        "jsCode": "// Normalise NIP numbers coming from the spreadsheet and validate the checksum.\n// A malformed NIP is rejected locally, so we never waste an API call on it.\nconst cfg = $('Set API and Columns').first().json;\nconst column = cfg.nipColumn || 'NIP';\n\nfunction checksumOk(nip) {\n  if (!/^\\d{10}$/.test(nip)) return false;\n  const w = [6, 5, 7, 2, 3, 4, 5, 6, 7];\n  const sum = w.reduce((acc, weight, i) => acc + weight * Number(nip[i]), 0);\n  return sum % 11 === Number(nip[9]);\n}\n\nconst out = [];\nfor (const item of $input.all()) {\n  const row = item.json;\n  const raw = String(row[column] ?? '').replace(/[^0-9]/g, '');\n  out.push({\n    json: {\n      ...row,\n      nip: raw,\n      nip_valid_format: checksumOk(raw),\n      row_number: row.row_number ?? null,\n    },\n  });\n}\nreturn out;"
      },
      "typeVersion": 2
    },
    {
      "id": "69059b30-1e02-4d5f-8f7e-d3c301ab7b1a",
      "name": "Fetch VAT White List Status",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        1760,
        96
      ],
      "parameters": {
        "url": "={{ $('Set API and Columns').first().json.whiteListApi }}{{ $json.nip }}?date={{ $now.format('yyyy-MM-dd') }}",
        "options": {
          "timeout": 20000,
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 1200
            }
          }
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "025266f5-e27f-4813-9a47-fff5027ac38e",
      "name": "Determine VAT Compliance Status",
      "type": "n8n-nodes-base.code",
      "position": [
        2000,
        96
      ],
      "parameters": {
        "jsCode": "// Turn the Ministry of Finance response into a plain verdict.\n// The API answers with { result: { subject: {...} } } \u2014 an ACTIVE taxpayer has\n// statusVat = \"Czynny\". Anything else means: do not pay yet.\nconst cfg = $('Set API and Columns').first().json;\nconst inputs = $('Normalize and Validate NIPs').all().map(i => i.json);\nconst results = $input.all().map(i => i.json);\n\nconst rows = [];\nfor (let i = 0; i < inputs.length; i++) {\n  const src = inputs[i];\n  const res = results[i] || {};\n  const subject = res?.result?.subject || null;\n\n  let verdict, detail;\n  if (!src.nip_valid_format) {\n    verdict = 'INVALID_NIP';\n    detail = 'Checksum failed \u2014 the number is not a valid Polish NIP.';\n  } else if (!subject) {\n    verdict = 'NOT_FOUND';\n    detail = 'No taxpayer found for this NIP on the given date.';\n  } else if (subject.statusVat === 'Czynny') {\n    verdict = 'ACTIVE';\n    detail = subject.name || '';\n  } else {\n    verdict = 'NOT_ACTIVE';\n    detail = `statusVat = ${subject.statusVat || 'unknown'}`;\n  }\n\n  const accounts = Array.isArray(subject?.accountNumbers) ? subject.accountNumbers : [];\n  const expected = String(src[cfg.accountColumn || 'Bank account'] || '').replace(/[^0-9]/g, '');\n  const accountOk = !expected ? null : accounts.some(a => String(a).replace(/[^0-9]/g, '') === expected);\n\n  rows.push({ json: {\n    nip: src.nip,\n    company: subject?.name || src[cfg.nameColumn || 'Company'] || '',\n    verdict,\n    detail,\n    account_on_white_list: accountOk,\n    registration_legal_date: subject?.registrationLegalDate || null,\n    checked_at: new Date().toISOString(),\n    row_number: src.row_number,\n  }});\n}\n\nconst problems = rows.filter(r => r.json.verdict !== 'ACTIVE' || r.json.account_on_white_list === false);\nif (problems.length) {\n  rows.unshift({ json: {\n    summary: true,\n    checked: rows.length,\n    problems: problems.length,\n    message: `${problems.length} of ${rows.length} contractors need attention before payment.`,\n  }});\n}\nreturn rows;"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "0a3b0d55-f03a-49b5-9d1e-6be93f417f48",
  "nodeGroups": [],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Set API and Columns",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set API and Columns": {
      "main": [
        [
          {
            "node": "Read Contractors from Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Weekdays at 7am": {
      "main": [
        [
          {
            "node": "Set API and Columns",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch VAT White List Status": {
      "main": [
        [
          {
            "node": "Determine VAT Compliance Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize and Validate NIPs": {
      "main": [
        [
          {
            "node": "Fetch VAT White List Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Contractors from Sheets": {
      "main": [
        [
          {
            "node": "Normalize and Validate NIPs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow reads contractor NIP numbers from Google Sheets and checks each one against Poland’s Ministry of Finance VAT “white list” API to verify VAT active status and (optionally) whether a provided bank account is registered, returning a results table plus an…

Source: https://n8n.io/workflows/17494/ — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

TrackCollect_deeper. Uses googleSheets, httpRequest, @n-octo-n/n8n-nodes-json-database, itemLists. Event-driven trigger; 80 nodes.

Google Sheets, HTTP Request, @N Octo N/N8N Nodes Json Database +1
Data & Sheets

This template is ideal for solo store owners, eCommerce marketers, automation beginners, or anyone using Shopify and Gmail who wants to recover lost revenue without coding.

HTTP Request, Gmail, Twilio +3
Data & Sheets

PCN. Uses googleSheets, httpRequest, @n-octo-n/n8n-nodes-json-database, itemLists. Event-driven trigger; 60 nodes.

Google Sheets, HTTP Request, @N Octo N/N8N Nodes Json Database +3
Data & Sheets

Product Ad Machine. Uses googleDrive, googleSheets, httpRequest, @ffmpeg-micro/n8n-nodes-ffmpeg-micro. Event-driven trigger; 60 nodes.

Google Drive, Google Sheets, HTTP Request +2
Data & Sheets

Basic AI SEO KW Research n8n DataForSEO Gumroad 030125. Uses googleSheets, googleDrive, httpRequest. Event-driven trigger; 56 nodes.

Google Sheets, Google Drive, HTTP Request