Poland VAT Whitelist Checker & Supplier Monitor avatar

Poland VAT Whitelist Checker & Supplier Monitor

Pricing

$5.00 / 1,000 resolved supplier checks

Go to Apify Store
Poland VAT Whitelist Checker & Supplier Monitor

Poland VAT Whitelist Checker & Supplier Monitor

Bulk-check up to 3,000 Polish suppliers against the official VAT White List (Biała Lista): verify VAT status and registered bank accounts, preserve official request IDs, and monitor deterministic supplier changes between scheduled runs. Failed checks never become false absences.

Pricing

$5.00 / 1,000 resolved supplier checks

Rating

0.0

(0)

Developer

Vadim Bezrukov

Vadim Bezrukov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

10 hours ago

Last modified

Share

Check VAT status and registered bank accounts today, then run the same supplier portfolio again to receive deterministic, webhook-ready change events.

Unofficial community Actor. This Actor is not affiliated with, sponsored by, or endorsed by the Polish Ministry of Finance (MF) or National Revenue Administration (KAS). It reads their public VAT White List API.

Bulk-check a Polish supplier portfolio against the official Ministry of Finance VAT White List (Biała Lista), verify an optional NIP + bank-account pair, and monitor deterministic VAT or registered-account changes between runs.

The Actor is built for accounting, AP, procurement, ERP and supplier-compliance workflows. It uses the official JSON API over direct HTTP: no browser, CAPTCHA, login, proxy, proxy rotation, VIES, KRS/CEIDG enrichment or private database.

This is not tax or legal advice. The Actor reports what the official register returned for the requested date and does not decide whether a payment is lawful or recommend a tax procedure.

Use from AI agents with MCP

Connect the public Actor directly at https://mcp.apify.com?tools=automa-flow/poland-vat-whitelist-monitor. Ask your agent to verify a supplier or bank account and preserve the official request ID, requested date, and explicit per-item status in its answer.

What you can do

  1. Bulk Polish VAT supplier verification — reconcile up to 3,000 NIPs in a single run with one explicit output row per input.
  2. Supplier master-data monitoring — reuse a monitorId and retain only the last verified normalized state in Apify KVS.
  3. Weekly VAT-status change detection — receive exact vat_status_changed and registration-state/date events.
  4. Bank-account change monitoring — compare sorted account hashes and emit bank_account_added / bank_account_removed without keeping raw accounts in monitor state.
  5. Pre-payment verification — include bankAccount to run the official NIP + account TAK/NIE method and retain both official request IDs.

Why use the supplier monitor instead of a one-off checker?

The default Dataset always keeps one explicit reconciliation row per input, so AP and supplier-master workflows can join results without guessing which NIP was lost. In monitor mode, only successful official observations advance state; source failures stay visible and cannot manufacture a VAT/account change. The changes view is already flattened for scheduled-run webhooks.

Input

{
"records": [
{
"nip": "PL 526-025-02-74",
"reference": "invoice-2026-0042",
"bankAccount": "PL73 1111 1111 1111 1111 1111 1111"
}
],
"mode": "monitor",
"monitorId": "weekly-ap-watchlist",
"onlyChanges": false,
"includeFullBankAccounts": false
}
  • records is required and accepts 1–3,000 rows.
  • nip is normalized from PL/spaces/dashes and must pass the Polish checksum.
  • reference is optional, at most 128 characters, and is echoed unchanged.
  • bankAccount is optional Polish NRB/PL IBAN. It is checksum-validated before any request and is never logged or included in an error URL.
  • mode defaults to snapshot. monitor requires a safe, stable monitorId.
  • asOfDate defaults to the current Europe/Warsaw date. The official register currently permits dates in the current year and the five preceding calendar years.
  • onlyChanges=true minimizes unchanged profile details, but deliberately keeps one explicit status row per input so batch reconciliation cannot silently lose suppliers. Use the changes Dataset view for event-only webhooks.
  • includeFullBankAccounts defaults to false. Enable it only when the workflow truly needs full registered accounts.

Concurrency, retries, delays and proxy internals are intentionally not public inputs. Official quotas, rather than CPU, are the limiting resource.

Output and failure semantics

Each input row produces one row with:

  • stable source, normalized source_id, source_url, UTC scraped_at, schema_version and semantic fingerprint;
  • SUCCESS, NOT_FOUND, PARTIAL, FAILED or INVALID_INPUT;
  • normalized ACTIVE, EXEMPT, NOT_REGISTERED or UNKNOWN VAT status;
  • masked registered accounts and deterministic account hashes;
  • optional authoritative account_check with last four digits only;
  • the Ministry search request ID and optional account-check request ID;
  • changed, change_type and deterministic changes[] in monitor mode;
  • a safe structured error on unverified work.

NOT_FOUND is only produced after HTTP 200 with a valid response entry and an empty subjects array. Timeout, HTTP 408/429/5xx, quota exhaustion, nightly maintenance, malformed HTTP-200 JSON/schema and account-check failure are never converted to absence. A failed supplier does not terminate valid siblings.

The run itself fails, after publishing explicit rows, only when the whole run is untrustworthy: every official search batch failed, the official allowance prevented every check, the HTTP-200 response envelope materially changed, or a billing limit changed while publishing.

A partial outcome succeeds instead. If the official allowance stops some checks after others resolved, the run succeeds, the unattempted suppliers carry explicit SOURCE_QUOTA rows, and the status message names how many were stopped. This keeps the ACTOR.RUN.SUCCEEDED webhook firing for scheduled monitors, so a cycle that did contain verified changes is never skipped silently. Filter status in the diagnostics view to see what was missed.

One supplier the parser cannot read, such as an unrecognized VAT status or a checksum-invalid registered account, is an isolated MALFORMED_SUBJECT row for that supplier only. It does not fail the run and does not stop the remaining suppliers from being checked.

Monitoring

State is namespaced by monitorId + normalized NIP in an Apify named KVS. It contains only the last verified semantic observation, its fingerprint and account hashes. Raw source payloads and full bank accounts are never retained.

The first verified monitor run is a baseline (changed=false). Later verified runs can emit:

  • vat_status_changed
  • registration_state_changed
  • registration_date_changed
  • removal_date_changed
  • restoration_date_changed
  • bank_account_added
  • bank_account_removed
  • supplier name, REGON or KRS changes already present in the official response

A failed profile never overwrites good state. If the supplier profile succeeds but its requested account check fails, the row is PARTIAL; the independently verified profile can advance the VAT/account-set baseline because the failed field is not part of that baseline.

Official source limits and update window

The current official production documentation is API v1.6: https://www.gov.pl/web/kas/api-wykazu-podatnikow-vat

  • search: 100 requests/day, at most 30 subjects/request — a practical maximum of approximately 3,000 searched NIPs/day.
  • check: 5,000 subjects/day.
  • Exhausting either allowance can block both API methods and the public search until 00:00. The Actor stops remaining work and never changes egress identity to multiply that allowance.
  • A retry spends one request from the same 100/day search allowance, so the Actor sizes its retry budget from what the allowance can still fund. At the 3,000-supplier maximum all 100 requests are committed to first attempts and the run performs no retries: a transient upstream failure then costs that one batch of 30 an explicit FAILED row instead of consuming the allowance a later batch still needs. Below roughly 2,700 suppliers there is real retry headroom.
  • The register is updated once on working days. The Ministry warns of possible disruption during 22:00–00:00 Europe/Warsaw, so retries are suppressed in that window.
  • The official daily flat file is the documented option for substantially larger verification volumes; it is outside this MVP.

Because allowances can be enforced by egress IP, a representative 300-NIP direct-HTTP run from Apify is a pre-publication gate. It was run on 2026-09-03: 300 suppliers over 10 search batches resolved with a 100% useful-output rate, no HTTP 429, no quota collision and one transient retry, using shared Apify egress without a browser, CAPTCHA, login or proxy. A single run still consumes its share of the official 100-request daily search allowance, and a retry consumes one more, so schedule large portfolios accordingly.

Privacy

The Ministry response can include PESEL-capable fields, representatives, authorized clerks, partners and personal addresses. The parser uses an explicit allowlist and never returns or stores those fields. It also never stores raw responses. Registered accounts are masked by default; monitor state uses only SHA-256 values. The full-account output is an explicit opt-in and full accounts never appear in logs.

Pay-per-event pricing

One supplier_checked event at $0.005 per resolved supplier ($5 per 1,000), with platform usage included and no separate start fee. A supplier can generate at most one event, even when an extra official account request is needed.

Billable: complete SUCCESS and authoritative NOT_FOUND rows, including a supplier that monitor mode reports as unchanged. A scheduled monitor run therefore costs the same per supplier as the first run; onlyChanges reduces row size, not price.

Free: invalid input, retries, PARTIAL, FAILED, quota/source failures, billing-limit skips and KVS operations.

Resolved suppliersActor charge
100$0.50
1,000$5.00
3,000$15.00

Set maxTotalChargeUsd on a run or Task to cap spend. Suppliers that the cap cannot cover are never contacted and are published as explicit MAX_TOTAL_CHARGE_REACHED rows, so a capped run still reconciles one row per input and never advances monitor state for work it did not pay for.

Run through the Apify API

Keep the API token in an environment secret; never paste it into Actor input or source control.

curl -X POST \
"https://api.apify.com/v2/acts/<ACTOR_ID>/runs?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"records": [{"nip": "5260250274", "reference": "supplier-001"}],
"mode": "snapshot"
}'

Schedule and webhook example

Create an Apify Task with a stable monitor input, then schedule it weekly after the nightly source window, for example every Monday at 06:00 Europe/Warsaw:

{
"records": [
{"nip": "5260250274", "reference": "supplier-001"},
{"nip": "7000000009", "reference": "supplier-002"}
],
"mode": "monitor",
"monitorId": "weekly-ap-watchlist",
"onlyChanges": true
}

Subscribe a webhook to the Task's ACTOR.RUN.SUCCEEDED event. From the webhook payload's default Dataset ID, fetch the flattened event view:

GET https://api.apify.com/v2/datasets/<DATASET_ID>/items?view=changes&clean=true

The view is empty when there are no deterministic changes. Failure/status rows remain available in the default Dataset. The diagnostics view projects status and error columns for every row; filter status client-side when selecting only failures.

Local verification

Offline fixture demonstration:

$uv run python actors/poland-vat-whitelist-monitor/scripts/local_run.py

Manual direct-source smoke (not used by CI):

$uv run python actors/poland-vat-whitelist-monitor/scripts/smoke_test.py 5260250274

Full repository gate:

uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy

The dated source evidence, legal/privacy review, pending hosted gate and economic guardrail are recorded in experiments/poland-vat-whitelist/README.md.