Guide · Python · SDK · REST API

KRS Validation in Python

The Polish National Court Register number — a 10-digit identifier for companies, associations, and foundations. Here's how to validate it and look up entity data in Python.

1. What is a KRS number?

KRS (Krajowy Rejestr Sadowy — National Court Register) is a centralised public registry maintained by the Ministry of Justice of Poland. Every company, association, foundation, and certain other legal entities registered in Poland receives a unique KRS number. It serves as the primary identifier in:

  • B2B contracts and invoicing between Polish companies
  • Public procurement and tender processes
  • Due diligence and KYC/AML checks
  • Cross-referencing with NIP (tax) and REGON (statistical) registries
  • Court filings and legal proceedings

The KRS database is split into two main registries:

RegistryCodeContains
Register of EntrepreneursPSp. z o.o., S.A., partnerships, cooperatives, state enterprises
Register of AssociationsSAssociations, foundations, public benefit organisations (OPP)
ℹ️A single entity can appear in both registries — for example, a foundation that also conducts commercial activity will have entries in both S (associations) and P (entrepreneurs).

2. KRS structure

A KRS number is a simple 10-digit zero-padded sequential number. Unlike NIP or REGON, KRS does not contain a check digit — there is no built-in checksum algorithm to verify structural correctness.

PropertyValue
Length1 to 10 digits (zero-padded to 10 in the official registry)
Character setDigits only (0–9)
AssignmentSequential — numbers are assigned in order of registration
Check digitNone — no built-in checksum
EntityKRSRegistry
CREACT.DEV SP. Z O.O.0000896246P (Entrepreneurs)
PKN ORLEN S.A.0000028860P (Entrepreneurs)
⚠️Because KRS has no check digit, format validation alone cannot catch typos. A mistyped digit will still produce a valid-looking 10-digit number. The only way to confirm a KRS number is correct is to look it up against the government registry.

3. Why KRS validation matters

Company verification in B2B transactions

Polish law requires KRS numbers on invoices and contracts for registered entities. Validating the KRS before signing a contract confirms the counterparty actually exists and is registered with the court.

NIP and REGON cross-referencing

Every KRS entry contains the entity's NIP (tax number) and REGON (statistical number). By looking up a KRS number, you can verify all three identifiers match, catching inconsistencies that might indicate fraud or data entry errors.

Due diligence and compliance

KYC/AML processes for Polish entities require checking the KRS registry. The lookup reveals the legal form, registered address, and whether the entity holds OPP (public benefit organisation) status.

Public procurement

Tenders in Poland require bidders to provide a valid KRS number. Automated validation ensures that only properly registered entities can participate, reducing manual verification workload.


4. The right solution: one API call

The IsValid KRS API handles format validation and government registry lookup in a single GET request:

1

Format validation

1-10 digits, all numeric, zero-padded

2

Government registry lookup (optional)

Entity name, legal form, NIP, REGON, and full address from the official KRS database

3

NIP / REGON extraction

Cross-reference tax and statistical identifiers from a single KRS query

4

Address data

Full registered address including city, voivodeship, street, and postal code

Get your free API key at isvalid.dev. The free tier includes 100 calls per day with no credit card required.

Full parameter reference and response schema: KRS Validation API docs →


5. Python code example

Using the isvalid-sdk Python SDK or the requests library. Install with pip install isvalid-sdk or pip install requests.

# krs_validator.py
import os
from isvalid_sdk import IsValidConfig, create_client

iv = create_client(IsValidConfig(api_key=os.environ["ISVALID_API_KEY"]))

# ── Basic validation ────────────────────────────────────────────────────────
result = iv.pl.krs("0000896246")

if not result["valid"]:
    print("Invalid KRS number")
else:
    print(f"KRS: {result['number']}")  # "0000896246"

# ── With government registry lookup ─────────────────────────────────────────
detailed = iv.pl.krs("0000896246", lookup=True)

if detailed["valid"] and detailed.get("krs", {}).get("found"):
    print(f"Name     : {detailed['krs']['name']}")
    print(f"Registry : {detailed['krs']['registry']}")    # "P" or "S"
    print(f"NIP      : {detailed['krs']['nip']}")
    print(f"REGON    : {detailed['krs']['regon']}")
    print(f"City     : {detailed['krs']['address']['city']}")
    print(f"OPP      : {detailed['krs']['hasOppStatus']}")
The lookup parameter is optional. Use it when you need the entity's name, NIP, REGON, or address. Omit it for fast format-only validation.

6. cURL examples

Basic format validation:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/pl/krs?value=0000896246"

With government registry lookup:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/pl/krs?value=0000896246&lookup=true"

7. Understanding the response

Valid KRS (basic)

{
  "valid": true,
  "number": "0000896246"
}

Valid KRS (with lookup)

{
  "valid": true,
  "number": "0000896246",
  "krs": {
    "checked": true,
    "found": true,
    "krs": "0000896246",
    "registry": "P",
    "name": "CREACT.DEV SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ",
    "legalForm": "SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ",
    "nip": "5252859428",
    "regon": "388770013",
    "hasOppStatus": false,
    "registeredAt": "2021-04-21",
    "dataAsOf": "2026-01-15",
    "lastEntryAt": "2026-01-14",
    "address": {
      "city": "WARSZAWA",
      "voivodeship": "MAZOWIECKIE",
      "street": "UL. ŚWIĘTOKRZYSKA",
      "houseNumber": "30",
      "flatNumber": "63",
      "postalCode": "00-116",
      "country": "POLSKA",
      "website": "HTTPS://CREACT.DEV/"
    }
  }
}

Invalid KRS

{ "valid": false }
FieldTypeDescription
validbooleanWhether the KRS number passed format validation
numberstringThe zero-padded 10-digit KRS number. Only present when valid: true
krs.registrystring"P" (Entrepreneurs) or "S" (Associations)
krs.namestringFull legal name of the entity
krs.legalFormstringLegal form (e.g. Sp. z o.o., S.A., Fundacja)
krs.nipstringNIP (tax identification number)
krs.regonstringREGON (statistical registry number)
krs.hasOppStatusbooleanWhether the entity has OPP (public benefit organisation) status
krs.registeredAtstringDate when the entity was first registered in KRS (ISO 8601)
krs.dataAsOfstringDate of the data snapshot from the registry
krs.lastEntryAtstringDate of the most recent entry/modification in the registry
krs.addressobjectRegistered address with city, voivodeship, street, houseNumber, flatNumber, postalCode, country, and website

8. Edge cases to handle

(a) Leading zeros

KRS numbers are zero-padded to 10 digits. A company registered early might have a KRS like 0000028860. Do not store KRS numbers as integers — use strings to preserve leading zeros. The API accepts both 28860 and 0000028860 and normalises the value.

# WRONG — loses leading zeros
krs = int("0000028860")  # 28860

# CORRECT — preserve as string
krs = "0000028860"

(b) Register P vs Register S

The registry field in the lookup response tells you whether the entity is in the Entrepreneurs register (P) or the Associations register (S). This distinction matters for compliance — a foundation (register S) has different legal obligations than a commercial company (register P).

result = iv.pl.krs("0000896246", lookup=True)

if result["valid"] and result.get("krs", {}).get("found"):
    if result["krs"]["registry"] == "P":
        print("Commercial entity — standard B2B flow")
    elif result["krs"]["registry"] == "S":
        print("Association/foundation — verify OPP status")

(c) OPP status (public benefit organisations)

Entities with hasOppStatus: true are registered as Organisations of Public Benefit (Organizacja Pozytku Publicznego). These entities can receive 1.5% of personal income tax from taxpayers. Check this field when building donation platforms or tax-deduction workflows.

result = iv.pl.krs("0000896246", lookup=True)

if result["valid"] and result.get("krs", {}).get("found"):
    if result["krs"]["hasOppStatus"]:
        print("This entity can receive 1.5% tax donations")

(d) Dissolved companies

A KRS number that passes format validation may belong to a dissolved or deregistered entity. When the lookup returns a result, check whether the entity is still active. The lastEntryAt and dataAsOf fields help you determine whether the data is current.

result = iv.pl.krs("0000896246", lookup=True)

if result["valid"] and result.get("krs"):
    if not result["krs"]["found"]:
        print("KRS number not found — entity may be dissolved")
    else:
        print(f"Last entry: {result['krs']['lastEntryAt']}")
        print(f"Data as of: {result['krs']['dataAsOf']}")

(e) Cross-referencing with REGON and NIP

The KRS lookup returns both nip and regon fields. Use these to cross-reference with data provided by the entity. If a business partner gives you a KRS, NIP, and REGON, you can validate all three in a single KRS lookup and check they match.

result = iv.pl.krs("0000896246", lookup=True)

if result["valid"] and result.get("krs", {}).get("found"):
    expected_nip = "5252859428"
    expected_regon = "388770013"

    if result["krs"]["nip"] != expected_nip:
        print("NIP mismatch!")
    if result["krs"]["regon"] != expected_regon:
        print("REGON mismatch!")

9. Summary

Do not store KRS as an integer — leading zeros will be lost
Do not rely on format checks alone — KRS has no check digit, so typos slip through
Do not assume a found entity is still active — check lastEntryAt and dataAsOf
Use lookup=True for due diligence — returns name, legal form, NIP, REGON, and full address
Cross-reference NIP and REGON from the KRS response with data provided by the entity
Check hasOppStatus for non-profit workflows — identifies public benefit organisations

See also

Validate KRS numbers instantly

Free tier includes 100 API calls per day. No credit card required. Format validation and optional government registry lookup included.