cd /news/developer-tools/checking-polish-companies-from-code-… · home topics developer-tools article
[ARTICLE · art-107984] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Checking Polish companies from code: VAT, KRS, REGON, EU VAT (REST + Python + MCP)

A developer launched skanfirmy.pl, a free REST API and MCP server that aggregates Polish company verification data from the Ministry of Finance, KRS, GUS, and EU VIES into simple JSON endpoints. The service checks VAT status, white-list bank accounts, REGON data, and EU VAT numbers, and includes an MCP server for agent integration and a monitoring feature with HMAC-signed webhooks.

read3 min views1 publishedAug 23, 2026

If you invoice or onboard Polish companies, sooner or later you have to check two dull things that turn out to matter a lot: is this company actually a registered VAT payer, and is the bank account they gave you the one that's on the government's official white list ("Biała Lista")? Both of those affect whether you can deduct the cost and reclaim VAT, so it's not really optional.

The annoying part is that the data lives in four different places: the Ministry of Finance, the KRS court register, GUS (the stats office), and the EU's VIES service. Each one has its own API and its own quirks.

I got tired of gluing those together every time, so I wrapped them behind a few plain HTTP calls that return JSON. Full disclosure: skanfirmy.pl is mine. It's free, no key, no signup, and the web layer runs client-side with no tracking. Here's how you'd actually use it.

Cheapest thing you can do is check a NIP (the tax ID):

curl https://skanfirmy.pl/nip/5260250995

You get back the VAT status (active, exempt, or not registered), the company details from the VAT register, and the accounts sitting on the white list.

The paths:

GET /nip/{nip}

gives VAT status + white-list data for one NIPGET /nips/{list}

takes several NIPs at once (comma-separated)GET /regon/{nip}

returns data from the REGON register (GUS)GET /vies/{country}/{number}

validates an EU VAT number, e.g. /vies/DE/811128135

It's a plain GET that returns JSON, so it drops into anything that can make an HTTP request: a cron job, a lambda, a CI step, whatever.

requests

and a few lines. This one raises if the company isn't an active VAT payer:

import requests

def check_vat(nip: str) -> dict:
    r = requests.get(f"https://skanfirmy.pl/nip/{nip}", timeout=10)
    r.raise_for_status()
    data = r.json()
    status = data.get("vatStatus") or data.get("status")
    if status != "Czynny":  # status comes back in Polish; compare against the raw value
        raise ValueError(f"NIP {nip}: VAT status = {status!r}")
    return data

result = check_vat("5260250995")
print("White-list accounts:", result.get("accountNumbers", []))

One thing that bit me: the status strings from the Ministry come back in Polish (Czynny

= active, Zwolniony

= exempt). Compare against the original string, and don't translate before you branch on it, or the check silently breaks the day someone flips the UI language.

Got a big list to run? Use GET /nips/{list}

, or the /bulk page if you just need a CSV once.

This is the part I actually built the thing for. There's an MCP server at https://skanfirmy.pl/mcp

with 9 tools and no API key, so an agent (say, an accounting assistant) can run the same NIP check a human would click through.

JSON-RPC 2.0 over POST. Calling a tool:

curl -X POST https://skanfirmy.pl/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "sprawdz_nip",
      "arguments": { "nip": "5260250995" }
    }
  }'

tools/list

gives you all of them with their input schemas. If your agent only speaks REST, there's an llms.txt

at https://skanfirmy.pl/llms.txt

describing the endpoints in a model-readable way. And if you need more than the Polish registers, I keep a sister catalog of public APIs aimed at agents over at otwarteapi.pl.

VAT status and white-list accounts change, sometimes day to day, and a one-off check won't tell you when that happens. So there's /monitoring: it diffs daily and pings you over an HMAC-signed webhook when something moves. You verify the signature on your end and react, instead of polling the registers in a loop.

curl for a quick look, requests

to put it in code, MCP if an agent is doing the checking. All JSON, no signup, no key. (It's bilingual too: English pages live under /en/

, and the REST/MCP endpoints don't care about language either way.)

If you're already solving this differently, especially the white-list account matching, I'd genuinely like to hear how. That part is fiddlier than it looks.

── more in #developer-tools 4 stories · sorted by recency
── more on @skanfirmy.pl 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/checking-polish-comp…] indexed:0 read:3min 2026-08-23 ·