# Poland KRZ Debtor Registry & Insolvency Check (`automa-flow/poland-krz-debtor-registry-insolvency-check`) Actor

Search Poland’s KRZ by KRS, NIP, or company name. Check up to 500 companies per run, export matched registry entries and case data, and schedule monitoring for new or changed results. Built for compliance, credit risk, supplier onboarding, debt collection, and receivables workflows.

- **URL**: https://apify.com/automa-flow/poland-krz-debtor-registry-insolvency-check.md
- **Developed by:** [Vadim Bezrukov](https://apify.com/automa-flow) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 company checks

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

Search Poland's **Krajowy Rejestr Zadłużonych** (KRZ, the National Register of
Debtors) by KRS number, NIP, or company name. Check up to 500 companies per run,
export normalized insolvency and restructuring findings, or schedule recurring
portfolio monitoring.

### What it does

You give it a list of Polish companies - by KRS number, NIP, or name. For each
one it looks the company up in the KRZ public register, extracts any bankruptcy,
restructuring, business-ban or enforcement proceedings, and returns a single
normalized status plus the underlying proceedings.

It is deliberately narrow. It answers *"what does KRZ show for this company?"*
for **companies**. It is not a general solvency certificate, a current KRS-status
check, or an interface for natural persons.

The one rule it never breaks:

> A zero-result lookup is `NO_KRZ_RECORD`, never `CLEAR`. KRZ contains only
> proceedings begun after 1 December 2021, so no KRZ match does not prove that a
> company is solvent or free of older proceedings.

"Nothing found" and "the request failed" are different fields with different
values, so a downstream credit decision can tell them apart.

### Main use cases

- **One input to counterparty screening** before signing a contract or extending
  credit. Do not use KRZ alone as a solvency clearance.
- **Portfolio monitoring** - run it on a schedule with `monitorMode: true` and
  get an event when a new KRZ proceeding appears for a customer or supplier.
- **KYC / onboarding checks** as part of a supplier or partner review.
- **Receivables risk** - spot debtors entering restructuring before a payment
  becomes uncollectable.

### Input

```json
{
  "companies": [
    { "krs": "0000026438", "externalId": "example-with-record" },
    { "krs": "0000127140", "externalId": "example-no-krz-record" }
  ],
  "monitorMode": false,
  "includeHistorical": true,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "PL"
  }
}
```

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `companies` | array | required | 1-500 entries; each needs at least one identifier, plus an optional `externalId` echoed back on the result |
| `monitorMode` | boolean | `false` | Compare against the previous run and report `changes` |
| `includeHistorical` | boolean | `true` | Include closed proceedings |
| `maxConcurrency` | integer | `3` | Advanced: parallel company checks, 1-10. Keep the default unless KRZ is stable at a higher value |
| `proxyConfiguration` | object | Apify Proxy, RESIDENTIAL, PL | See [Proxy requirement](#proxy-requirement) |

**Identifier precedence: KRS → NIP → name.** If you supply several, the most
specific one is used for the search and the rest are echoed back. Give a KRS or
NIP whenever you have one. A zero-candidate lookup is reported as
`NO_KRZ_RECORD`; this describes the KRZ response only and is not a company-level
clearance.

A name that matches several debtors is never resolved to a guess. The record
comes back unmatched with `match.ambiguous: true` and the candidate count, so
you can tell "not in the register" from "we could not tell which one you
meant".

`externalId` is yours - an opaque string echoed back untouched on the result so
you can join it to your own rows. It is never sent to KRZ and never affects the
search or the monitoring state key.

Identifiers are validated before any request is made. NIP checksums are
verified, KRS numbers are zero-padded to ten digits. An invalid entry does not
stop the batch - it becomes one `FAILED` record explaining what was wrong with
that row, and the other companies are still checked.

### Output

One dataset record per input row. This is a real no-record response shape for
the second company in the sample input above:

```json
{
  "query": {
    "nip": null,
    "krs": "0000127140",
    "name": null,
    "externalId": "example-no-krz-record"
  },
  "company": null,
  "businessStatus": "NO_KRZ_RECORD",
  "match": { "method": "krs", "candidates": 0, "ambiguous": false, "truncated": false },
  "proceedings": [],
  "changes": [],
  "source": "KRZ",
  "sourceUrl": "https://krz.ms.gov.pl/",
  "checkedAt": "2026-08-29T14:50:55.548461Z",
  "checkStatus": "NOT_FOUND",
  "error": null,
  "schemaVersion": 2
}
```

#### `businessStatus` - what we know about the company

| Value | Meaning |
| --- | --- |
| `NO_KRZ_RECORD` | KRZ returned zero matching records. This is **not** proof of solvency and does not exclude proceedings begun before 1 December 2021 |
| `ACTIVE_PROCEEDING` | In the register with at least one **characterized** proceeding that is open (or of a known type whose status KRZ did not state) |
| `HISTORICAL_PROCEEDING` | In the register with characterized proceedings, all closed |
| `LISTED_UNVERIFIED` | In the register, but the proceeding could **not be characterized** - the detail lookup gave no type or status. Not clear, not a confirmed active proceeding. **Verify manually** |
| `UNKNOWN` | The check did not complete (transport error, or an ambiguous name miss). Never treat as clear |

**Presence in the register is a signal, but absence is not a clearance.** KRZ
lists only proceedings begun after 1 December 2021. A company that appears is
never `CLEAR`; a company with zero candidates is `NO_KRZ_RECORD`, even under an
exact KRS or NIP.

The entity search alone returns only an id and a start date - **no type or
status** - so each proceeding's nature comes from a per-company detail lookup.
When the detail resolves, `ACTIVE_PROCEEDING` and `HISTORICAL_PROCEEDING` are
distinguished (a known type with an unstated status still counts as open - a
missed insolvency is the expensive error). When the detail **cannot be read**,
the company reads `LISTED_UNVERIFIED`, not `ACTIVE_PROCEEDING`: the Actor knows
the company is in KRZ but will not assert an active proceeding it has not seen.
This is deliberate - reporting a large solvent company as being in active
insolvency on the strength of one unresolved row is the failure mode this status
prevents. A matched company is still **never** downgraded to `CLEAR` by a detail
error. `includeHistorical` shapes which proceedings are listed, never the status.

#### `checkStatus` - whether the check worked

| Value | Meaning |
| --- | --- |
| `SUCCESS` | KRZ answered and the company was matched |
| `NOT_FOUND` | KRZ answered, no entity matched this identifier |
| `FAILED` | The lookup did not complete. `error` says why; `businessStatus` is `UNKNOWN` |

`NOT_FOUND` with `businessStatus: NO_KRZ_RECORD` means the query completed and
KRZ returned zero matching records. It does **not** mean "healthy company".

#### `proceedings[].type`

`BANKRUPTCY`, `BANKRUPTCY_PETITION`, `RESTRUCTURING`, `BUSINESS_BAN`,
`ENFORCEMENT`, `OTHER`. The original Polish label is kept in `sourceType` so a
normalization you disagree with is visible in the data.

#### Partial failures

A bad company does not stop the rest of a batch. For example, 100 inputs with 3
failed lookups still produce 100 dataset records: 97 usable records and 3
records marked `FAILED`. The log and `RUN_SUMMARY` make the totals explicit:

```
Processed: 100
Successful: 16
Not found: 81
Failed: 3
No matching KRZ record: 81
Active proceedings: 4
Historical proceedings: 11
Listed, details unverified: 1
```

The same numbers are written to `RUN_SUMMARY` in the run's key-value store. The
run itself is only marked failed when KRZ is unreachable or every check failed,
because that is a source problem rather than a data problem.

### Monitoring mode

Set `monitorMode: true` and schedule the Actor. Each run compares against the
previous one and fills `changes`:

```json
"changes": [
  {
    "type": "NEW_PROCEEDING",
    "caseNumber": "WA1M/GU/301/2026",
    "proceedingType": "BANKRUPTCY_PETITION",
    "previousStatus": null,
    "currentStatus": "ACTIVE",
    "detectedAt": "2026-08-27T11:46:51+00:00"
  }
]
```

Change types: `NEW_PROCEEDING`, `STATUS_CHANGED`, `PROCEEDING_CLOSED`.

State is kept in an Apify key-value store, one record per company, keyed by the
strongest identifier supplied. Keep passing the *same* KRS or NIP for a company
so its history lines up. The first monitored run reports no changes because it
has no earlier successful observation to compare against.

A proceeding that disappears from KRZ produces no event. Disappearing is not a
fact about the company; only new entries and status transitions are reported.

**Failures do not manufacture change events.** A failed or incomplete check does
not overwrite the last successful state. Once KRZ becomes readable again, the
Actor compares two successful observations rather than treating the outage as a
company event.

`includeHistorical` shapes the `proceedings` listing only. Change detection and
state always run on everything KRZ returned, so a proceeding closing is still
reported as `PROCEEDING_CLOSED` even with `includeHistorical: false`.

### Proxy requirement

**KRZ rejects requests from IP addresses outside Poland.** Use Apify Proxy with
country `PL`. The input defaults to `RESIDENTIAL`, which is the most reliable
tested configuration. A Polish datacenter proxy may be cheaper, but is not
guaranteed to pass KRZ access controls. If the country is missing from
`proxyConfiguration`, the Actor fills in `PL` and reports that choice in the
log.

Without a working Polish proxy the run fails immediately with a clear message
rather than producing a dataset full of false no-record results.

### Limitations

- **Companies only.** KRZ also covers natural persons; this Actor does not, and
  passing a personal identifier is not supported.
- **Historical coverage starts on 1 December 2021.** The
  [Polish Ministry of Justice](https://www.gov.pl/web/sprawiedliwosc/12-czy-w-krz-moge-znalezc-informacje-na-temat-postepowan-wszczetych-przed-powstaniem-systemu-i-wejsciem-w-zycie-ustawy)
  states that KRZ contains only proceedings begun after that date. Older
  proceedings can remain active without appearing in KRZ.
- **No KRS health verification.** The Actor does not currently verify whether a
  company is active, deleted, in liquidation, or named "w upadłości" in KRS.
  `NO_KRZ_RECORD` must not be used as a compliance or credit clearance.
- **Name searches are weak.** Several candidates or a truncated result produce
  `NOT_FOUND` with `businessStatus: UNKNOWN` rather than a guess. Use KRS or NIP.
- **No official public API.** The Actor reads the public KRZ portal. A portal
  redesign can interrupt extraction; such failures are returned as `FAILED`,
  never as an empty or clear result.
- **Register lag.** KRZ reflects court announcements. A proceeding exists in
  reality from the moment a court acts, which can precede its publication.
- **`sourceUrl` is the portal root**, not a per-company deep link; no stable
  deep-link format has been confirmed.
- **Batch cap of 500** companies per run. Split larger lists across runs.

### Storage and integrations

Results are available in Apify Console, through the API, and to integrations or
AI agents:

- **`results`** - the default dataset, one record per input company
  (`{{apiDefaultDatasetUrl}}/items`).
- **`runSummary`** - the `RUN_SUMMARY` record in the default key-value store:
  processed / successful / not found / failed counts, per-status totals, and the
  request/browser counters used for costing.

### Pricing

The Actor supports **Pay per event**. Its billing boundary is a *logical,
customer-visible* company check - never an HTTP request or a retry:

| Situation | `company-check` billed? |
| --- | --- |
| `SUCCESS` (KRZ answered, company matched) | **yes** |
| `NOT_FOUND` (KRZ answered, no record matched) | **yes** - the lookup was performed |
| `FAILED` (transport error, source blocked, skipped) | **no** |
| Invalid input row (bad NIP, too-short name, …) | **no** - it never reaches KRZ |
| Internal client retries / token refresh | **no** - billing is per result, not per request |

`monitor-change` is an **additional** event charged only alongside a billable
`company-check`, one per detected change - so a failed check is never billed for
phantom changes.

Users can set a maximum charge for an individual run. Once the remaining budget
cannot pay for another `company-check`, the Actor starts no more KRZ lookups and
reports the number skipped in `RUN_SUMMARY`. A few checks already in flight may
finish, bounded by `maxConcurrency`; the SDK atomically prevents their dataset
writes from exceeding the limit. If the Actor start event consumes the entire
budget, the browser and proxy are not initialized at all.

### API usage

Run it from your own code with the Apify API or a client library:

```bash
curl -X POST "https://api.apify.com/v2/acts/automa-flow~poland-krz-debtor-registry-insolvency-check/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
        "companies": [{"krs": "0000026438"}, {"krs": "0000127140"}],
        "proxyConfiguration": {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "PL"}
      }'
```

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("automa-flow/poland-krz-debtor-registry-insolvency-check").call(
    run_input={
        "companies": [{"krs": "0000026438"}],
        "monitorMode": True,
        "proxyConfiguration": {
            "useApifyProxy": True,
            "apifyProxyGroups": ["RESIDENTIAL"],
            "apifyProxyCountry": "PL",
        },
    }
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["query"], item["businessStatus"], item["checkStatus"])
```

Always branch on `checkStatus` before acting on `businessStatus`.

Keep API tokens in environment variables or Apify secrets. Do not paste them
into input, source code, issue reports, or URLs.

### Troubleshooting and support

- **Run fails before producing results:** keep the default Polish residential
  proxy and retry. KRZ blocks non-Polish traffic.
- **A name search is ambiguous:** use KRS or NIP. The Actor deliberately refuses
  to guess between multiple companies.
- **A row says `FAILED`:** inspect its `error` field and retry it. Never treat a
  failed row as absence from KRZ.
- **A row says `NO_KRZ_RECORD`:** the KRZ query completed but returned no match.
  This is not a KRS-status or solvency clearance.
- **Unexpected output:** open an issue on the Actor page and include the run ID,
  expected result, and affected KRS or company identifier. Never include an API
  token or private proxy credentials.

### Data and source disclaimer

Data comes from the **Krajowy Rejestr Zadłużonych**, a public register operated
by the Polish Ministry of Justice at <https://krz.ms.gov.pl/>. The register is
public and free to consult; this Actor automates reading it and normalizes the
result.

- This Actor is **not affiliated with or endorsed by** the Ministry of Justice.
- Output is provided as-is with **no warranty of accuracy, completeness or
  timeliness**, and is not legal, credit or financial advice. For anything with
  legal consequence, consult the register or an official document directly.
- KRZ is the authoritative source. Where this Actor's output and KRZ disagree,
  KRZ is right.
- Only company records are returned. Do not use this Actor to profile natural
  persons; if a personal record is ever returned, that is a bug - please report
  it.
- You are responsible for using the data lawfully, including under GDPR where
  any personal data (a court official's name in a case record, for instance) is
  involved.

# Actor input Schema

## `companies` (type: `array`):

Up to 500 companies. Each entry needs at least one identifier. Search precedence is KRS, then NIP, then name - the more specific the identifier, the more reliable the match. Add an optional externalId to join results back to your own records.

## `monitorMode` (type: `boolean`):

Compare this run against the previous one and report NEW\_PROCEEDING, STATUS\_CHANGED and PROCEEDING\_CLOSED events in the 'changes' field. State is kept in a named key-value store, so schedule this Actor and leave the option on.

## `includeHistorical` (type: `boolean`):

Include closed proceedings in the 'proceedings' list. This shapes the list only - businessStatus always reflects whether the company is in the register, so turning it off never turns a listed debtor into CLEAR.

## `maxConcurrency` (type: `integer`):

How many companies to check in parallel. KRZ sits behind a WAF; raising this increases the chance of being rate limited.

## `proxyConfiguration` (type: `object`):

REQUIRED IN PRACTICE. KRZ returns HTTP 403 to any IP outside Poland - verified with a real browser that completed the anti-bot challenge and was still refused. What is established is that the country matters; whether a Polish DATACENTER proxy is enough, or RESIDENTIAL is needed, has not yet been tested. RESIDENTIAL is the default because it is the safer of the two, but it is also the more expensive - try datacenter first and switch only if it is refused.

## Actor input object example

```json
{
  "companies": [
    {
      "krs": "0000026438",
      "externalId": "example-with-record"
    },
    {
      "krs": "0000127140",
      "externalId": "example-no-krz-record"
    },
    {
      "nip": "5250007738",
      "externalId": "example-by-nip"
    }
  ],
  "monitorMode": false,
  "includeHistorical": true,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "PL"
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One record per input company - source-scoped businessStatus, checkStatus, KRZ proceedings, and (in monitor mode) detected changes. NO\_KRZ\_RECORD is not a solvency clearance.

## `runSummary` (type: `string`):

Counts and cost metrics for the whole run: processed, successful, not found, failed, per-status totals, and request/browser counters.

# 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 = {
    "companies": [
        {
            "krs": "0000026438",
            "externalId": "example-with-record"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automa-flow/poland-krz-debtor-registry-insolvency-check").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 = { "companies": [{
            "krs": "0000026438",
            "externalId": "example-with-record",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("automa-flow/poland-krz-debtor-registry-insolvency-check").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 '{
  "companies": [
    {
      "krs": "0000026438",
      "externalId": "example-with-record"
    }
  ]
}' |
apify call automa-flow/poland-krz-debtor-registry-insolvency-check --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automa-flow/poland-krz-debtor-registry-insolvency-check"
        }
    }
}

```

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/T5Al78IbCgbnYWb4y/builds/1SXrmuGF5VkQd45tj/openapi.json
