Filling out order forms is one of the most frustrating aspects of online shopping. Customers must manually enter company details: name, address, postal code, city. If there’s an error – the invoice may be incorrect. Can this be simplified?
It turns out, yes. Polish public registries provide APIs that allow automatic retrieval of company data based on the tax identification number (NIP). In this article, I’ll describe how it works and what challenges you might encounter.
Why You Cannot Query KRS by NIP Directly
Many developers are surprised that it is not possible to search the official KRS API directly by NIP, even though the web-based KRS search form clearly allows this in the browser. In practice, the public API only exposes endpoints based on KRS number, so NIP-based lookup has to be implemented indirectly via other registries or commercial services.
In fact, there are several third‑party websites that sell access to their own APIs with NIP search support, usually priced per 1,000 requests, effectively reselling aggregated public data behind a paid interface. No clear public explanation is given why such functionality is not offered for free in the official API, but with the help of modern AI tools it is relatively easy to design and generate the code for a free, NIP‑driven integration that combines CEIDG, REGON and KRS.
The Problem: Three Different Registries for Different Company Types
Polish legal reality divides companies into several categories, and each is registered in a different database:
- CEIDG (Central Registration and Information on Business Activity) – sole proprietorships
- KRS (National Court Register) – commercial law companies (LLCs, joint-stock companies, etc.)
- REGON (National Business Registry) – all economic entities
The key problem: you cannot determine which registry a company is in based solely on the NIP number. NIP is just a tax identifier – it says nothing about the legal form of the business.
Strategy: Cascading Registry Queries
To retrieve complete company data, you must apply a “waterfall” strategy:
1. CEIDG First – Fastest and Simplest
CEIDG is the starting point because:
- It has the fastest API (REST, JSON)
- Doesn’t require complicated authorization
- Contains ~2.5 million sole proprietorships
CEIDG API v3:
- Endpoint: https://dane.biznes.gov.pl/api/ceidg/v3/firmy[dane.gov]
- Authorization: Bearer token (API key to generate on the portal at https://dane.biznes.gov.pl/pl/dane-po-api)
- Format: JSON
- Limit: no official limit, but throttling is recommended (e.g., 10 req/min)
If the company is in CEIDG – you have everything: name, NIP, REGON, business address. Done.
2. If Not in CEIDG – Check REGON
Absence from CEIDG likely means a corporate entity. Here, REGON (GUS API) comes to the rescue:
REGON API (BIR1):
- Endpoint: https://wyszukiwarkaregon.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc[api.stat.gov]
- Protocol: SOAP (yes, in 2026!)
- Authorization: API key from GUS (request via email to [email protected])
- Test key:
abcde12345abcde12345 - Documentation: https://api.stat.gov.pl/Home/RegonApi
REGON allows you to:
- Search for a company by NIP
- Retrieve basic data (name, REGON, entity type)
- Most importantly: obtain the KRS number (if the company has one)
Problem: REGON doesn’t contain the current registered address. That’s why another step is needed.
3. With KRS Number – Retrieve Full Data from KRS API
Having the KRS number, you can retrieve complete data from the court register:
KRS API:
- Endpoint:
https://api-krs.ms.gov.pl/api/krs/OdpisAktualny/{KRS} - Format: JSON
- Authorization: none (public API)
- Limit: 20 queries/minute
KRS returns complete data:
- Full company name
- Current registered address
- Management board information
- Share capital
- Company status
NIP Validation – Don’t Trust User Input
Before querying any API, validate the NIP on the application side:
NIP Format:
- 10 digits
- Optional “PL” prefix (for EU VAT)
- Checksum (algorithm with weights: 6,5,7,2,3,4,5,6,7)
Checksum validation saves unnecessary API calls and protects against transcription errors.
Rate Limiting – Don’t Block Your Access
Each API has limits:
- CEIDG: no official limit, but 10-20 req/min recommended
- REGON: ~10 queries/second (production key)
- KRS: 20 queries/minute
Solution: middleware throttling on the application side. Better to limit yourself (e.g., 3 queries per 5 seconds) than get banned by the API.
Error Handling – What Can Go Wrong?
Inactive Company
CEIDG returns company status. Check if status === 'ACTIVE' before filling out the form.[dane.gov]
Missing Address Data
Some companies in REGON don’t have a KRS number (e.g., foundations, associations). In such cases, return at least the name and NIP, and leave the address for manual completion.
API Timeout
External APIs may not respond. Set a timeout (e.g., 10-15 seconds) and display a friendly error message instead of an infinite loader.
Invalid API Key
CEIDG especially requires an active key. Log 401/403 errors and monitor whether the key has expired.
Caching – Don’t Query Every Time
Company data changes rarely. Consider:
- Caching responses for 24h-7 days
- Storing in Redis/Memcached
- Cache key:
company_data:{nip}
You save API queries and improve UX.
User Experience
From the user’s perspective, the process should look like this:
- Enter NIP in form field
- Click “Auto-fill”
- After 1-2 seconds, form fills with data
- Can edit data if something is incorrect
Important: always allow editing of retrieved data. The API may return outdated information or the user may want to use a different address (e.g., correspondence address).
Summary
Integration with Polish registries involves:
- 3 different APIs (CEIDG, REGON, KRS)
- Cascading strategy (CEIDG → REGON → KRS)
- NIP validation on client and server side
- Rate limiting (3-10 req/min)
- Error handling and timeouts
- Caching for 24h-7 days
The result? Instead of transcribing 5 form fields, the user only enters the NIP and clicks one button. Fewer errors, faster orders, better UX.
Is it worth it? Absolutely. Implementation takes 1-2 days, and every B2B customer placing an order benefits from it.
API Links and Documentation
CEIDG API (Central Registration and Information on Business Activity)
Official documentation:
- Main portal: https://dane.biznes.gov.pl/
- API v3 documentation: https://dane.biznes.gov.pl/api/ceidg/v3/swagger/index.html
- Registration and API key: https://dane.biznes.gov.pl/pl/dane-po-api
- API endpoint:
https://dane.biznes.gov.pl/api/ceidg/v3/firmy
REGON API (GUS BIR1)
Official documentation:
- Main portal: https://api.stat.gov.pl/Home/RegonApi
- Technical documentation: Available via GUS portal
- SOAP endpoint:
https://wyszukiwarkaregon.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc - Test key:
abcde12345abcde12345
PHP Library (used in project):
- GitHub: https://github.com/johnzuk/GusApi
- Installation:
composer require gusapi/gusapi
KRS API (National Court Register)
Official documentation:
- Main portal: https://api-krs.ms.gov.pl/
- Swagger documentation: https://api-krs.ms.gov.pl/swagger/index.html
- Endpoint:
https://api-krs.ms.gov.pl/api/krs/OdpisAktualny/{krs_number} - Format: JSON (REST API)
- No authorization required – public API
Additional Resources
NIP Validation:
- Tax office portal: https://www.gov.pl/web/kas/sprawdz-nip
- VAT database (checking VAT status): https://www.podatki.gov.pl/wykaz-podatnikow-vat-wyszukiwarka
Online search engines (for testing):
- CEIDG: https://prod.ceidg.gov.pl/CEIDG/CEIDG.Public.UI/Search.aspx
- REGON: https://wyszukiwarkaregon.stat.gov.pl/appBIR/index.aspx
- KRS: https://ekrs.ms.gov.pl/
Rate Limiting and Limits
- CEIDG: No official limit, max 20 req/min recommended
- REGON: ~10 queries/second (production key), 1 query/second (test key)
- KRS: 20 queries/minute (official limit)
Note: This article is based on a real implementation in an e-commerce system handling thousands of B2B orders monthly.

