# Polish Company Register (KRS) API → Clean JSON (`quietpinelabs/pl-krs-company`) Actor

Company profiles from the official Polish KRS open API (Ministry of Justice, CC0) by KRS number: name, legal form, status, address, NIP/REGON, PKD→NACE, share capital, masked officers. No scraping, no personal identifiers.

- **URL**: https://apify.com/quietpinelabs/pl-krs-company.md
- **Developed by:** [Quietpine Labs](https://apify.com/quietpinelabs) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 krs extracts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Polish company data from the KRS open API as clean JSON — by KRS number

Get the court-register extract (*odpis*) of a Polish company, association or foundation from the **Krajowy Rejestr Sądowy** through the Ministry of Justice's official open API and receive one schema-validated JSON profile per entity: name, legal form, status, registered address, NIP and REGON, PKD activities mapped to NACE Rev. 2, share capital, registration court and officers exactly as the Ministry publishes them (masked). The actor calls only the two published open endpoints (no search-UI scraping, no PDFs) and never un-masks or adds personal identifiers. The data are CC0 (public domain).

**Status note:** the Ministry's API served a maintenance page ("Przerwa techniczna") throughout this actor's build, so it was built and tested against recorded Ministry responses, not verified live. While the API is down the actor fails with a clear "maintenance page" error and charges nothing.

### Who uses it

- **KYC/AML and supplier-onboarding teams** — confirm a KRS number, legal form, NIP/REGON, status and who sits on the board.
- **Credit-risk, legal and procurement teams** — detect liquidation, bankruptcy or restructuring from the register itself; feed the dataset to Make, Zapier or n8n.
- **Data journalists and researchers** — structured extracts instead of PDF parsing, with PKD codes as NACE.

### Use cases

**1. Enrich a list of KRS numbers:**

```json
{ "krsNumbers": ["0000028860", "0000026438"] }
```

One current extract per number found (ORLEN S.A. and PKO BP S.A. in this example).

**2. Full extract with history for due diligence:**

```json
{ "krsNumbers": ["0000032267"], "fullExtract": true }
```

Adds previous names with dates, officer appointment dates, the registration court and, for struck-off entities, the deletion date (`status: dissolved`).

**3. Foundations and associations, watched for changes (schedule daily):**

```json
{ "krsNumbers": ["0000101821"], "register": "S", "mode": "incremental" }
```

Only extracts whose content changed since the previous run are returned and charged.

### Input

| Field | Type | Default | Meaning |
|---|---|---|---|
| `krsNumbers` | string\[] | `["0000028860","0000026438"]` | 1–10 digits, zero-padded to 10; up to 5,000 per run; duplicates merged; invalid values counted in `STATS.invalidKrs`. |
| `register` | `P` / `S` | `P` | `P` = rejestr przedsiębiorców (companies, partnerships, cooperatives, branches); `S` = associations, foundations, other organisations, SP ZOZ. A number exists in exactly one; the wrong one yields 404 (not charged). |
| `fullExtract` | boolean | `false` | Use `OdpisPelny` instead of `OdpisAktualny` (5–10× larger upstream response, same price). |
| `includeOfficers` | boolean | `true` | Management board, supervisory bodies, commercial proxies and liquidators with masked names, role and (full extract) appointment date. |
| `mode` | `full` / `incremental` | `full` | See *Incremental mode*. |
| `maxRecords` | integer | `1000` | Stop after this many records. |
| `icos`, `region`, `dateFrom`, `dateTo` | – | ignored | Common fields of the CEE actor family; not applicable to KRS. |
| `name` | string | – | **Unsupported** — the open API has no name search; setting it fails the run with a pointer to the official search UI. |

### Output

One `CompanyProfile` per extract found. Sample mapped from a recorded Ministry response (`OdpisAktualny`, register P, response captured 2026-09-03; NACE and officer lists shortened):

```jsonc
{
  "country": "PL", "id": "0000026438", "idType": "krs",
  "name": "POWSZECHNA KASA OSZCZĘDNOŚCI BANK POLSKI SPÓŁKA AKCYJNA",
  "kind": "legal-person",
  "legalForm": { "code": "SPÓŁKA AKCYJNA", "label": "Joint-stock company (S.A.)" },
  "status": "active",
  "registeredAddress": { "street": "UL. ŚWIĘTOKRZYSKA", "houseNumber": "36", "city": "WARSZAWA", "postalCode": "00-116", "region": "MAZOWIECKIE", "country": "PL", "formatted": "UL. ŚWIĘTOKRZYSKA 36, 00-116 WARSZAWA, PL" },
  "nace": {
    "main": { "code": "64.19", "label": "Other monetary intermediation", "section": "K", "raw": "64.19.Z" },
    "other": [ { "code": "64.91", "label": "Financial leasing", "section": "K", "raw": "64.91.Z" } /* … 4 more */ ]
  },
  "vatId": "PL5250007738",
  "otherIds": { "nip": "5250007738", "regon": "016298263" },
  "establishedOn": "2001-07-12",
  "registrations": [
    { "register": "KRS", "registerCode": "RejP", "number": "0000026438" },
    { "register": "RHB", "number": "60069", "court": "SĄD REJONOWY DLA M. ST. WARSZAWY XVI WYDZIAŁ GOSPODARCZY-REJESTROWY" }
  ],
  "officers": [
    { "name": "S***** K******** M*****", "role": "PREZES ZARZĄDU", "roleCode": "management" },
    { "name": "M***** C***********", "role": "CZŁONEK RADA NADZORCZA", "roleCode": "supervisory" },
    { "name": "D***** B**** S********", "role": "PROKURENT", "roleCode": "proxy" }
    // … 19 more; the first management officer also carries `representation` (sposób reprezentacji)
  ],
  "shareCapital": { "amount": 1250000000, "currency": "PLN" },
  "previousNames": [],
  "provenance": {
    "source": "pl-krs",
    "sourceName": "Krajowy Rejestr Sądowy – API KRS, Ministerstwo Sprawiedliwości",
    "sourceUrl": "https://api-krs.ms.gov.pl/api/krs/OdpisAktualny/0000026438?rejestr=P&format=json",
    "licence": "Źródło: Krajowy Rejestr Sądowy, Ministerstwo Sprawiedliwości (https://api-krs.ms.gov.pl), public domain (CC0 1.0) …",
    "retrievedAt": "2026-10-18T00:00:00.000Z", "sourceUpdatedAt": "2026-07-09"
  }
}
```

Other fields: `status` is `active`, `in-liquidation`, `in-insolvency` or `dissolved` (precedence dissolved > insolvency > liquidation), derived from dział 6 proceedings, the full-extract deletion entry and the name suffixes `W LIKWIDACJI` / `W UPADŁOŚCI`; `dissolvedOn` (full extract only); `kind` is `public-body` for SP ZOZ, research institutes and state or self-government institutions in register S; `establishedOn` is the **KRS registration date** (2001 or later for companies migrated from the old RHB register), not the founding date; `provenance.sourceUpdatedAt` is the date of the last entry. Shareholders are not output (natural-person shareholders are personal data; corporate ones are a planned opt-in). `STATS` in the key-value store counts found, not-found (404), struck-off (204), rejected, unchanged and invalid numbers.

### Pricing in plain words

You pay **$3 per 1,000 extracts returned**, plus $0.00005 per run start. Empty results are free: unknown numbers (404), struck-off entities on the current extract (204), rejected or invalid numbers and unchanged extracts in incremental mode are never charged. If the Ministry's API is down, the run fails before charging anything. On the free plan ($5 monthly credit) that is about 1,600 extracts a month. Bronze, Silver and Gold volume discounts are configured on the store page. The run stops gracefully at `maxRecords` or your maximum total charge.

### Limits & fair use

- The Ministry states the API "nie posiada limitów pobrań" (no download limits) and needs no token; third parties observe about 2 requests per second and occasional 429s. This actor paces at **1.5 requests per second, concurrency 1**, retries 429/5xx/timeouts with exponential back-off honouring `Retry-After`, and aborts with a clear error if 429/403 persists.
- Maintenance ("Przerwa techniczna") comes back as HTTP 200 with an HTML page; the actor detects it and fails fast with "maintenance page … retry later" — nothing is charged. Observed for a whole day during the build.
- 5,000 numbers per run take about 56 minutes; split larger lists. Only `OdpisAktualny` and `OdpisPelny` are ever requested; nothing else on `*.ms.gov.pl`.

### Incremental mode

The cursor is kept in the run's default key-value store under `CURSOR` **and mirrored to the named key-value store `pl-krs-company-cursor`** (override with the `cursorStore` input, one per watch-list), so it survives across runs and tasks. Format: `{ "value": { "<krs>": "<content-hash>" }, "updatedAt": "…" }` . The hash covers the whole mapped record except `provenance.retrievedAt`. On the next run with the same `krsNumbers`, only extracts whose hash changed (new entry, officer, status or address) are returned and charged; unchanged ones are counted in `STATS.unchanged`. The first run returns everything; numbers not pushed because the budget was reached are not marked as seen. A mode driven by the Ministry's daily and hourly bulletins of changed KRS numbers is planned once their URL pattern is confirmed.

### Data protection

KRS data are public by law (ustawa o Krajowym Rejestrze Sądowym, art. 4 ust. 4a) and the open API already masks natural persons' names (`K******** D******`) and PESEL numbers. This actor goes further:

- **never outputs** PESEL (even masked), registered e-mail or e-delivery addresses, the free-text descriptions of liquidation, bankruptcy, statute changes, prokura and mergers (they contain notary and court-officer names in clear text), natural-person shareholders, or anything from dział 4–5;
- returns **officers only as the Ministry masks them** and never attempts to un-mask or re-identify them — no search-UI or PDF scraping, which is exactly what art. 60a of the 2025 KRS amendment (Dz.U. 2025 poz. 1556) penalises; set `includeOfficers: false` to drop them entirely;
- applies a key deny-list to every record as a last line of defence;
- stores no personal data on the developer's side — datasets live in your Apify storage; only cursors and counters are kept.

Natural-person entrepreneurs are not in the KRS (they are in CEIDG), so the register contains legal persons only. Lawful basis for the processing inside a run is Art. 6(1)(f) GDPR — legitimate interest in making statutorily public register data about economic entities machine-readable for due diligence, KYC/AML, procurement and journalism. You are the controller of what you download. Corrections or removals of register content must be requested from Centralna Informacja KRS (Ministerstwo Sprawiedliwości); `provenance.sourceUrl` is the API URL of the extract. This section describes the actor's behaviour and is not legal advice.

### FAQ

**Why 404 for a company that exists?** Wrong register. Companies, partnerships, cooperatives and branches are in `P`; associations, foundations, trade unions and SP ZOZ in `S`. Some foundations that run a business are in both.

**The number is right but nothing comes back.** The entity was struck off: the current extract answers HTTP 204 (`STATS.struckOff`). Run with `fullExtract: true` to get the deletion record with `status: dissolved` and `dissolvedOn`.

**Can I search by name, NIP or REGON?** No — the open API has none. Find the number at https://wyszukiwarka-krs.ms.gov.pl/ or use the GUS REGON (BIR 1.1) or MF VAT white-list APIs as a NIP → KRS bridge; neither is part of this actor.

**Why are officer names masked?** The Ministry masks them in the open API; full names are reserved for authorised public bodies. The actor passes the masked tokens through unchanged.

**Who invoices me?** Apify. Usage is billed to your Apify account; the developer never sees your data or payment details.

### Source & licence

Źródło: Krajowy Rejestr Sądowy, Ministerstwo Sprawiedliwości (https://api-krs.ms.gov.pl), public domain (CC0 1.0) per dane.gov.pl dataset 27606. Personal identifiers are masked by the Ministry and never un-masked here.

Dataset: https://dane.gov.pl/pl/dataset/27606,api-krajowego-rejestru-sadowego-api-krs ("API nie wymaga tokenu i nie posiada limitów pobrań. Dane udostępniane są w domenie publicznej."). Attribution is not required under CC0 but is carried in every record's `provenance.licence`. Data are informative in character; the binding extract is the one issued by the court. Not affiliated with Ministerstwo Sprawiedliwości (the Polish Ministry of Justice).

### Changelog / support

- 0.1 — first public release: current and full extracts by KRS number, register P/S, masked officers, incremental content-hash mode. Built against recorded Ministry responses; live verification pending the end of the API maintenance.

Questions, bugs and feature requests: use the **Issues** tab of this actor.

Documentation drafted with AI assistance and reviewed by the publisher before publication.

# Actor input Schema

## `krsNumbers` (type: `array`):

Krajowy Rejestr Sądowy numbers (1–10 digits; zero-padded to 10 automatically). Up to 5,000 per run; duplicates are merged. Unknown numbers (HTTP 404) and struck-off entities (HTTP 204) are reported in the STATS record and are not charged. Default: ORLEN S.A. and PKO BP S.A.

## `register` (type: `string`):

`P` = rejestr przedsiębiorców (companies, partnerships, cooperatives, branches). `S` = rejestr stowarzyszeń, fundacji, innych organizacji społecznych i zawodowych oraz SP ZOZ. A KRS number exists in exactly one of them; a lookup in the wrong one returns 404.

## `fullExtract` (type: `boolean`):

Use `OdpisPelny` instead of `OdpisAktualny`: adds previous names with dates, officer appointment dates, the registration court and the deletion date of struck-off entities (status `dissolved`). ~5–10× larger upstream responses; same price per record.

## `includeOfficers` (type: `boolean`):

Return management board, supervisory body members, commercial proxies and liquidators as the Ministry publishes them: names are masked by the source (e.g. `K******** D******`), with role and (full extract) appointment date. PESEL and free-text descriptions are never returned.

## `mode` (type: `string`):

`full` returns every extract found. `incremental` stores a content hash per KRS number in the key-value store (key `CURSOR`) and returns only extracts that changed since the previous run with the same input (first run returns everything).

## `maxRecords` (type: `integer`):

Stop after this many records (budget guard).

## `icos` (type: `array`):

Common field of the CEE registry actors; not applicable to Poland and ignored here. Use `krsNumbers`.

## `name` (type: `string`):

Not supported — the KRS open API has no name search. Setting it fails the run with an explanation; look the number up at https://wyszukiwarka-krs.ms.gov.pl/ instead.

## `region` (type: `string`):

Not applicable to KRS extracts; ignored.

## `dateFrom` (type: `string`):

Not applicable to KRS extracts; ignored.

## `dateTo` (type: `string`):

Not applicable to KRS extracts; ignored.

## `cursorStore` (type: `string`):

Named key-value store that keeps the incremental-mode cursor across runs (default `pl-krs-company-cursor`). Use a different name per watch-list.

## Actor input object example

```json
{
  "krsNumbers": [
    "0000028860",
    "0000026438"
  ],
  "register": "P",
  "fullExtract": false,
  "includeOfficers": true,
  "mode": "full",
  "maxRecords": 1000
}
```

# Actor output Schema

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

All records returned by this run (full JSON).

## `overview` (type: `string`):

No description

## `stats` (type: `string`):

Records requested, returned and charged, plus source request counts.

# 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 = {
    "krsNumbers": [
        "0000028860",
        "0000026438"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("quietpinelabs/pl-krs-company").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 = { "krsNumbers": [
        "0000028860",
        "0000026438",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("quietpinelabs/pl-krs-company").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 '{
  "krsNumbers": [
    "0000028860",
    "0000026438"
  ]
}' |
apify call quietpinelabs/pl-krs-company --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,quietpinelabs/pl-krs-company"
        }
    }
}
```

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/4uBmqgxWW0ll6DvPH/builds/S4QWBHMgJmyHWTJe3/openapi.json
