How to Extract Polish Company Financial Data with a Single API Call
Ever needed financial data on a Polish company? Whether you're building a fintech app, doing competitor analysis, or automating due diligence, accessing data from Poland's National Court Register (KRS) can be... painful.
In this tutorial, I'll show you how to get balance sheets, income statements, and key financial metrics from any Polish company in under 30 seconds.
The Problem
Poland requires all companies to submit annual financial statements to the eKRS portal. This data is public, but:
- No official API exists
- Multiple page navigations required
- Files come in XML or XHTML format
-
Complex Polish accounting schemas (
AktywaRazem,KapitalWlasny,ZyskNetto...) - Different schemas for different accounting standards (UoR vs IFRS)
Building a scraper from scratch takes 20-40 hours. But that's just step one — then you need to parse the XML, which means learning Polish accounting terminology and handling multiple schema versions.
The Solution
We'll use the Poland KRS Financial Scraper Actor on Apify. It handles all the complexity — including XML parsing — and returns structured JSON with financial metrics ready to use.
Key benefit: You get totalAssets, equity, revenue, netProfit etc. directly in JSON — no XML parsing required on your end.
Prerequisites
- Free Apify account (sign up here)
- API token (found in Apify Console → Settings → Integrations)
- A Polish company's NIP (tax ID) or KRS number
Method 1: Using the Apify Console (No Code)
The simplest way to test:
- Go to the Actor page
- Enter input:
{
"krs": "0000023302"
}
- Click "Start"
- Wait ~30 seconds
- View results in the "Dataset" tab
Method 2: Using the API (JavaScript/Node.js)
For integration into your applications:
const Apify = require('apify-client');
const client = new Apify.ApifyClient({
token: 'YOUR_API_TOKEN',
});
async function getPolishCompanyFinancials(krsNumber) {
// Start the Actor
const run = await client.actor('minute_contest/poland-krs-financial-scraper').call({
krs: krsNumber
});
// Get results from dataset
const { items } = await client.dataset(run.defaultDatasetId).listItems();
return items[0];
}
// Example usage
const financials = await getPolishCompanyFinancials('0000023302');
console.log(financials);
Output:
{
"krs": "0000023302",
"year": 2024,
"fileName": "Sprawozdanie_finansowe_2024.xml",
"fileFormat": "xml",
"financials": {
"totalAssets": 54850000000,
"equity": 32100000000,
"fixedAssets": 42100000000,
"currentAssets": 12750000000,
"revenue": 33500000000,
"operatingProfit": 4200000000,
"netProfit": 2850000000
},
"success": true
}
Method 3: Using cURL
For quick command-line testing or integration with any language:
# Start the Actor and wait for results
curl -X POST "https://api.apify.com/v2/acts/minute_contest~poland-krs-financial-scraper/run-sync-get-dataset-items" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{"krs": "0000023302"}'
Method 4: Using Python
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
def get_polish_company_financials(krs_number):
run_input = {"krs": krs_number}
run = client.actor("minute_contest/poland-krs-financial-scraper").call(run_input=run_input)
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
return items[0] if items else None
# Example
financials = get_polish_company_financials("0000023302")
print(f"Total Assets: {financials['financials']['totalAssets']:,} PLN")
print(f"Net Profit: {financials['financials']['netProfit']:,} PLN")
Using NIP Instead of KRS
Don't have the KRS number? Use the company's NIP (tax ID) instead:
const financials = await getPolishCompanyFinancials({ nip: '8992736629' });
The Actor will automatically look up the KRS number from the NIP.
Understanding the Output
Parsed Financial Metrics
| Field | Polish Name | Description |
|---|---|---|
totalAssets |
Aktywa razem | Total assets |
fixedAssets |
Aktywa trwałe | Fixed/non-current assets |
currentAssets |
Aktywa obrotowe | Current assets |
equity |
Kapitał własny | Shareholders' equity |
revenue |
Przychody | Revenue from sales |
operatingProfit |
Zysk operacyjny | Operating profit |
netProfit |
Zysk netto | Net profit |
Raw Data Access
For custom parsing, the full XML/XHTML file is available in rawXml:
const { rawXml, fileFormat } = financials;
if (fileFormat === 'xml') {
// Parse Polish Accounting Standards format
const parser = new DOMParser();
const doc = parser.parseFromString(rawXml, 'text/xml');
// Custom extraction...
}
Real-World Use Cases
1. Competitor Analysis Dashboard
const competitors = ['0000023302', '0000012345', '0000067890'];
const results = await Promise.all(
competitors.map(krs => getPolishCompanyFinancials(krs))
);
// Compare metrics
results.forEach(company => {
console.log(`KRS ${company.krs}: Revenue ${company.financials.revenue}`);
});
2. Automated Due Diligence
async function dueDiligenceCheck(nip) {
const financials = await getPolishCompanyFinancials({ nip });
const checks = {
hasPositiveEquity: financials.financials.equity > 0,
isProfitable: financials.financials.netProfit > 0,
currentRatio: financials.financials.currentAssets /
(financials.financials.totalAssets - financials.financials.equity)
};
return { financials, checks };
}
3. Bulk Data Collection
const companies = readCSV('polish_companies.csv'); // List of KRS numbers
for (const krs of companies) {
const data = await getPolishCompanyFinancials(krs);
await saveToDatabase(data);
await sleep(1000); // Rate limiting
}
Pricing
The Actor uses pay-per-result pricing:
- ~$0.03 per successful extraction
- No subscription required
- Free tier available for testing
Error Handling
const result = await getPolishCompanyFinancials('0000023302');
if (!result.success) {
console.error(`Error: ${result.error}`);
// Common errors:
// - "Company not found" - Invalid KRS number
// - "No financial statements" - Company hasn't filed yet
// - "Multiple formats" - Handle XHTML separately
}
Conclusion
Accessing Polish company financial data doesn't have to be complicated. With a single API call, you can get structured financial metrics ready for analysis.
Links:
Have questions? Drop them in the comments!
Top comments (0)