# Poland Supplier Verification: VAT White List & Bank Check (`plym-actor-factory/poland-supplier-kyb-packet`) Actor

Supplier verification for AP, treasury and procurement teams paying Polish suppliers: per NIP, one KYB packet with official MF VAT White List status, bank account verification (accountAssigned) with requestId audit proof, a KRZ insolvency signal and mismatch events. No API key.

- **URL**: https://apify.com/plym-actor-factory/poland-supplier-kyb-packet.md
- **Developed by:** [Daniel Witney](https://apify.com/plym-actor-factory) (community)
- **Categories:** AI, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 kyb packet delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Poland Supplier Verification: VAT White List & Bank Check

**Supplier verification for AP, treasury and procurement teams paying Polish suppliers.** For each supplier **NIP** (+ optional bank account), get one JSON **KYB packet**: the official **MF VAT White List** status (*biała lista podatników VAT*), a **bank account verification** (`accountAssigned` TAK/NIE) with the MF `requestId` as audit proof, and a best-effort **KRZ** (National Debtor Register) insolvency signal — plus typed **mismatch events** such as `BANK_ACCOUNT_MISMATCH` and `VAT_NOT_ACTIVE`. Official public HTTP, **no API key**. Not a Northdata clone, not a VAT-only ghost monitor, not a KRS financial-statement dump.

**Quick start (no key):** put your suppliers' NIPs (and optionally `NIP:account` pairs) in the input → set **Source mode = live** → Start. Unlike the watch Actors, **the first live run already returns one verified packet per supplier**; schedule it (e.g. before each payment run) to re-check. Clicking *Start* with the defaults runs a free health check only.

### Who this is for

- **Accounts payable and treasury** teams that must check a Polish supplier's bank account is on the MF White List before paying (split-payment / tax-liability risk).
- **Procurement and vendor-onboarding** teams doing supplier KYB on new Polish vendors.
- **Shared-service centres** re-verifying a supplier master file on a schedule.

#### Typical workflow

1. Export supplier NIPs (and the bank accounts you are about to pay, as `NIP:NRB` or `NIP:IBAN`).
2. Run with `sourceMode: "live"` (no key) — each verified supplier returns a packet with `status_vat`, `bank_status`, `mf_request_id` and `mismatch_events`.
3. Block or review payments where `mismatch_events` is non-empty (e.g. `BANK_ACCOUNT_MISMATCH`, `VAT_NOT_ACTIVE`); keep `mf_request_id` as audit evidence.
4. Schedule it (e.g. before each payment run). Unchanged packets are deduplicated and not re-charged; a VAT, bank or KRZ flip produces a new packet.

#### First run vs later runs

**No baseline step:** the first live run returns a packet for each verified supplier. Later runs re-check and only deliver (and charge) a new packet when VAT, bank or KRZ status changes.

#### Run it live now (no API key)

```json
{
  "supplierNips": [
    "5261040828"
  ],
  "bankAccounts": [
    "5261040828:07101010100024791339300000"
  ],
  "sourceMode": "live",
  "includeKrz": true,
  "maxRunSeconds": 120
}
```

#### Example output (SAMPLE)

> SAMPLE — illustrative values in the real output shape; NIP `0000000000` / `EXAMPLE SP. Z O.O.` / the account and request IDs are placeholders, not a real supplier or a real MF response.

```json
{
  "event_type": "KYB_PACKET",
  "event_subtype": "BANK_ACCOUNT_MISMATCH",
  "nip": "0000000000",
  "legal_name": "EXAMPLE SP. Z O.O.",
  "status_vat": "ACTIVE",
  "bank_status": "NOT_ASSIGNED",
  "bank_account": "00000000000000000000000000",
  "account_assigned": "NIE",
  "krz_status": "CLEAR",
  "mf_request_id": "<MF requestId>",
  "mismatch_events": [
    "BANK_ACCOUNT_MISMATCH"
  ],
  "verified": true,
  "summary": "KYB packet for NIP 0000000000: vat=ACTIVE bank=NOT_ASSIGNED krz=CLEAR verified=true mismatches=BANK_ACCOUNT_MISMATCH",
  "event_uid": "<md5>",
  "billable": true
}
```

**What you get per $0.02 event:** one verified KYB packet for one supplier (one dataset row like the sample above). Unverified results (MF outage or quota, NIP not found) are not delivered or charged (they are counted in the `RUN_STATUS` row); duplicates and health rows are never charged.

**Honest title:** batch / scheduled KYB packet over official/public HTTP. Not a paid Bisnode/Creditreform extract, not a certified KRS odpisu, not real-time KRZ push.

### Value proposition

- **Cross-source join:** MF White List × bank `accountAssigned` proof × KRZ signal.
- **Mismatch events:** `VAT_NOT_ACTIVE`, `VAT_REMOVED`, `VAT_EXEMPT`, `BANK_ACCOUNT_MISMATCH`, `BANK_ACCOUNT_UNCHECKED`, `KRZ_PROCEEDING_OPEN`, `KRZ_CHECK_UNAVAILABLE`, `MF_API_UNAVAILABLE`, `NIP_NOT_FOUND`.
- Official / public HTTP only. **No paid credit-bureau HTML.**
- **Pay only for unique verified KYB packets.** MF outage and fixture health ≈ $0 product charges.
- Durable KVS checkpoint + `event_uid` dedupe (VAT/bank/KRZ flips → new packet).

### PRODUCTION USE (required for real KYB)

> **Store default ≠ product.** Schema defaults use `sourceMode=fixture` so Apify Store daily auto-tests leave a non-empty health dataset **without** calling MF or KRZ. That fixture path only writes a non-billable `RUN_STATUS` / `FIXTURE_HEALTH` row. It is **not** supplier verification.

For **production KYB** you **must**:

1. Set **`sourceMode` = `live`**
2. Provide `supplierNips` (10-digit NIPs; optional `NIP:KRS`)
3. Optionally provide `bankAccounts` as `NIP:NRB` / `NIP:IBAN` pairs for official `accountAssigned` checks
4. Use fair-use `requestPaceMs` (default 400) and respect **MF API daily caps** (~100 requests/day × up to 30 NIPs per bulk call)

Official references:

- [API Wykazu podatników VAT](https://www.gov.pl/web/kas/api-wykazu-podatnikow-vat) — `wl-api.mf.gov.pl`
- [Plik płaski (flat file)](https://www.gov.pl/web/kas/plik-plaski) — prefer for books above API daily caps (hash-based NIP×account offline verify; download from [podatki.gov.pl](https://www.podatki.gov.pl/vat/bezpieczna-transakcja/wykaz-podatnikow-vat/plik-plaski/))
- [KRZ / PRS](https://prs.ms.gov.pl/krz) — public National Debtor Register (no official third-party REST API yet per Ministry FAQ)

### Data limitations (read before buying)

- **Not a Northdata / Bisnode / Creditreform substitute.** No paid bureau scrape.
- **MF API daily caps:** MF documents rate limits (order of **100 queries/day**, up to **30 NIPs** per bulk search). Exhausted quota → `MF_API_UNAVAILABLE` (not charged). For large supplier books use the official **plik płaski** offline path (documented above; this Actor’s live mode uses the search/check API for `requestId` audit proof).
- **KRZ:** Ministry states an official API is still under analytical/legislative work. Live KRZ is **best-effort** against the public portal; SPA/login shells often yield `KRZ_CHECK_UNAVAILABLE` without blocking VAT×bank verification. Do **not** treat absence of OPEN as a certified CLEAR.
- Optional **CRBR UBO** is out of scope for this version.
- KRS number is taken from the White List subject (and optional `NIP:KRS` hint) — this Actor does **not** dump KRS financial statements.
- Fair-use pacing applies; large batches need longer `maxRunSeconds` or chunked runs.
- We cite the Ministry of Finance (White List) and Ministry of Justice (KRZ portal) as data origins. This Actor is not affiliated with or endorsed by them.

### Apify Store daily auto-test / default input

| Field | Default |
|-------|---------|
| `supplierNips` | `["5261040828","5252344078"]` |
| `sourceMode` | `fixture` |
| `emitFixtureDemoEvents` | `false` |
| `maxRunSeconds` | `55` |
| `maxEvents` | `500` |
| `includeKrz` | `true` |

On that path the Actor **SUCCEEDS** quickly, pushes exactly one `RUN_STATUS` / `FIXTURE_HEALTH` row (`billable: false`), and does **not** charge `kyb-packet-delivered`.

### Input (summary)

| Field | Notes |
|-------|--------|
| `supplierNips` | NIPs required; optional `NIP:KRS` |
| `bankAccounts` | Optional `NIP:account` pairs |
| `sourceMode` | `fixture` (default) or `live` |
| `emitFixtureDemoEvents` | Default **false** |
| `includeKrz` | Default true (best-effort) |
| `asOfDate` | Optional YYYY-MM-DD (default today UTC) |
| `maxRunSeconds` / `maxEvents` | Budgets |
| `resumeFromCheckpoint` | Default true |
| `requestPaceMs` | Fair-use delay (default 400) |

#### Production example

```json
{
  "supplierNips": ["5261040828", "5252344078"],
  "bankAccounts": ["5261040828:07101010100024791339300000"],
  "sourceMode": "live",
  "maxRunSeconds": 120,
  "requestPaceMs": 400,
  "includeKrz": true,
  "resumeFromCheckpoint": true
}
```

### Output

#### KYB packets (billable under PPE when verified)

Typed rows include: `nip`, `legal_name`, `status_vat`, `bank_status`, `account_assigned`, `mf_request_id`, `krz_status`, `mismatch_events`, `verified`, `evidence`, `event_uid`, `billable: true`.

#### RUN\_STATUS (never billed)

Every successful run pushes one health row (`FIXTURE_HEALTH` | `MONITOR_IDLE` | `CATCHUP_COMPLETE` | `HEALTH_OK`).

### Pricing

Pay-per-event: **`kyb-packet-delivered`** at **$0.02** per delivered unique **verified** KYB packet ($20 / 1,000). Single tier (see `docs/monetization.md` and ADR 0010). Health / incomplete / duplicate / fixture rows are never charged.

### Local development

```bash
cd actors/poland-supplier-kyb-packet
npm install
npm test
npm run build
## Store-safe fixture health:
apify run -p
## Demo typed packets locally:
## set input emitFixtureDemoEvents=true (still sourceMode=fixture)
```

### Attribution

VAT status and bank-account assignment originate from the **Ministry of Finance VAT White List** (`wl-api.mf.gov.pl`). KRZ signals originate from the **public National Debtor Register portal** (Ministry of Justice). Not an official product of those bodies.

# Actor input Schema

## `supplierNips` (type: `array`):

Polish supplier tax IDs (NIP, 10 digits; punctuation optional). Optional KRS can be passed as NIP:KRS (e.g. 5261040828:0000000000). Invalid entries are skipped with no charge.

## `bankAccounts` (type: `array`):

Optional NIP:IBAN or NIP:NRB pairs for official MF accountAssigned checks (e.g. 5261040828:07101010100024791339300000). When omitted, packet still includes White List accountNumbers list but bank assignment is SKIPPED.

## `maxRunSeconds` (type: `integer`):

Wall-clock budget for this batch.

## `maxEvents` (type: `integer`):

Stop after this many unique verified KYB packets are delivered (does not include RUN\_STATUS).

## `resumeFromCheckpoint` (type: `boolean`):

If true, resume seen event\_uids and last packet fingerprints from the default Key-Value Store.

## `sourceMode` (type: `string`):

fixture = local/CI / Apify Store daily auto-test default (no network; emits RUN\_STATUS only unless emitFixtureDemoEvents=true). live = official MF White List API (+ optional bank check) and best-effort public KRZ signal. For books above MF API daily caps, prefer official plik płaski offline (documented in README; not auto-downloaded here).

## `emitFixtureDemoEvents` (type: `boolean`):

When sourceMode=fixture, if true push fabricated KYB packets from local fixtures (unit/local demos only). Default false so Store daily auto-tests never emit fake packets or charge kyb-packet-delivered. Production: leave false and use sourceMode=live. SAMPLE rows only: demo events use placeholder entities (never real companies/IDs), are flagged sample=true / isSample=true, and are NEVER charged. To see them, set Source mode = fixture and put the placeholder values 9999999999, 9999999982 in "Supplier NIPs to verify (example NIPs prefilled — replace with yours)".

## `includeKrz` (type: `boolean`):

If true (default), attempt public KRZ (National Debtor Register) open-proceeding flag and nest it on the packet. KRZ has no official public REST API — HTML/portal fragility may yield KRZ\_CHECK\_UNAVAILABLE without blocking VAT×bank verification.

## `asOfDate` (type: `string`):

Optional date for MF White List / bank check queries. Default = today (UTC). Format YYYY-MM-DD.

## `maxTotalChargeUsd` (type: `number`):

Optional soft budget hint for delivered packets. Platform ACTOR\_MAX\_TOTAL\_CHARGE\_USD also applies when set.

## `requestPaceMs` (type: `integer`):

Minimum delay between outbound official/public HTTP requests (fair-use pacing; respect MF API daily caps).

## Actor input object example

```json
{
  "supplierNips": [
    "5261040828",
    "5252344078"
  ],
  "bankAccounts": [],
  "maxRunSeconds": 55,
  "maxEvents": 500,
  "resumeFromCheckpoint": true,
  "sourceMode": "fixture",
  "emitFixtureDemoEvents": false,
  "includeKrz": true,
  "requestPaceMs": 400
}
```

# Actor output Schema

## `OUTPUT` (type: `string`):

JSON summary: delivered, charged, runStatus, checkpoint, stats

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("plym-actor-factory/poland-supplier-kyb-packet").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("plym-actor-factory/poland-supplier-kyb-packet").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call plym-actor-factory/poland-supplier-kyb-packet --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,plym-actor-factory/poland-supplier-kyb-packet"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9CyoJaNewxODXJQIP/builds/lYMhwvyjoDPbxh4IQ/openapi.json
