
Apify Public Registries
- 95 installs
- 239 repo stars
- Updated June 29, 2026
- apify/awesome-skills
apify-public-registries is a Claude skill that looks up official company data (registration, ownership, filings, VAT, ESG) from European public registries across 11 countries and regions.
About
This skill looks up official company data from European public registries across 11 countries and regions, including EU-level and ESG sources. A developer uses it for company due diligence, checking VAT status, finding ownership structure, or resolving identifiers like IČO, KRS, or LEI. It calls direct REST APIs via Python where they exist and falls back to Apify actors for scraping-based registries.
- Looks up official company data across 11 European countries/regions plus EU-level and ESG
- Uses stdlib Python REST scripts where APIs exist and falls back to Apify actors for scraping-only registries
- Covers registration, ownership, financial filings, VAT status, and ESG data
Apify Public Registries by the numbers
- 95 all-time installs (skills.sh)
- Ranked #830 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
apify-public-registries capabilities & compatibility
Most country lookups are free stdlib API calls; some (NL KVK, PL GUS, SE, HR) require registration, and Apify-fallback registries consume Apify credits.
- Capabilities
- due diligence · company lookup · web scraping
- Use cases
- research · data analysis · web scraping
- Pricing
- Freemium
What apify-public-registries says it does
Look up official company data from European public registries across 11 countries/regions (CZ, SK, PL, DE, UK, NL, RO, HR, SE + EU-level + ESG).
Some lookups use Python scripts (stdlib), some fall back to Apify actors for scraping-based registries.
npx skills add https://github.com/apify/awesome-skills --skill apify-public-registriesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 95 |
|---|---|
| repo stars | ★ 239 |
| Last updated | June 29, 2026 |
| Repository | apify/awesome-skills ↗ |
What it does
Look up official European company registration, ownership, filings, and VAT data across 11 registries.
Who is it for?
Company due diligence and official registry lookups across European jurisdictions.
Skip if: News or social sentiment (use apify-financial-news or apify-financial-osint).
When should I use this skill?
The user asks to look up a company, check a registry, verify VAT status, find ownership structure, or resolve IČO/KRS/LEI.
What you get
Interpreted registry results (profile, ownership, filings, VAT, ESG) per country and identifier.
- Official company registry records per country and identifier
By the numbers
- 11 countries/regions covered
- Step 0 to Step 3 workflow checklist
Files
Public Company Registries — 11 Countries
Look up official company data from European public registries via Python scripts (direct REST API) or Apify actor fallback (scraping when no API exists).
Prerequisites
- Python 3 (scripts use stdlib — no pip dependencies for most countries)
- Apify access (only for DE, UK, PL financials, CZ justice.cz, RO fallback) — preferred:
apifyCLI (npm install -g apify-cli && apify login); fallback: Apify MCP connector (call-actortool). CLI is faster and preferred when both are available. - NL:
KVK_API_KEYenv var (register at developers.kvk.nl — see REGISTRATION/NL.md) - PL GUS:
GUS_API_KEYenv var (email regon_bir@stat.gov.pl) - SE: Bolagsverket requires registration (see REGISTRATION/SE.md)
- HR: Sudski registar requires OAuth registration (see REGISTRATION/HR.md)
${CLAUDE_PLUGIN_ROOT} is the plugin's root directory (where .claude-plugin/ lives). It is resolved automatically by Claude Code when the plugin is installed, or set to the --plugin-dir path during development.
Workflow checklist
Copy this and tick boxes as you progress:
Task Progress:
- [ ] Step 0: Verify prerequisites — run `python3 --version` (required); for Apify-dependent registries: try `apify --version && apify info`, or check for `call-actor` MCP tool; if neither, tell user to install apify CLI or Apify MCP connector
- [ ] Step 1: Identify country + identifier type (IČO/KRS/CUI/LEI/company name)
- [ ] Step 2: Run the lookup command per country table
- [ ] Step 3: Interpret results (key fields vary by source)
- [ ] Optional: Apify fallback for scraping-based registries
- [ ] Optional: Cross-reference with EU-level sources (GLEIF LEI, ESMA bonds, EBA)Quick Reference — Lookup by Country
All paths relative to ${CLAUDE_PLUGIN_ROOT}/skills/apify-public-registries/.
| Country | Command | Identifier | Access |
|---|---|---|---|
| CZ | python3 reference/scripts/CZ/fetch_all.py lookup <IČO> | IČO (8-digit) | Free (ARES API) |
| SK | python3 reference/scripts/SK/fetch_all.py lookup <IČO> | IČO | Free (ORSR scraping) |
| PL | python3 reference/scripts/PL/fetch_all.py lookup <KRS> | KRS (10-digit, zero-padded) | Free (KRS API) |
| PL | python3 reference/scripts/PL/fetch_all.py lookup_nip <NIP> | NIP (10-digit) | Free (Biała Lista, 100/day) |
| PL GUS | (included in batch fetch_all.py) | NIP | `GUS_API_KEY` REQUIRED — without it, returns fake test data silently (see gotchas) |
| DE | python3 reference/scripts/DE/fetch_all.py keyword <name> | Company name | Apify (mcpc CLI) |
| UK | python3 reference/scripts/UK/fetch_all.py search <name> | Company name | Apify (mcpc CLI) |
| NL | python3 reference/scripts/NL/fetch_all.py | KVK number (configured) | API key (KVK_API_KEY) |
| RO | python3 reference/scripts/RO/fetch_all.py lookup <CUI> | CUI number | Free (ANAF — offline since 2026-03) |
| HR | Manual — see REGISTRATION/HR.md | OIB / MBS | OAuth registration |
| SE | Manual — see REGISTRATION/SE.md | Org.nr | Bolagsverket registration |
| EU | python3 reference/scripts/EU/fetch_all.py lookup <name> | Company name | Free (GLEIF + ESMA + TED) |
| EU | python3 reference/scripts/EU/fetch_all.py lookup_lei <LEI> | LEI (20-char) | Free (GLEIF) |
| ESG | python3 reference/scripts/ESG/fetch_all.py lookup <country> | Country name/ISO code | Free |
By Data Type
| Need | Best source | Command |
|---|---|---|
| Basic profile (name, address, legal form) | CZ: ARES, SK: ORSR, PL: KRS, DE: Handelsregister, UK: Companies House | See country table above |
| Ownership / corporate tree | EU GLEIF | EU/fetch_all.py lookup_lei <LEI> |
| Financial filings (CZ) | Justice.cz sbírka listin (Apify fallback) | CZ/fetch_all.py justice |
| Financial filings (SK) | FinStat.sk | SK/fetch_all.py finstat |
| Financial filings (PL) | eKRS via Apify | PL/fetch_all.py financials |
| Bonds & instruments | ESMA FIRDS | EU/fetch_all.py lookup <name> |
| VAT / due diligence (CZ) | DPH register | Included in CZ/fetch_all.py lookup |
| VAT / due diligence (PL) | Biała Lista | PL/fetch_all.py lookup_nip <NIP> |
| Bank regulatory data | EBA Transparency CSVs (100MB+) | EU/fetch_all.py eba |
| ESG / emissions | Climate TRACE + EU ETS | ESG/fetch_all.py lookup <country> |
| Regulated entities (CZ) | ČNB bank list + OAM | CZ/fetch_all.py cnb_banks / cnb_oam |
| Public procurement | TED | EU/fetch_all.py lookup <name> |
Step 1: Identify country + identifier
- Check
${CLAUDE_PLUGIN_ROOT}/data/companies.json->identifiers.registry_idsfor existing IDs. - If identifier unknown, start with EU GLEIF by name — returns LEI + registered-as numbers usable in country-specific lookups.
Identifier types by country:
- CZ/SK: IČO (8-digit)
- PL: KRS (10-digit zero-padded) or NIP (10-digit)
- DE: Company name keyword
- UK: Company name
- NL: KVK number (8-digit)
- RO: CUI (numeric)
- HR: OIB (11-digit) or MBS
- SE: Organisationsnummer (10-digit, e.g. 559124-6847)
- EU: LEI (20-char alphanumeric) or company name
Step 2: Run lookup
Execute the command from the country table. Scripts are at: ${CLAUDE_PLUGIN_ROOT}/skills/apify-public-registries/reference/scripts/<CC>/fetch_all.py
Example — look up a company in Czech ARES:
python3 ${CLAUDE_PLUGIN_ROOT}/skills/apify-public-registries/reference/scripts/CZ/fetch_all.py lookup 25099345Example — find ownership chain via GLEIF:
python3 ${CLAUDE_PLUGIN_ROOT}/skills/apify-public-registries/reference/scripts/EU/fetch_all.py lookup_lei 31570048XH84U51GGT05Example — look up InPost in KRS:
python3 ${CLAUDE_PLUGIN_ROOT}/skills/apify-public-registries/reference/scripts/PL/fetch_all.py lookup 0000536554Batch fetch (all companies in a country):
python3 reference/scripts/CZ/fetch_all.py # all CZ sources (ares, dph, cnb_banks, cnb_oam, justice)
python3 reference/scripts/PL/fetch_all.py # all PL sources (krs, biala_lista, gus, financials)
python3 reference/scripts/EU/fetch_all.py # all EU sources except EBA (gleif, ted, esma, eurostat)Step 3: Interpret results
Key fields vary by source:
| Source | Key fields |
|---|---|
| ARES (CZ) | obchodniJmeno, dic, sidlo.textovaAdresa, czNace, datumVzniku, pravniForma |
| DPH (CZ) | nespolehlivyPlatce (unreliable payer flag), bank accounts |
| GLEIF (EU) | lei, legalName, jurisdiction, status, registeredAs, parent LEI + name |
| KRS (PL) | nazwa, nip, regon, kapital (share capital) |
| Biała Lista (PL) | statusVat, krs, regon, accountNumbers |
| ORSR (SK) | name, address, legal_form, share_capital, registration_date |
| FinStat (SK) | revenue, profit, employees, assets |
| Handelsregister (DE) | name, legal form, share capital, management, HRB number |
| Companies House (UK) | company number, SIC codes, directors, incorporation date |
| ESMA FIRDS (EU) | isin, lei, instrument name, cfi_code, status |
| TED (EU) | buyer-name, winner-name, total-value, procedure-type |
| ANAF (RO) | denumire, adresa, scpTVA (VAT payer flag), active status |
Apify fallback
When no direct API exists, use Apify CLI with a specific actor or apify/website-content-crawler:
apify call apify/website-content-crawler \
--input '{"startUrls":[{"url":"https://or.justice.cz/ias/ui/rejstrik-$firma?ico=25099345"}],"maxCrawlPages":1}' \
--user-agent apify-awesome-skills/apify-public-registriesApify-dependent registries:
| Country | Registry | Actor | Trigger |
|---|---|---|---|
| DE | Handelsregister | radeance/handelsregister-api | DE/fetch_all.py keyword <name> |
| UK | Companies House | dhrumil/company-house-scraper | UK/fetch_all.py search <name> |
| PL | eKRS Financials | minute_contest/poland-krs-financial-scraper | PL/fetch_all.py financials |
| CZ | Justice.cz filings | apify/website-content-crawler | Direct via apify CLI |
| RO | ListaFirme.ro | apify/website-content-crawler | RO/fetch_all.py listafirme |
| SE | Allabolag.se | apify/website-content-crawler | Manual (residential proxy needed) |
Note: DE, UK, and RO scripts use mcpc CLI internally (not apify CLI).
Dependencies
Python stdlib only (no pip)
CZ (ares, dph, cnb_banks, cnb_oam, justice), SK (orsr, finstat), PL (krs, biala_lista, gus), EU (gleif, esma, ted, eurostat), ESG (ets, climate_trace), RO (anaf)
Requires Apify + APIFY_TOKEN
DE (handelsregister), UK (companies_house), PL (financials via eKRS), CZ (justice.cz sbírka listin via scraping), RO (listafirme.ro)
Requires API key registration
- NL:
KVK_API_KEY— register at developers.kvk.nl (REGISTRATION/NL.md) - PL GUS:
GUS_API_KEY— email regon_bir@stat.gov.pl (test keyabcde12345abcde12345exists but has no real data) - SE: Bolagsverket — register at portal.api.bolagsverket.se (REGISTRATION/SE.md)
- HR: Sudski registar — register at sudreg-data.gov.hr, OAuth2 flow (REGISTRATION/HR.md)
Critical gotchas
- CZ ARES is the best single starting point for Czech companies — aggregates data from multiple source registers.
- EU GLEIF is the best cross-country starting point — maps LEI to registered-as numbers usable in country lookups.
- RO ANAF API is offline since March 2026 — lookup returns errors. Use listafirme.ro (Apify) as fallback.
- SK ORSR uses HTML scraping with windows-1250 encoding and regex parsing — fragile, may break if page layout changes.
- SK FinStat is also HTML scraping — may block automated access.
- PL Biała Lista has a hard rate limit: 100 queries/day (search method) or 5,000/day (check method).
- PL GUS silently returns fake data when
GUS_API_KEYis unset — test server returns plausible-looking records (ul. Test-Krucza,Kraków-Podgórze) for any valid NIP. Production key required: email regon_bir@stat.gov.pl. Always inspect first GUS record to confirm prod vs test. - DE + UK scripts use mcpc CLI (not apify CLI) — require authenticated
@apifysession. - UK Companies House has a free API at api.company-information.service.gov.uk, but the script uses Apify scraping instead.
- CZ Justice.cz bulk datasets are 13GB+ XML/CSV. The CKAN API returns a dataset list, not per-company data.
- CZ ČNB OAM is only relevant for emitents (listed companies, banks) — uses Oracle BI XML export.
- ESG data is country-level, not company-level — useful only as contextual benchmark.
- ESAP (centralized EU ESG/financial database with API) launches CSRD data January 2028.
- EBA Transparency CSVs are 100MB+ each — run
EU/fetch_all.py ebaseparately, not as part of normal batch. - TED has low value — most portfolio companies are private. Winner-name only in eForms notices (2024+).
- Batch mode (
fetch_all.pywithout arguments) readslookup_targets.jsonfrom the script's directory — these are per-country ID→name mappings, NOT copies ofdata/companies.json. For single-company lookups, pass the identifier directly.
Reference
- data/registries.json — machine-readable: 11 countries, 27 registry entries
- REGISTRATION/HR.md, REGISTRATION/NL.md, REGISTRATION/SE.md — per-country API access guides
- reference/european-company-data-institutions.md — full narrative catalog (413 lines, CZ + PL + EU institutions)
- reference/scripts/{CZ,DE,ESG,EU,NL,PL,RO,SK,UK}/fetch_all.py — per-country lookup scripts
{
"_metadata": {
"version": "1.0",
"last_updated": "2026-04-27",
"source": "Derived from local/*/fetch_all.py + european-company-data-institutions.md",
"upstream_issues": [
"DE/fetch_all.py, UK/fetch_all.py, RO/fetch_all.py: depend on mcpc CLI (subprocess calls to 'mcpc @apify tools-call call-actor'), which conflicts with our REST-based tech stack (apify call). Scripts work if user has mcpc installed, but SKILL.md documents apify call alternative for direct Apify REST calls. Migration candidate for Phase 2.",
"RO/fetch_all.py: ANAF API endpoint webservicesp.anaf.ro has been offline since March 2026 (returns 404). Noted in script comments (line 102). Fallback: listafirme via Apify scraping. Alternative APIs: openapi.ro, termene.ro (both require registration).",
"SK/fetch_all.py: ORSR registry uses regex HTML scraping on windows-1250 encoded pages. Fragile — will break on any layout change to orsr.sk. No REST API currently available.",
"UK/fetch_all.py: uses Apify scraping (dhrumil/company-house-scraper) instead of free official Companies House API (api.company-information.service.gov.uk). Migration to free API would eliminate Apify dependency + cost for UK lookups.",
"NL/fetch_all.py: no single-company lookup CLI command — only batch fetch for all configured companies. API URL documented in registries.json for direct agent use.",
"PL/fetch_all.py financials: the fetch_krs_financials_instructions() function only prints mcpc commands and saves them to a text file — does NOT actually run the Apify actor or retrieve data. Agent must use apify call directly with actor minute_contest/poland-krs-financial-scraper.",
"CZ/fetch_all.py justice: uses CKAN API which returns bulk dataset catalog (13GB+ XML/CSV), not per-company filings. Per-company financial statements from justice.cz require Apify scraping of or.justice.cz."
]
},
"countries": [
{
"code": "CZ",
"name": "Czech Republic",
"registries": [
{
"id": "ares",
"name": "ARES (Administrative Register of Economic Entities)",
"operator": "Ministerstvo financí ČR",
"url": "https://ares.gov.cz/",
"api_url": "https://ares.gov.cz/ekonomicke-subjekty-v-be/rest/ekonomicke-subjekty/{ico}",
"access": "free",
"identifier": {
"name": "IČO",
"format": "8-digit string",
"registry_ids_key": "CZ_ICO"
},
"data_types": [
"company_profile",
"address",
"nace_codes",
"dic",
"legal_form",
"founding_date",
"registration_status"
],
"has_script": true,
"script_command": "python3 reference/scripts/CZ/fetch_all.py lookup <IČO>",
"apify_fallback": false,
"gotchas": [
"0.3s sleep between requests in batch mode"
]
},
{
"id": "dph",
"name": "Registr DPH (VAT Payer Register)",
"operator": "Finanční správa ČR",
"url": "https://adisrws.mfcr.cz/",
"api_url": "https://adisrws.mfcr.cz/adistc/axis2/services/rozhraniCRPDPH.rozhraniCRPDPHSOAP",
"access": "free",
"identifier": {
"name": "DIČ",
"format": "CZ + 8-digit IČO (e.g. CZ25099345)",
"registry_ids_key": "CZ_DIC"
},
"data_types": [
"vat_status",
"unreliable_payer_flag",
"registered_bank_accounts"
],
"has_script": true,
"script_command": "python3 reference/scripts/CZ/fetch_all.py dph",
"apify_fallback": false,
"gotchas": [
"SOAP API (not REST)",
"0.2s sleep between requests"
]
},
{
"id": "cnb_banks",
"name": "ČNB Licensed Banks List",
"operator": "Česká národní banka",
"url": "https://apl.cnb.cz/apljerrsdad/JERRS.WEB07.INTRO_PAGE",
"api_url": "https://jerrs.cnb.cz/apljerrsdad/JERRS.OPENDATA.STAHUJ?p_seznam=1",
"access": "free",
"identifier": {
"name": "IČO",
"format": "8-digit string",
"registry_ids_key": "CZ_ICO"
},
"data_types": [
"bank_license",
"bank_name",
"address"
],
"has_script": true,
"script_command": "python3 reference/scripts/CZ/fetch_all.py cnb_banks",
"apify_fallback": false,
"gotchas": [
"CSV format, windows-1250 encoding possible"
]
},
{
"id": "cnb_oam",
"name": "ČNB Central Storage of Regulated Information (OAM)",
"operator": "Česká národní banka",
"url": "https://oam.cnb.cz/",
"api_url": "https://oam.cnb.cz/xmlpserver/OAM_CNB_CZ/R1_K22.xdo",
"access": "free",
"identifier": {
"name": "IČO",
"format": "8-digit string",
"registry_ids_key": "CZ_ICO"
},
"data_types": [
"regulated_reports",
"annual_reports",
"half_yearly_reports",
"ad_hoc_disclosures"
],
"has_script": true,
"script_command": "python3 reference/scripts/CZ/fetch_all.py cnb_oam",
"apify_fallback": false,
"gotchas": [
"Oracle BI XML export format",
"Only relevant for emitents (listed companies, banks)",
"0.5s sleep between requests"
]
},
{
"id": "justice_cz",
"name": "Justice.cz — Sbírka listin (Collection of Documents)",
"operator": "Ministerstvo spravedlnosti ČR",
"url": "https://or.justice.cz/",
"api_url": "https://dataor.justice.cz/api/3/action/package_list",
"access": "free",
"identifier": {
"name": "IČO",
"format": "8-digit string",
"registry_ids_key": "CZ_ICO"
},
"data_types": [
"financial_filings",
"ownership",
"articles_of_association"
],
"has_script": true,
"script_command": "python3 reference/scripts/CZ/fetch_all.py justice",
"apify_fallback": true,
"apify_actor": "apify/website-content-crawler",
"gotchas": [
"CKAN API returns bulk dataset list, not per-company data",
"Per-company filings require Apify scraping of or.justice.cz",
"SSL certificate sometimes fails on macOS",
"Bulk datasets are 13GB+ XML/CSV"
]
}
]
},
{
"code": "SK",
"name": "Slovakia",
"registries": [
{
"id": "orsr",
"name": "ORSR (Obchodný register SR)",
"operator": "Ministerstvo spravedlivosti SR",
"url": "https://www.orsr.sk/",
"api_url": null,
"access": "free",
"identifier": {
"name": "IČO",
"format": "8-digit string",
"registry_ids_key": "SK_ICO"
},
"data_types": [
"company_profile",
"address",
"legal_form",
"share_capital",
"business_purpose",
"registration_date"
],
"has_script": true,
"script_command": "python3 reference/scripts/SK/fetch_all.py lookup <IČO>",
"apify_fallback": false,
"gotchas": [
"HTML scraping (no REST API)",
"windows-1250 encoding",
"0.5s sleep between requests",
"Fragile HTML parsing with regex"
]
},
{
"id": "finstat",
"name": "FinStat.sk (Financial Data)",
"operator": "FinStat s.r.o.",
"url": "https://finstat.sk/",
"api_url": null,
"access": "free",
"identifier": {
"name": "IČO",
"format": "8-digit string",
"registry_ids_key": "SK_ICO"
},
"data_types": [
"revenue",
"profit",
"employees",
"total_assets"
],
"has_script": true,
"script_command": "python3 reference/scripts/SK/fetch_all.py finstat",
"apify_fallback": false,
"gotchas": [
"HTML scraping (regex-based extraction)",
"1.0s sleep between requests (be polite)",
"May block automated access"
]
}
]
},
{
"code": "PL",
"name": "Poland",
"registries": [
{
"id": "krs",
"name": "KRS (Krajowy Rejestr Sądowy)",
"operator": "Ministerstwo Sprawiedliwości",
"url": "https://prs.ms.gov.pl/krs",
"api_url": "https://api-krs.ms.gov.pl/api/krs/OdpisAktualny/{krs}?rejestr=P&format=json",
"access": "free",
"identifier": {
"name": "KRS",
"format": "10-digit, zero-padded (e.g. 0000536554)",
"registry_ids_key": "PL_KRS"
},
"data_types": [
"company_profile",
"nip",
"regon",
"share_capital",
"management_board",
"shareholders"
],
"has_script": true,
"script_command": "python3 reference/scripts/PL/fetch_all.py lookup <KRS>",
"apify_fallback": false,
"gotchas": [
"0.5s sleep between requests"
]
},
{
"id": "biala_lista",
"name": "Biała Lista VAT (White List of VAT Taxpayers)",
"operator": "Krajowa Administracja Skarbowa",
"url": "https://www.podatki.gov.pl/narzedzia/white-list/",
"api_url": "https://wl-api.mf.gov.pl/api/search/nip/{nip}?date={today}",
"access": "free",
"identifier": {
"name": "NIP",
"format": "10-digit",
"registry_ids_key": "PL_NIP"
},
"data_types": [
"vat_status",
"krs",
"regon",
"registered_bank_accounts"
],
"has_script": true,
"script_command": "python3 reference/scripts/PL/fetch_all.py lookup_nip <NIP>",
"apify_fallback": false,
"gotchas": [
"Rate limit: 100 queries/day",
"1.0s sleep between requests",
"Requires date parameter (today's date)"
]
},
{
"id": "gus_regon",
"name": "GUS/REGON (Główny Urząd Statystyczny)",
"operator": "Główny Urząd Statystyczny",
"url": "https://wyszukiwarkaregon.stat.gov.pl/",
"api_url": "https://wyszukiwarkaregon.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc",
"access": "api_key_required",
"env_var": "GUS_API_KEY",
"identifier": {
"name": "NIP",
"format": "10-digit",
"registry_ids_key": "PL_NIP"
},
"data_types": [
"regon",
"nip",
"name",
"address",
"pkd_codes"
],
"has_script": true,
"script_command": "python3 reference/scripts/PL/fetch_all.py gus",
"apify_fallback": false,
"gotchas": [
"SOAP API (not REST)",
"Test env key: abcde12345abcde12345 (but has no real data)",
"Production key: email regon_bir@stat.gov.pl",
"Session-based: login returns SID, pass in sid header"
]
},
{
"id": "ekrs_financials",
"name": "eKRS Financial Statements",
"operator": "Ministerstwo Sprawiedliwości",
"url": "https://ekrs.ms.gov.pl/",
"api_url": null,
"access": "apify_required",
"env_var": "APIFY_TOKEN",
"identifier": {
"name": "KRS",
"format": "10-digit, zero-padded",
"registry_ids_key": "PL_KRS"
},
"data_types": [
"financial_statements",
"assets",
"equity",
"revenue",
"profit"
],
"has_script": true,
"script_command": "python3 reference/scripts/PL/fetch_all.py financials",
"apify_fallback": true,
"apify_actor": "minute_contest/poland-krs-financial-scraper",
"gotchas": [
"Requires Apify actor (mcpc CLI or apify call)",
"Cost: ~$0.03/result",
"Script only prints instructions, does not run actor directly"
]
}
]
},
{
"code": "DE",
"name": "Germany",
"registries": [
{
"id": "handelsregister",
"name": "Handelsregister (Commercial Register)",
"operator": "Bundesministerium der Justiz",
"url": "https://www.handelsregister.de/",
"api_url": null,
"access": "apify_required",
"env_var": "APIFY_TOKEN",
"identifier": {
"name": "Company name (keyword)",
"format": "free text",
"registry_ids_key": null
},
"data_types": [
"company_profile",
"legal_form",
"share_capital",
"management",
"hrb_number",
"business_purpose"
],
"has_script": true,
"script_command": "python3 reference/scripts/DE/fetch_all.py keyword <name>",
"apify_fallback": true,
"apify_actor": "radeance/handelsregister-api",
"gotchas": [
"No free public API — entirely Apify-dependent",
"Uses mcpc CLI (not apify call)",
"Cost: $0.01/search",
"Actor: 99.5% success rate, rating 5.0",
"1.0s sleep between searches"
]
}
]
},
{
"code": "UK",
"name": "United Kingdom",
"registries": [
{
"id": "companies_house",
"name": "Companies House",
"operator": "Companies House (UK Government)",
"url": "https://find-and-update.company-information.service.gov.uk/",
"api_url": null,
"access": "apify_required",
"env_var": "APIFY_TOKEN",
"identifier": {
"name": "Company name",
"format": "free text",
"registry_ids_key": null
},
"data_types": [
"company_profile",
"crn",
"sic_codes",
"directors",
"accounts_timeline",
"incorporation_date"
],
"has_script": true,
"script_command": "python3 reference/scripts/UK/fetch_all.py search <name>",
"apify_fallback": true,
"apify_actor": "dhrumil/company-house-scraper",
"gotchas": [
"Script uses mcpc CLI (not apify call)",
"Companies House has a free API (api.company-information.service.gov.uk) but this script uses Apify scraping instead",
"Actor: 95.7% success rate, rating 5.0, pay-per-event",
"1.0s sleep between searches"
]
}
]
},
{
"code": "NL",
"name": "Netherlands",
"registries": [
{
"id": "kvk",
"name": "KvK (Kamer van Koophandel)",
"operator": "Kamer van Koophandel",
"url": "https://www.kvk.nl/",
"api_url": "https://api.kvk.nl/api/v1/basisprofielen/{kvkNummer}",
"access": "api_key_required",
"env_var": "KVK_API_KEY",
"registration_guide": "REGISTRATION/NL.md",
"identifier": {
"name": "KVK number",
"format": "8-digit",
"registry_ids_key": "NL_KVK"
},
"data_types": [
"company_profile",
"addresses",
"trade_names"
],
"has_script": true,
"script_command": "python3 reference/scripts/NL/fetch_all.py",
"apify_fallback": false,
"gotchas": [
"Requires API key registration at developers.kvk.nl",
"Key sent in 'apikey' header (not Authorization)",
"0.5s sleep between requests",
"No single-company lookup command — script fetches all configured companies"
]
}
]
},
{
"code": "RO",
"name": "Romania",
"registries": [
{
"id": "anaf",
"name": "ANAF (Agenția Națională de Administrare Fiscală)",
"operator": "ANAF",
"url": "https://www.anaf.ro/",
"api_url": "https://webservicesp.anaf.ro/AsynchWebApi/api/v8/interogare/getInformatii",
"access": "free",
"identifier": {
"name": "CUI",
"format": "numeric (e.g. 2835636)",
"registry_ids_key": "RO_CUI"
},
"data_types": [
"company_name",
"address",
"vat_status",
"active_status"
],
"has_script": true,
"script_command": "python3 reference/scripts/RO/fetch_all.py lookup <CUI>",
"apify_fallback": false,
"gotchas": [
"ANAF API has been OFFLINE since March 2026 (returns 404)",
"Alternative: openapi.ro or termene.ro (both require API key)",
"0.3s sleep between requests"
]
},
{
"id": "listafirme",
"name": "ListaFirme.ro (Company Profiles)",
"operator": "ListaFirme.ro",
"url": "https://www.listafirme.ro/",
"api_url": null,
"access": "apify_required",
"env_var": "APIFY_TOKEN",
"identifier": {
"name": "CUI",
"format": "numeric",
"registry_ids_key": "RO_CUI"
},
"data_types": [
"company_profile",
"caen_codes",
"financial_data"
],
"has_script": true,
"script_command": "python3 reference/scripts/RO/fetch_all.py listafirme",
"apify_fallback": true,
"apify_actor": "apify/website-content-crawler",
"gotchas": [
"Cloudflare-protected — requires residential proxy",
"Uses playwright:firefox crawler type",
"Async runs — check status with: python fetch_all.py status",
"Uses mcpc CLI (not apify call)"
]
}
]
},
{
"code": "HR",
"name": "Croatia",
"registries": [
{
"id": "sudski_registar",
"name": "Sudski registar (Court Register)",
"operator": "Ministarstvo pravosuđa i uprave",
"url": "https://sudreg-data.gov.hr/",
"api_url": "https://sudreg-data.gov.hr/api/javni/",
"access": "registration_required",
"registration_guide": "REGISTRATION/HR.md",
"identifier": {
"name": "OIB / MBS",
"format": "OIB: 11-digit, MBS: company-specific",
"registry_ids_key": "HR_OIB"
},
"data_types": [
"company_profile",
"address",
"roles",
"share_capital"
],
"has_script": false,
"apify_fallback": false,
"gotchas": [
"OAuth2 client_credentials flow required",
"Must register at sudreg-data.gov.hr for Client ID + Secret",
"REST/JSON + XML output",
"Test environment available at sudreg-data-test.gov.hr"
]
}
]
},
{
"code": "SE",
"name": "Sweden",
"registries": [
{
"id": "bolagsverket",
"name": "Bolagsverket (Swedish Companies Registration Office)",
"operator": "Bolagsverket",
"url": "https://bolagsverket.se/",
"api_url": "https://api.bolagsverket.se/foretagsinformation-vardefulladatamangder/v1/organisationer/{org_nr}",
"access": "registration_required",
"registration_guide": "REGISTRATION/SE.md",
"identifier": {
"name": "Organisationsnummer",
"format": "10-digit (e.g. 559124-6847)",
"registry_ids_key": "SE_ORG"
},
"data_types": [
"company_profile",
"address",
"legal_form"
],
"has_script": false,
"apify_fallback": true,
"apify_actor": "apify/website-content-crawler",
"gotchas": [
"Free datasets available since Feb 2025 (EU High-Value Datasets regulation)",
"Full API requires contract with Bolagsverket",
"Allabolag.se is Cloudflare-protected — use residential proxy",
"UBO API available from 2025"
]
}
]
},
{
"code": "EU",
"name": "EU-Level Sources",
"registries": [
{
"id": "gleif",
"name": "GLEIF (Global Legal Entity Identifier Foundation)",
"operator": "GLEIF",
"url": "https://search.gleif.org/",
"api_url": "https://api.gleif.org/api/v1/lei-records",
"access": "free",
"identifier": {
"name": "LEI or Company name",
"format": "LEI: 20-char alphanumeric",
"registry_ids_key": "LEI"
},
"data_types": [
"lei",
"company_profile",
"jurisdiction",
"status",
"ownership_chain",
"parent_lei"
],
"has_script": true,
"script_command": "python3 reference/scripts/EU/fetch_all.py lookup <name>",
"script_command_lei": "python3 reference/scripts/EU/fetch_all.py lookup_lei <LEI>",
"apify_fallback": false,
"gotchas": [
"Best starting point for cross-country lookups — returns registered-as numbers usable in country-specific registries",
"Ownership chain via direct-parent-relationship endpoint",
"0.3s sleep between requests"
]
},
{
"id": "esma_firds",
"name": "ESMA FIRDS (Financial Instruments Reference Data)",
"operator": "ESMA",
"url": "https://registers.esma.europa.eu/",
"api_url": "https://registers.esma.europa.eu/solr/esma_registers_firds/select",
"access": "free",
"identifier": {
"name": "Company name",
"format": "free text (quoted in Solr query)",
"registry_ids_key": null
},
"data_types": [
"isin",
"lei",
"instrument_name",
"cfi_code",
"status"
],
"has_script": true,
"script_command": "python3 reference/scripts/EU/fetch_all.py lookup <name>",
"apify_fallback": false,
"gotchas": [
"Solr-based search engine",
"Returns ISIN, LEI, instrument name, CFI code",
"0.3s sleep between requests"
]
},
{
"id": "ted",
"name": "TED (Tenders Electronic Daily)",
"operator": "Publications Office of the European Union",
"url": "https://ted.europa.eu/",
"api_url": "https://api.ted.europa.eu/v3/notices/search",
"access": "free",
"identifier": {
"name": "Company name (buyer)",
"format": "free text (wildcard query)",
"registry_ids_key": null
},
"data_types": [
"contract_awards",
"buyer_name",
"winner_name",
"total_value",
"procedure_type"
],
"has_script": true,
"script_command": "python3 reference/scripts/EU/fetch_all.py lookup <name>",
"apify_fallback": false,
"gotchas": [
"Low value for PPF — most PPF companies are private and don't do public procurement",
"winner-name only populated in eForms notices (~2024+)",
"Expert query syntax: buyer-name ~ \"*keyword*\" AND notice-type = can-standard",
"0.5s sleep between requests"
]
},
{
"id": "eurostat",
"name": "Eurostat (Macro Statistics)",
"operator": "European Commission",
"url": "https://ec.europa.eu/eurostat/",
"api_url": "https://ec.europa.eu/eurostat/api/dissemination/sdmx/2.1/data/",
"access": "free",
"identifier": {
"name": "Dataset + parameters",
"format": "SDMX query parameters",
"registry_ids_key": null
},
"data_types": [
"gdp",
"sector_statistics",
"trade_data"
],
"has_script": true,
"script_command": "python3 reference/scripts/EU/fetch_all.py eurostat",
"apify_fallback": false,
"gotchas": [
"Low value: aggregate macro data only, no company-level data",
"Only useful as contextual benchmark for PPF countries",
"SDMX 3.0 REST API"
]
},
{
"id": "eba_transparency",
"name": "EBA Transparency Exercise (Bank Data)",
"operator": "European Banking Authority",
"url": "https://www.eba.europa.eu/risk-analysis-and-data/eu-wide-transparency-exercise",
"api_url": "https://www.eba.europa.eu/assets/TE2025/Full_database/883401/",
"access": "free",
"identifier": {
"name": "LEI",
"format": "20-char alphanumeric (LEI_Code field)",
"registry_ids_key": "LEI"
},
"data_types": [
"capital_adequacy",
"credit_risk",
"market_risk",
"sovereign_exposure"
],
"has_script": true,
"script_command": "python3 reference/scripts/EU/fetch_all.py eba",
"apify_fallback": false,
"gotchas": [
"CSV files are 100MB+ each — run separately",
"Filters by LEI code — needs GLEIF data first",
"~120 EU banks covered",
"Files: tr_cre.csv, tr_mrk.csv, tr_sov.csv"
]
}
]
},
{
"code": "ESG",
"name": "ESG / Sustainability Sources",
"registries": [
{
"id": "eu_ets",
"name": "EU ETS (Emissions Trading System)",
"operator": "European Commission",
"url": "https://climate.ec.europa.eu/eu-action/eu-emissions-trading-system-eu-ets_en",
"api_url": null,
"access": "free",
"identifier": {
"name": "Country name/ISO code",
"format": "free text or ISO code",
"registry_ids_key": null
},
"data_types": [
"verified_co2_emissions",
"installation_name",
"sector"
],
"has_script": true,
"script_command": "python3 reference/scripts/ESG/fetch_all.py lookup <country>",
"apify_fallback": false,
"gotchas": [
"GitHub CSV source (76K rows)",
"Filtered for PPF countries (BG, HU, PL, RO, SK) — CZ missing from dataset",
"Contextual benchmark — PPF firms unlikely to appear (not heavy industry)"
]
},
{
"id": "climate_trace",
"name": "Climate TRACE (Country Emissions)",
"operator": "Climate TRACE",
"url": "https://climatetrace.org/",
"api_url": "https://api.climatetrace.org/v6/country/emissions",
"access": "free",
"identifier": {
"name": "Country ISO code",
"format": "3-letter ISO (e.g. CZE, POL)",
"registry_ids_key": null
},
"data_types": [
"co2e_100yr",
"co2",
"ch4",
"global_rank"
],
"has_script": true,
"script_command": "python3 reference/scripts/ESG/fetch_all.py lookup <country>",
"apify_fallback": false,
"gotchas": [
"Country-level only, no company-level data",
"REST API with JSON response",
"0.3s sleep between requests",
"Maps common country names to ISO codes (e.g. 'czech republic' -> 'CZE')"
]
},
{
"id": "eba_pillar3_esg",
"name": "EBA Pillar 3 ESG Signposting",
"operator": "European Banking Authority",
"url": "https://www.eba.europa.eu/",
"api_url": null,
"access": "free",
"identifier": {
"name": "Bank name",
"format": "manual lookup in XLSX",
"registry_ids_key": null
},
"data_types": [
"esg_disclosure_links"
],
"has_script": true,
"script_command": "python3 reference/scripts/ESG/fetch_all.py eba_esg",
"apify_fallback": false,
"gotchas": [
"Downloads XLSX file (62KB) — not JSON",
"Requires Referer header for download",
"Contains links to ESG disclosures for ~120 EU banks"
]
},
{
"id": "esg_ratings",
"name": "ESG Rating URLs",
"operator": "Various (S&P Global, Sustainalytics, MSCI, LSEG)",
"url": null,
"api_url": null,
"access": "free",
"identifier": {
"name": "Listed company name",
"format": "manual lookup",
"registry_ids_key": null
},
"data_types": [
"esg_score_urls"
],
"has_script": true,
"script_command": "python3 reference/scripts/ESG/fetch_all.py ratings",
"apify_fallback": false,
"gotchas": [
"LOW VALUE: only prints URLs for manual lookup, no machine-readable data",
"Only covers listed PPF companies (InPost, O2 CZ)",
"PPF Group is private — not covered by major ESG raters",
"ESAP (centralized EU ESG database with API) launches CSRD data January 2028"
]
}
]
}
]
}
Public Institutions Providing Official Company Data in Europe
Compiled: 2026-03-19
---
1. CZECH REPUBLIC (CR)
1.1 Business & Company Registries
Verejny rejstrik a Sbirka listin (Public Register and Collection of Documents)
- Operator: Ministerstvo spravedlnosti CR (Ministry of Justice)
- URL: https://or.justice.cz/
- Data provided: Company registration data, articles of association, ownership structures, statutory bodies, financial statements (annual reports, balance sheets, profit/loss statements) filed in the Sbirka listin (Collection of Documents)
- Access: Free, fully public, no registration required
- API: No official REST API; data accessible via ARES (see below)
ARES - Administrativni registr ekonomickych subjektu (Administrative Register of Economic Entities)
- Operator: Ministerstvo financi CR (Ministry of Finance)
- URL: https://ares.gov.cz/
- Data provided: Aggregated data from multiple source registers (Commercial Register, Trade Register, CSU Business Register, Tax Register, etc.). Company identification, addresses, legal forms, NACE codes, registration details
- Access: Free, fully public
- API: Yes - REST API at https://ares.gov.cz/ekonomicke-subjekty-v-be/rest/ with Swagger documentation at https://ares.gov.cz/swagger-ui/. Supports search by ICO (ID number) and company name. Open data published at https://data.mf.gov.cz/topics/ares
- Notes: The single most important aggregation point for Czech company data
Zivnostensky rejstrik (Trade Register)
- Operator: Ministerstvo prumyslu a obchodu (Ministry of Industry and Trade)
- URL: https://www.rzp.cz/
- Data provided: Trade license information, scope of business activities, business premises, validity periods
- Access: Free, public
- API: Data accessible through ARES
1.2 Financial & Securities Regulators
Ceska narodni banka - CNB (Czech National Bank)
- URL: https://www.cnb.cz/en/
- Multiple data services:
a) Lists and Registers of Regulated Entities (JERRS)
- URL: https://apl.cnb.cz/apljerrsdad/JERRS.WEB07.INTRO_PAGE?p_lang=en
- Data provided: All licensed/registered financial market participants - banks, insurance companies, pension funds, investment firms, payment institutions, etc.
- Access: Free, public web interface
- API: Yes - WS JERRS web service available upon application (electronically signed request to jerrsws@cnb.cz)
b) Centralni uloziste regulovanych informaci (Central Storage of Regulated Information)
- URL: https://www.cnb.cz/en/supervision-financial-market/information-published-issuers/
- Data provided: Regulated information from issuers of listed securities - annual reports, half-yearly reports, inside information, notifications of major holdings, manager's transactions. Czech equivalent of SEC EDGAR
- Access: Free, public
- API: Not publicly documented
c) Financial Market Supervision Reports
- URL: https://www.cnb.cz/en/supervision-financial-market/aggregate-information-financial-sector/
- Data provided: Aggregate statistics on banking sector, insurance, capital markets, pension funds
- Access: Free, public
1.3 Beneficial Ownership
Evidence skutecnych majitelu (Register of Beneficial Owners)
- Operator: Ministerstvo spravedlnosti CR (Ministry of Justice)
- URL: https://issm.justice.cz/
- Data provided: Ultimate beneficial owners (UBO) of companies and trusts - name, date of birth, nationality, nature and extent of beneficial interest
- Access: Restricted since December 17, 2025 - public online access removed. Now available only to: registering entities, public authorities, AML-obliged persons (banks, lawyers), and persons demonstrating legitimate interest
- API: Not publicly available
1.4 Insolvency
Insolvencni rejstrik - ISIR (Insolvency Register)
- Operator: Ministerstvo spravedlnosti CR (Ministry of Justice)
- URL: https://isir.justice.cz/
- Data provided: Insolvency proceedings, bankruptcy filings, restructuring proceedings, creditor claims, court decisions
- Access: Free, fully public. Search by ICO (company ID) is most reliable
- API: ISIR provides a web service interface for automated queries
1.5 Tax & VAT
Registr DPH - Register platcu DPH (VAT Payer Register)
- Operator: Financni sprava CR (Financial Administration)
- URL: https://financnisprava.gov.cz/cs/dane/dane-elektronicky/danovy-portal/registr-dph (via Moje dane portal at www.mojedane.cz)
- Data provided: VAT registration status, reliable/unreliable payer status ("spolehlivy platce"), registered bank accounts of VAT payers
- Access: Free, public
- API: Yes - web service (RWS) for verifying VAT payer reliability and registered bank accounts
1.6 Statistical Office
Cesky statisticky urad - CSU (Czech Statistical Office)
- URL: https://csu.gov.cz/
- Business Register: https://csu.gov.cz/business_register
- Data provided: Business register (RES) with data on all legal and natural persons, trusts, public authorities. Updated twice monthly. Also publishes structural business statistics, industry data
- Access: Free; individual lookups on web, full database downloadable as CSV via open data
- API: Open data catalog at https://csu.gov.cz/open-data; also published to National Catalog of Open Data (NKOD) at https://data.gov.cz/
- Notes: R package
czsoavailable for programmatic access
1.7 Public Procurement
Vestnik verejnych zakazek - VVZ (Public Procurement Bulletin)
- Operator: Ministerstvo pro mistni rozvoj (Ministry for Regional Development)
- URL: https://vvz.nipez.cz/
- Data provided: All public procurement notices, tender results, contract awards
- Access: Free, public
Narodni elektronicky nastroj - NEN (National Electronic Tool)
- URL: https://nen.nipez.cz/en/
- Data provided: Full electronic procurement management - tender documentation, bids, contract administration
- Access: Free to search; participation requires registration
1.8 Cybersecurity
NUKIB - Narodni urad pro kybernetickou a informacni bezpecnost (National Cyber and Information Security Agency)
- URL: https://nukib.gov.cz/
- Data provided: Registry of regulated entities under NIS2 (Act No. 264/2025 Sb.), critical infrastructure operators, cybersecurity incident reports. Covers 60 services across 18 sectors
- Access: NUKIB Portal for registration and compliance; not a public company lookup database
- Notes: New Cybersecurity Act effective November 1, 2025, transposing EU NIS2
1.9 Open Data Portal
Narodni katalog otevrenych dat - NKOD (National Open Data Catalog)
- Operator: Ministerstvo vnitra (Ministry of Interior)
- URL: https://data.gov.cz/english/
- Data provided: Aggregated open datasets from all Czech public institutions including company data, procurement, budgets
- Access: Free, open data
---
2. POLAND (PL)
2.1 Business & Company Registries
Krajowy Rejestr Sadowy - KRS (National Court Register)
- Operator: Ministerstwo Sprawiedliwosci (Ministry of Justice)
- URL: https://prs.ms.gov.pl/krs (Portal Rejestrow Sadowych)
- Also via: https://www.biznes.gov.pl/en/wyszukiwarka-firm
- Data provided: Registration data for companies (sp. z o.o., S.A., sp.k., sp.j., etc.), cooperatives, state-owned enterprises, foreign company branches. Includes: company name, registered office, share capital, management board, supervisory board, shareholders, NACE codes, registration history
- Access: Free, fully public online since July 1, 2021
- API: Not an official public REST API, but data available via commercial providers (e.g., Transparent Data)
Repozytorium Dokumentow Finansowych - RDF (Financial Documents Repository)
- Operator: Ministerstwo Sprawiedliwosci (Ministry of Justice)
- URL: https://ekrs.ms.gov.pl/rdf/pd/search_df (search) / https://rdf-przegladarka.ms.gov.pl/ (browser)
- Data provided: Financial statements (annual reports, balance sheets, P&L, cash flow statements) of all KRS-registered companies in structured XML format, auditor opinions, resolutions approving financial statements
- Access: Free, no login required for browsing/downloading. Search by KRS number
- API: No official public API; protected against automated scraping (CAPTCHA)
- Notes: This is the Polish equivalent of the Czech "Sbirka listin" for financial data
Centralna Ewidencja i Informacja o Dzialalnosci Gospodarczej - CEIDG (Central Register of Business Activity)
- Operator: Ministerstwo Rozwoju i Technologii (Ministry of Development and Technology)
- URL: https://www.biznes.gov.pl/en/wyszukiwarka-firm
- Data provided: All sole proprietorships (~2.5 million entities) - name, NIP, REGON, address, scope of business, status, suspension/resumption dates
- Access: Free, fully public
- API: Yes - CEIDG provides a public API for company verification
2.2 Beneficial Ownership
Centralny Rejestr Beneficjentow Rzeczywistych - CRBR (Central Register of Beneficial Owners)
- Operator: Ministerstwo Finansow (Ministry of Finance)
- URL: https://crbr.podatki.gov.pl/
- Data provided: Beneficial owners of companies, foundations, associations, trusts - name, citizenship, country of residence, nature and extent of ownership/control
- Access: Free, public (subject to EU CJEU ruling limitations - may require legitimate interest demonstration in future)
- API: Yes - available via commercial providers like Transparent Data (https://transparentdata.pl/en/api-company-information-poland/ubo-poland)
2.3 Financial & Securities Regulators
Komisja Nadzoru Finansowego - KNF (Polish Financial Supervision Authority)
- URL: https://www.knf.gov.pl/en/
- Entities search: https://www.knf.gov.pl/en/ENTITIES/entities_search
- Data provided: Lists of regulated entities - banks, insurance companies, investment firms, payment institutions, pension funds. Warnings about unauthorized entities. Financial data on supervised sectors
- Access: Free, public
- API: Not publicly documented
Narodowy Bank Polski - NBP (National Bank of Poland)
- URL: https://nbp.pl/en/
- Data provided: Banking sector financial data, monetary statistics, balance of payments data, exchange rates
- Access: Free, public
- API: Yes - NBP provides APIs for exchange rates and statistical data
2.4 Tax & VAT
Biala Lista Podatnikow VAT (White List of VAT Taxpayers)
- Operator: Krajowa Administracja Skarbowa - KAS (National Revenue Administration)
- URL: https://www.podatki.gov.pl/narzedzia/white-list/
- API documentation: https://www.gov.pl/web/kas/api-wykazu-podatnikow-vat
- Data provided: VAT registration/deregistration status, registered bank accounts, NIP, REGON
- Access: Free, public
- API: Yes - official REST API with two methods:
- "search" method: 100 queries/day, up to 30 entities per query (by NIP, REGON, or bank account + date)
- "check" method: 5,000 queries/day for simplified verification
- Also available as downloadable flat file (full NIP-account pair list)
- Notes: Updated once daily on business days
2.5 Insolvency & Debt
Krajowy Rejestr Zadluzonych - KRZ (National Register of Debtors)
- Operator: Ministerstwo Sprawiedliwosci (Ministry of Justice)
- URL: https://krz.ms.gov.pl/
- Data provided: Entities with pending enforcement, restructuring and bankruptcy proceedings; insolvent entities or those threatened with insolvency
- Access: Free, public (launched December 1, 2021)
- API: Not publicly documented
2.6 Statistical Office
Glowny Urzad Statystyczny - GUS (Central Statistical Office)
- URL: https://stat.gov.pl/en/
- REGON database: https://wyszukiwarkaregon.stat.gov.pl/appBIR/index.aspx
- Data provided: REGON register (all economic entities), structural business statistics, industry data, economic indicators. REGON number assignment for all entities
- Access: Free for basic lookups; bulk data may require application
- API: Yes - BIR (Baza Internetowa REGON) web service for REGON data queries
2.7 Public Procurement
Urzad Zamowien Publicznych - UZP (Public Procurement Office)
- URL: https://www.gov.pl/web/uzp-en
- Biuletyn Zamowien Publicznych (BZP): https://bzp.uzp.gov.pl/ (search: https://searchbzp.uzp.gov.pl/)
- Platform e-Zamowienia: https://ezamowienia.gov.pl/
- Data provided: All public procurement notices (below EU thresholds in BZP, above thresholds in TED), contract awards, annual procurement reports
- Access: Free, public
- API: e-Zamowienia platform provides some integration capabilities
2.8 Cybersecurity
CSIRT GOV / CSIRT NASK / CSIRT MON
- URLs:
- CSIRT GOV: https://csirt.gov.pl/
- CSIRT NASK: https://www.nask.pl/
- Data provided: Cybersecurity incident reporting and response. Not a public company data registry per se, but relevant for cybersecurity compliance status of key service operators and digital service providers
- Access: Incident reporting portals; not a public company lookup
2.9 ESG / Sustainability
Poland implements CSRD (Corporate Sustainability Reporting Directive) from January 1, 2025. ESG reports are filed as part of annual reports through the KRS/RDF system. The Warsaw Stock Exchange (GPW) also publishes ESG reporting guidelines for listed companies at https://www.gpw.pl/pub/GPW/ESG/ESG_Reporting_Guidelines.pdf.
---
3. EU-LEVEL INSTITUTIONS
3.1 Business Registers
Business Registers Interconnection System (BRIS)
- Operator: European Commission / European e-Justice Portal
- URL: https://e-justice.europa.eu/topics/registers-business-insolvency-land/business-registers-search-company-eu_en
- Search portal: https://webgate.ec.europa.eu/e-justice/searchBris.do
- Data provided: Basic company data (name, legal form, registered office, status, directors) from national business registers of all EU/EEA countries. Covers public and private limited liability companies and their branches
- Access: Free, public
- API: Not a public REST API; web interface only
- Notes: Based on Directive 2012/17/EU. Does not include financial statements
European Business Register (EBR)
- Operator: European Business Registry Association (EBRA)
- URL: https://ebra.be/ / https://www.eubusinessregister.org/
- Data provided: Company information from national business registries of member states
- Access: Varies by country; some free, some paid
- Notes: Platform closing April 1, 2026 - being replaced by BRIS functionality
3.2 Beneficial Ownership
Beneficial Ownership Registers Interconnection System (BORIS)
- Operator: European Commission / European e-Justice Portal
- URL: https://e-justice.europa.eu/topics/registers-business-insolvency-land/beneficial-ownership-registers-interconnection-system-boris_en
- Access portal: https://webgate.ec.europa.eu/e-justice/38590/EN/beneficial_ownership_registers_interconnection_system_boris
- Data provided: Beneficial ownership data from connected national UBO registers across EU/EEA
- Access: Varies - following CJEU ruling and 6th AMLD, access may require demonstration of legitimate interest. Law enforcement/FIUs have full access
- Status: Only 17 of 30 EU/EEA countries fully connected as of 2025. Ongoing technical integration challenges
3.3 Securities & Financial Markets
European Securities and Markets Authority (ESMA) - Databases and Registers
- URL: https://www.esma.europa.eu/publications-and-data/databases-and-registers
- Key databases:
a) Financial Instruments Reference Data System (FIRDS)
- Data provided: Reference data on all financial instruments traded in EU - name, ISIN, LEI of issuer, trading venue, instrument type
- Access: Free, public. Human interface and machine-to-machine download
- API: Yes - bulk file downloads and search interface
b) European Rating Platform (ERP)
- Data provided: Credit ratings and rating outlooks from all EU-registered credit rating agencies
- Access: Free, public (launched to provide free credit ratings info to the public)
c) Short Selling Register
- Data provided: Net short position notifications for sovereign issuers, list of exempted shares
- Access: Free, public
d) EMIR Trade Repositories
- Data provided: Lists of registered/recognized trade repositories; derivative transaction data (not directly public, but aggregate statistics published)
- Access: List of TRs is public; transaction data available to regulators only
e) Registers of Investment Firms, Fund Managers, etc.
- Data provided: AIFMD registers, UCITS management companies, CCP registers, CSDs, benchmark administrators
- Access: Free, public
European Banking Authority (EBA)
- URL: https://www.eba.europa.eu/
- Key data resources:
a) EU-wide Transparency Exercise
- URL: https://www.eba.europa.eu/risk-analysis-and-data/eu-wide-transparency-exercise
- Data provided: Bank-by-bank data for ~119 banks across 25 EU/EEA countries. Capital adequacy, risk exposures, asset quality, P&L data. Published annually
- Access: Free, downloadable datasets (Excel/CSV)
b) EU-wide Stress Test Results
- Data provided: Stress test results for major EU banks under adverse scenarios
- Access: Free, downloadable
European Insurance and Occupational Pensions Authority (EIOPA)
- URL: https://www.eiopa.europa.eu/
- Data provided: Insurance sector statistics, pension fund data, Solvency II reporting data, risk dashboards
- Access: Aggregate data free; entity-level data varies
ECB Banking Supervision (SSM - Single Supervisory Mechanism)
- URL: https://www.bankingsupervision.europa.eu/
- Data provided:
- List of all supervised entities (significant and less significant institutions) in eurozone
- Supervisory banking statistics
- SREP aggregate results
- Access: Free, public
- API: ECB Data Portal at https://data.ecb.europa.eu/ provides API access to statistical data
3.4 European Single Access Point (ESAP)
ESAP
- Operator: ESMA (on behalf of the European Commission)
- URL: https://www.esma.europa.eu/esmas-activities/data/european-single-access-point-esap
- Data provided: Will provide single access to: financial information, sustainability/ESG reports, regulatory disclosures from EU companies
- Access: Will be free, multilingual, machine-readable
- Timeline:
- July 2026: Start collecting information from Collection Bodies
- July 2027: Information accessible to the public
- January 2028: Phase 2 information collection
- January 2029: Phase 2bis
- Notes: This will become the most important pan-European company data portal for both financial and ESG data. Designed to replace fragmented national systems
3.5 Legal Entity Identification
Global Legal Entity Identifier Foundation (GLEIF)
- URL: https://www.gleif.org/
- LEI Search: https://search.gleif.org/
- Data provided: Legal Entity Identifiers (LEI) - 20-digit codes for unique identification of legal entities in financial transactions. Includes: entity name, registered address, headquarters address, legal form, registration authority, ownership relationships (direct & ultimate parent)
- Access: Free, fully public
- API: Yes - comprehensive REST API at https://www.gleif.org/en/lei-data/gleif-api. Supports filters, full-text search, fuzzy matching. Production since 2020. Also provides bulk download files (CSV, XML)
- Notes: Maps to OpenCorporates IDs (bi-weekly updated CSV). Over 2.7 million LEIs globally
3.6 Public Procurement
Tenders Electronic Daily (TED)
- Operator: Publications Office of the European Union
- URL: https://ted.europa.eu/en/
- Developer docs: https://docs.ted.europa.eu/api/latest/index.html
- Data provided: ~800,000 public procurement notices per year from all EU/EEA countries, worth over EUR 815 billion. Contract notices, contract awards, prior information notices
- Access: Free, public
- API: Yes - TED API for retrieving, submitting, validating, and visualizing notices. Bulk XML downloads available (daily and monthly packages). CSV subset also available
- Formats: XML (full), CSV (subset), PDF/HTML rendering
3.7 Statistics
Eurostat
- URL: https://ec.europa.eu/eurostat/
- Database: https://ec.europa.eu/eurostat/data/database
- Structural Business Statistics: https://ec.europa.eu/eurostat/web/structural-business-statistics/database
- Data provided: Aggregate business statistics by country, sector, size class. Covers: number of enterprises, turnover, value added, employment, investment. Also: trade statistics, R&D expenditure, ICT usage
- Access: Free for aggregate/published data. Microdata (firm-level) available only to recognized research entities upon application (8-10 week process)
- API: Yes - SDMX 3.0 REST API. Supports JSON-stat, SDMX-CSV, SDMX-ML, TSV formats. Full documentation at https://ec.europa.eu/eurostat/web/user-guides/data-browser/api-data-access/
3.8 Open Data & Aggregators
EU Open Data Portal
- URL: https://data.europa.eu/
- Data provided: Aggregates open datasets from EU institutions and member states, including company-related datasets
- Access: Free
OpenCorporates
- URL: https://opencorporates.com/
- Data provided: Largest open database of companies globally - aggregates data from official registries worldwide. Basic company data: name, jurisdiction, status, registration date, officers
- Access: Basic search free; bulk access and API are paid (commercial license)
- API: Yes - REST API (paid). Linked to GLEIF LEI data
OpenSanctions
- URL: https://www.opensanctions.org/
- Data provided: Sanctions lists, PEP databases, company data from various registries (including CZ and PL business registers)
- Access: Free for non-commercial use
---
SUMMARY TABLE
| Institution | Country | Data Type | Free? | API? |
|---|---|---|---|---|
| Justice.cz (Verejny rejstrik) | CZ | Company registration, financial statements | Yes | Via ARES |
| ARES | CZ | Aggregated company data | Yes | Yes (REST) |
| CNB - JERRS | CZ | Regulated financial entities | Yes | Yes (WS) |
| CNB - Central Storage | CZ | Issuer reports (annual, half-yearly) | Yes | No |
| ISIR | CZ | Insolvency proceedings | Yes | Yes (WS) |
| Evidence skutecnych majitelu | CZ | Beneficial ownership | Restricted | No |
| Registr DPH | CZ | VAT payer status | Yes | Yes (RWS) |
| CSU Business Register | CZ | Business statistics | Yes | Open data |
| VVZ/NEN | CZ | Public procurement | Yes | Partial |
| KRS | PL | Company registration | Yes | No (official) |
| RDF | PL | Financial statements | Yes | No |
| CEIDG | PL | Sole proprietorships | Yes | Yes |
| CRBR | PL | Beneficial ownership | Yes* | Via 3rd party |
| KNF | PL | Regulated financial entities | Yes | No |
| Biala Lista VAT | PL | VAT taxpayer data | Yes | Yes (REST) |
| KRZ | PL | Insolvency/debt | Yes | No |
| GUS/REGON | PL | Business statistics | Yes | Yes (BIR WS) |
| BZP/e-Zamowienia | PL | Public procurement | Yes | Partial |
| BRIS | EU | Basic company data cross-border | Yes | No |
| BORIS | EU | Beneficial ownership cross-border | Restricted | No |
| ESMA (FIRDS, ERP, etc.) | EU | Securities, ratings, instruments | Yes | Yes |
| EBA Transparency | EU | Bank-by-bank financial data | Yes | Downloads |
| ECB SSM | EU | Supervised bank lists | Yes | Yes |
| ESAP | EU | Financial + ESG data (from 2027) | Yes | TBD |
| GLEIF | Global | Legal Entity Identifiers | Yes | Yes (REST) |
| TED | EU | Public procurement | Yes | Yes (REST) |
| Eurostat | EU | Business statistics (aggregate) | Yes | Yes (SDMX) |
\ May be subject to legitimate interest requirements following EU CJEU ruling*
#!/usr/bin/env python3
"""Fetch data from all Czech sources for portfolio + competitors.
Usage:
python fetch_all.py # fetch all sources for all companies
python fetch_all.py ares # fetch only ARES
python fetch_all.py ares dph # fetch ARES + DPH
python fetch_all.py lookup 25099345 # lookup single company by IČO (all sources)
Sources:
ares — ARES REST API (MF ČR). Základní profil firmy: název, adresa, IČO, DIČ,
NACE kódy, právní forma, datum vzniku, statusy registrací.
Klíčový identifikační zdroj pro všechny CZ firmy.
dph — Registr DPH (SOAP). Status plátce DPH, nespolehlivý plátce ANO/NE,
zveřejněné bankovní účty. Užitečné pro due diligence a ověření protistrany.
cnb_banks — ČNB seznam bank (CSV open data). Kompletní seznam licencovaných bank v ČR
s IČO a adresou. Matchuje portfolio banky (Air Bank, PPF banka).
cnb_oam — ČNB Centrální úložiště regulovaných informací (Oracle BI XML export).
Regulované zprávy emitentů — výroční zprávy, pololetní zprávy, ad hoc.
Relevantní pro O2 CZ (veřejně obchodovaná) a banky.
justice — Justice.cz Open Data (CKAN API). Bulk datasety sbírky listin — účetní
závěrky a výroční zprávy všech firem. 13GB+ XML/CSV.
Pozn: SSL certifikát občas selhává na macOS.
"""
import json
import os
import sys
import time
import urllib.request
import urllib.parse
import xml.etree.ElementTree as ET
from pathlib import Path
BASE_DIR = Path(__file__).parent
OUTPUT_DIR = BASE_DIR / "output"
OUTPUT_DIR.mkdir(exist_ok=True)
with open(BASE_DIR / "lookup_targets.json") as f:
COMPANIES = json.load(f)
def all_icos():
"""Return all IČOs (portfolio + competitors)."""
icos = dict(COMPANIES["portfolio"])
for sector_companies in COMPANIES["competitors"].values():
icos.update(sector_companies)
return icos
# --- 1. ARES REST API ---
def fetch_ares(ico: str) -> dict:
url = f"https://ares.gov.cz/ekonomicke-subjekty-v-be/rest/ekonomicke-subjekty/{ico}"
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
def fetch_all_ares():
print("=== ARES ===")
results = {}
icos = all_icos()
for ico, info in icos.items():
try:
data = fetch_ares(ico)
results[ico] = {
"name": data.get("obchodniJmeno"),
"dic": data.get("dic"),
"address": data.get("sidlo", {}).get("textovaAdresa"),
"legal_form": data.get("pravniForma"),
"nace_codes": data.get("czNace", []),
"founded": data.get("datumVzniku"),
"registrations": data.get("seznamRegistraci", {}),
}
print(f" OK {ico} {data.get('obchodniJmeno')}")
time.sleep(0.3)
except Exception as e:
results[ico] = {"error": str(e), "name": info.get("name", "")}
print(f" ERR {ico} {e}")
out = OUTPUT_DIR / "ares.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} records to {out}")
return results
# --- 2. Registr DPH (SOAP) ---
def fetch_dph(dic: str) -> dict:
soap = f"""<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:roz="http://adis.mfcr.cz/rozhraniCRPDPH/">
<soapenv:Body>
<roz:StatusNespolehlivyPlatceRequest>
<roz:dic>{dic}</roz:dic>
</roz:StatusNespolehlivyPlatceRequest>
</soapenv:Body>
</soapenv:Envelope>"""
req = urllib.request.Request(
"https://adisrws.mfcr.cz/adistc/axis2/services/rozhraniCRPDPH.rozhraniCRPDPHSOAP",
data=soap.encode(),
headers={"Content-Type": "text/xml"},
)
with urllib.request.urlopen(req, timeout=15) as resp:
return resp.read().decode()
def fetch_all_dph():
print("=== Registr DPH ===")
results = {}
icos = all_icos()
for ico, info in icos.items():
dic = f"CZ{ico}"
try:
xml_str = fetch_dph(dic)
import re
unreliable = re.findall(r'nespolehlivyPlatce="([^"]+)"', xml_str)
accounts = re.findall(r'<standardniUcet cislo="([^"]+)" kodBanky="([^"]+)"/>', xml_str)
results[ico] = {
"dic": dic,
"unreliable": unreliable[0] if unreliable else None,
"bank_accounts": [{"number": a[0], "bank_code": a[1]} for a in accounts],
}
status = unreliable[0] if unreliable else "N/A"
print(f" OK {ico} unreliable={status} accounts={len(accounts)}")
time.sleep(0.2)
except Exception as e:
results[ico] = {"error": str(e)}
print(f" ERR {ico} {e}")
out = OUTPUT_DIR / "dph.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} records to {out}")
return results
# --- 3. ČNB Open Data (bank list CSV) ---
def fetch_cnb_banks():
print("=== ČNB Banks ===")
url = "https://jerrs.cnb.cz/apljerrsdad/JERRS.OPENDATA.STAHUJ?p_seznam=1"
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=30) as resp:
data = resp.read().decode("utf-8")
import csv, io
reader = csv.DictReader(io.StringIO(data))
banks = {}
our_icos = set(all_icos().keys())
for row in reader:
ico = row.get("ičo", row.get("ico", ""))
banks[ico] = dict(row)
if ico in our_icos:
print(f" MATCH {ico} {row.get('název', row.get('nazev', ''))}")
out = OUTPUT_DIR / "cnb_banks.json"
with open(out, "w") as f:
json.dump(banks, f, ensure_ascii=False, indent=2)
print(f" Saved {len(banks)} banks to {out}")
return banks
# --- 4. ČNB Centrální úložiště (OAM XML) ---
def fetch_cnb_oam(ico: str) -> str:
params = urllib.parse.urlencode({
"_xpf": "",
"_xpt": "1",
"_xdo": "/OAM_CNB_CZ/R1_K22.xdo",
"_paramspar_emit_ico": ico,
"_paramspar_emit": "EMIT*",
"_paramspar_count": "200",
"_xt": "lay_R1_K22",
"_xf": "xml",
"_xmode": "4",
"par_lang": "cs",
})
url = f"https://oam.cnb.cz/xmlpserver/OAM_CNB_CZ/R1_K22.xdo?{params}"
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=30) as resp:
return resp.read().decode("utf-8")
def fetch_all_cnb_oam():
print("=== ČNB OAM (Centrální úložiště) ===")
results = {}
# Only fetch for companies likely to be emitents (banks, O2, etc.)
emitent_icos = {
"60193336": "O2 Czech Republic a.s.",
"29045371": "Air Bank a.s.",
"47116129": "PPF banka a.s.",
"45244782": "Česká spořitelna, a.s.",
"00001350": "ČSOB a.s.",
"45317054": "Komerční banka, a.s.",
"25672720": "MONETA Money Bank, a.s.",
}
for ico, name in emitent_icos.items():
try:
xml_str = fetch_cnb_oam(ico)
import re
docs = re.findall(r"<DOCUMENT_ID>(\d+)</DOCUMENT_ID>", xml_str)
doc_names = re.findall(r"<DOCUMENT_NAME>(.*?)</DOCUMENT_NAME>", xml_str)
results[ico] = {
"name": name,
"document_count": len(docs),
"documents": [{"id": d, "name": n} for d, n in zip(docs[:20], doc_names[:20])],
}
print(f" OK {ico} {name}: {len(docs)} documents")
time.sleep(0.5)
except Exception as e:
results[ico] = {"error": str(e), "name": name}
print(f" ERR {ico} {name}: {e}")
out = OUTPUT_DIR / "cnb_oam.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} records to {out}")
return results
# --- 5. Justice.cz Open Data (CKAN dataset list) ---
def fetch_justice_datasets():
print("=== Justice.cz Open Data ===")
url = "https://dataor.justice.cz/api/3/action/package_list"
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=30) as resp:
data = json.loads(resp.read())
datasets = data.get("result", [])
# Filter for a.s. datasets (most portfolio companies are a.s.)
relevant = [d for d in datasets if d.startswith(("as-", "sro-"))]
out = OUTPUT_DIR / "justice_datasets.json"
with open(out, "w") as f:
json.dump({"total": len(datasets), "as_sro_datasets": relevant}, f, ensure_ascii=False, indent=2)
print(f" Total datasets: {len(datasets)}, a.s./s.r.o.: {len(relevant)}")
return datasets
# --- Single company lookup ---
def lookup_company(ico: str):
"""Lookup a single company across all sources."""
print(f"=== Lookup IČO: {ico} ===\n")
print("--- ARES ---")
try:
data = fetch_ares(ico)
print(f" Název: {data.get('obchodniJmeno')}")
print(f" Adresa: {data.get('sidlo', {}).get('textovaAdresa')}")
print(f" DIČ: {data.get('dic')}")
print(f" NACE: {data.get('czNace', [])[:5]}")
print(f" Založeno: {data.get('datumVzniku')}")
except Exception as e:
print(f" Error: {e}")
print("\n--- DPH ---")
try:
xml_str = fetch_dph(f"CZ{ico}")
import re
unreliable = re.findall(r'nespolehlivyPlatce="([^"]+)"', xml_str)
accounts = re.findall(r'<standardniUcet cislo="([^"]+)" kodBanky="([^"]+)"/>', xml_str)
print(f" Nespolehlivý plátce: {unreliable[0] if unreliable else 'N/A'}")
print(f" Bankovní účty: {len(accounts)}")
for a in accounts[:3]:
print(f" {a[0]}/{a[1]}")
except Exception as e:
print(f" Error: {e}")
print("\n--- ČNB OAM ---")
try:
xml_str = fetch_cnb_oam(ico)
import re
docs = re.findall(r"<DOCUMENT_ID>(\d+)</DOCUMENT_ID>", xml_str)
print(f" Regulované dokumenty: {len(docs)}")
except Exception as e:
print(f" Error: {e}")
# --- MAIN ---
if __name__ == "__main__":
if len(sys.argv) > 2 and sys.argv[1] == "lookup":
lookup_company(sys.argv[2])
else:
sources = sys.argv[1:] if len(sys.argv) > 1 else ["ares", "dph", "cnb_banks", "cnb_oam", "justice"]
runners = {
"ares": fetch_all_ares,
"dph": fetch_all_dph,
"cnb_banks": fetch_cnb_banks,
"cnb_oam": fetch_all_cnb_oam,
"justice": fetch_justice_datasets,
}
for source in sources:
if source in runners:
try:
runners[source]()
except Exception as e:
print(f"FATAL {source}: {e}")
else:
print(f"Unknown source: {source}. Available: lookup <IČO>, {list(runners.keys())}")
{
"portfolio": {
"25099345": {
"name": "PPF a.s."
},
"29045371": {
"name": "Air Bank a.s."
},
"60192666": {
"name": "Home Credit International a.s."
},
"47116129": {
"name": "PPF banka a.s."
},
"60193336": {
"name": "O2 Czech Republic a.s."
},
"04084063": {
"name": "CETIN a.s."
},
"10900004": {
"name": "SOTIO Biotech a.s."
},
"07822774": {
"name": "Heureka Group a.s."
},
"62623753": {
"name": "SKODA TRANSPORTATION a.s."
},
"07961774": {
"name": "ITIS Holding a.s."
},
"24214795": {
"name": "Bestsport a.s."
},
"27638987": {
"name": "PPF Real Estate s.r.o."
},
"17139708": {
"name": "EmbedIT s.r.o."
},
"45800456": {
"name": "TV Nova s.r.o."
},
"25672720": {
"name": "MONETA Money Bank a.s."
}
},
"competitors": {}
}#!/usr/bin/env python3
"""Fetch data from German Handelsregister via Apify actor.
Requires: mcpc CLI with authenticated @apify session.
Actor: radeance/handelsregister-api ($0.01/search, 99.5% success, rating 5.0)
Usage:
python fetch_all.py # fetch all companies
python fetch_all.py keyword Siemens # search by keyword
Sources:
handelsregister — Německý obchodní rejstřík (via Apify). Strukturovaná data: název,
právní forma, sídlo, základní kapitál, předmět podnikání, management
(jména + data narození), registrační soud, HRB číslo.
Žádné přímé DE entity, ale konkurenti Škoda Transportation ano
(Siemens Mobility, Stadler, Alstom). Relevantní pro DE telco (T-Mobile).
"""
import json
import os
import subprocess
import sys
import time
from pathlib import Path
BASE_DIR = Path(__file__).parent
OUTPUT_DIR = BASE_DIR / "output"
OUTPUT_DIR.mkdir(exist_ok=True)
with open(BASE_DIR / "lookup_targets.json") as f:
COMPANIES = json.load(f)
ACTOR = "radeance/handelsregister-api"
UA = "User-Agent: apify-awesome-skills/apify-mcpc-1.4.1/call_actor"
def mcpc_call_actor(input_data: dict, timeout: int = 120) -> dict:
"""Call Apify actor via mcpc and return structured result."""
input_json = json.dumps(input_data)
cmd = [
"mcpc", "-H", UA, "@apify", "tools-call", "call-actor",
f"actor:={ACTOR}",
f"input:={input_json}",
f'callOptions:={{"timeout": {timeout}}}',
"--json",
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout + 30)
if result.returncode != 0:
return {"error": result.stderr[:500]}
return json.loads(result.stdout).get("structuredContent", {})
def mcpc_get_output(dataset_id: str, limit: int = 100) -> list:
"""Get actor output from dataset."""
cmd = [
"mcpc", "-H", UA, "@apify", "tools-call", "get-actor-output",
f"datasetId:={dataset_id}", f"limit:={limit}", "--json",
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
if result.returncode != 0:
return []
return json.loads(result.stdout).get("structuredContent", {}).get("items", [])
def search_company(keyword: str) -> dict:
"""Search Handelsregister by company keyword."""
return mcpc_call_actor({"keyword": keyword})
def fetch_all():
print(f"=== DE Handelsregister (via {ACTOR}) ===")
results = {}
all_companies = {}
for sector, companies in COMPANIES.get("competitors", {}).items():
for reg_id, info in companies.items():
all_companies[reg_id] = {**info, "sector": sector}
for reg_id, info in all_companies.items():
keyword = info.get("keyword", info.get("name", ""))
print(f" Searching: {keyword}...")
try:
result = search_company(keyword)
run_id = result.get("runId")
dataset_id = result.get("datasetId")
item_count = result.get("itemCount", 0)
items = result.get("items", [])
results[reg_id] = {
"keyword": keyword,
"sector": info.get("sector"),
"run_id": run_id,
"item_count": item_count,
"data": items[:5],
}
print(f" OK: {item_count} results, runId={run_id}")
time.sleep(1.0)
except Exception as e:
results[reg_id] = {"keyword": keyword, "error": str(e)}
print(f" ERR: {e}")
out = OUTPUT_DIR / "handelsregister.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} searches to {out}")
return results
if __name__ == "__main__":
if len(sys.argv) > 2 and sys.argv[1] == "keyword":
keyword = " ".join(sys.argv[2:])
print(f"Searching: {keyword}")
result = search_company(keyword)
print(json.dumps(result, indent=2, ensure_ascii=False)[:2000])
else:
fetch_all()
{
"portfolio": {},
"competitors": {
"media": {
"prosiebensat1": {
"name": "ProSiebenSat.1 Media SE",
"keyword": "ProSiebenSat.1"
}
},
"industrial": {
"vitronic": {
"name": "VITRONIC Dr.-Ing. Stein Bildverarbeitungssysteme GmbH",
"keyword": "VITRONIC"
}
}
}
}#!/usr/bin/env python3
"""Fetch structured ESG data from verified working sources.
Usage:
python fetch_all.py # fetch all sources
python fetch_all.py ets # EU ETS verified emissions
python fetch_all.py climate_trace # Climate TRACE country emissions
python fetch_all.py eba # EBA bank capital/risk data (100MB+)
python fetch_all.py eba_esg # EBA Pillar 3 ESG signposting (XLSX)
python fetch_all.py ratings # ESG rating URLs for listed portfolio companies
python fetch_all.py lookup "Czech Republic" # lookup country in EU ETS + Climate TRACE
Sources (all verified working, free, no auth):
ets — EU ETS (GitHub CSV). Ověřené CO2 emise per průmyslová instalace.
76K řádků, filtrováno na portfolio země (BG, HU, PL, RO, SK).
CZ v tomto datasetu chybí. Portfolio firmy většinou nejsou těžký průmysl,
takže přímé matche jsou nepravděpodobné — spíš kontextový benchmark.
climate_trace — Climate TRACE REST API. Celkové GHG emise per země + global rank.
CZ: 232M tCO2e (#61), PL: 817M (#29). Kontextový zdroj, ne firemní data.
eba — EBA Transparency CSVs (100MB+ per soubor). Bankovní metriky: kapitál,
credit risk, sovereign exposure pro ~120 EU bank. Filtruje přes LEI.
Relevantní pro Air Bank + PPF banka pokud mají LEI v EBA datasetu (company names).
eba_esg — EBA Pillar 3 ESG signposting (XLSX, 62KB). Linky na ESG disclosures
~120 EU bank. Vyžaduje Referer header pro download.
ratings — ESG rating URLs (jen linky, žádná strojová data). S&P Global score
pro InPost a O2 CZ. Sustainalytics risk rating pro InPost.
NÍZKÁ HODNOTA: jen URL pro manuální lookup, nelze programově extrahovat.
PPF Group je privátní — hlavní ESG ratingové agentury ji nekryjí.
ESAP (centrální EU ESG databáze s API) spustí CSRD data až leden 2028.
"""
import json
import csv
import io
import sys
import time
import urllib.request
import urllib.parse
from pathlib import Path
BASE_DIR = Path(__file__).parent
OUTPUT_DIR = BASE_DIR / "output"
OUTPUT_DIR.mkdir(exist_ok=True)
with open(BASE_DIR / "lookup_targets.json") as f:
COMPANIES = json.load(f)
# --- 1. EU ETS (Emissions Trading System) ---
def fetch_eu_ets():
"""Download EU ETS verified emissions and filter by portfolio countries."""
print("=== EU ETS (Verified CO2 Emissions) ===")
url = COMPANIES["eu_ets"]["csv_url"]
countries = set(COMPANIES["eu_ets"]["countries"])
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=60) as resp:
data = resp.read().decode("utf-8")
reader = csv.DictReader(io.StringIO(data))
results = {}
total = 0
for row in reader:
total += 1
country = row.get("country", "")
if country in countries:
if country not in results:
results[country] = []
results[country].append(dict(row))
summary = {c: len(rows) for c, rows in results.items()}
print(f" Total rows: {total}")
for c, count in sorted(summary.items()):
print(f" {c}: {count} installations")
out = OUTPUT_DIR / "eu_ets.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved to {out}")
# --- 2. Climate TRACE (country-level emissions) ---
def fetch_climate_trace_country(country_code: str) -> dict:
"""Fetch country emissions from Climate TRACE API."""
url = f"https://api.climatetrace.org/v6/country/emissions?since=2022&to=2023&countries={country_code}"
req = urllib.request.Request(url, headers={"Accept": "application/json", "User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
def fetch_climate_trace_sectors(country_code: str) -> list:
"""Fetch sector breakdown for a country."""
url = f"https://api.climatetrace.org/v6/country/emissions?since=2023&to=2023&countries={country_code}&subsectors=true"
req = urllib.request.Request(url, headers={"Accept": "application/json", "User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
def fetch_all_climate_trace():
"""Fetch Climate TRACE emissions for all portfolio countries."""
print("=== Climate TRACE (Country Emissions) ===")
countries = COMPANIES["climate_trace"]["countries"]
results = {}
for cc in countries:
try:
data = fetch_climate_trace_country(cc)
if data and isinstance(data, list) and len(data) > 0:
entry = data[0]
emissions = entry.get("emissions", {})
co2e = emissions.get("co2e_100yr", 0)
results[cc] = {
"co2e_100yr_tonnes": co2e,
"co2_tonnes": emissions.get("co2", 0),
"ch4_tonnes": emissions.get("ch4", 0),
"rank": entry.get("rank"),
}
print(f" {cc}: {co2e/1e6:.1f}M tCO2e (rank #{entry.get('rank', '?')})")
else:
results[cc] = {"error": "no data"}
print(f" {cc}: no data")
time.sleep(0.3)
except Exception as e:
results[cc] = {"error": str(e)}
print(f" {cc}: {e}")
out = OUTPUT_DIR / "climate_trace.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved to {out}")
# --- 3. EBA Transparency (bank capital/risk CSVs) ---
def fetch_eba_transparency():
"""Download EBA transparency CSVs and filter for portfolio bank LEIs."""
print("=== EBA Transparency Exercise (Bank Data) ===")
base = COMPANIES["eba_transparency"]["base_url"]
files = COMPANIES["eba_transparency"]["files"]
# Known portfolio bank LEIs (from GLEIF)
# TODO: replace with actual LEIs from local/EU/output/gleif.json
portfolio_leis = set()
gleif_path = BASE_DIR.parent / "EU" / "output" / "gleif.json"
if gleif_path.exists():
with open(gleif_path) as f:
gleif = json.load(f)
for lei, info in gleif.items():
if isinstance(info, dict):
name = info.get("name", "").lower()
if any(k in name for k in ("air bank", "ppf banka", "ppf bank", "home credit")):
portfolio_leis.add(lei)
print(f" LEI match: {lei} ({info.get('name')})")
if not portfolio_leis:
print(" No portfolio bank LEIs found in GLEIF data. Run local/EU/fetch_all.py gleif first.")
print(" Downloading full CSVs for manual inspection...")
results = {}
for label, fname in files.items():
url = f"{base}/{fname}"
print(f" Downloading {fname}...")
try:
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=120) as resp:
reader = csv.DictReader(io.TextIOWrapper(resp, encoding="utf-8"))
matched = []
total = 0
for row in reader:
total += 1
if portfolio_leis and row.get("LEI_Code") in portfolio_leis:
matched.append(dict(row))
results[label] = {
"file": fname,
"total_rows": total,
"matched": len(matched),
"data": matched[:200],
}
print(f" {total} rows, {len(matched)} matched portfolio LEIs")
except Exception as e:
results[label] = {"error": str(e)}
print(f" Error: {e}")
out = OUTPUT_DIR / "eba_transparency.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved to {out}")
# --- 4. EBA Pillar 3 ESG signposting ---
def fetch_eba_esg():
"""Download EBA Pillar 3 ESG signposting XLSX."""
print("=== EBA Pillar 3 ESG (Signposting XLSX) ===")
url = COMPANIES["eba_transparency"]["pillar3_esg"]
out = OUTPUT_DIR / "eba_pillar3_esg_signposting.xlsx"
try:
req = urllib.request.Request(url, headers={
"Referer": "https://www.eba.europa.eu/",
"User-Agent": "Mozilla/5.0",
})
with urllib.request.urlopen(req, timeout=30) as resp:
with open(out, "wb") as f:
f.write(resp.read())
size = out.stat().st_size
print(f" Downloaded {size/1024:.0f} KB to {out}")
print(" Contains: ESG disclosure links for ~120 EU banks")
except Exception as e:
print(f" Error: {e}")
# --- 5. ESG Ratings (URLs for listed companies) ---
def fetch_ratings_info():
"""Print ESG rating URLs for listed portfolio companies."""
print("=== ESG Ratings (Free Lookup URLs) ===")
listed = COMPANIES.get("listed_companies", {})
for key, info in listed.items():
name = info.get("name", key)
print(f"\n {name}:")
if info.get("spglobal_url"):
print(f" S&P Global ESG Score: {info['spglobal_url']}")
if info.get("sustainalytics_url"):
print(f" Sustainalytics Risk Rating: {info['sustainalytics_url']}")
print(f" MSCI: search at https://www.msci.com/data-and-analytics/sustainability-solutions/esg-ratings-climate-search-tool")
print(f" LSEG: search at https://www.lseg.com/en/data-analytics/sustainable-finance/esg-scores")
print("\n Note: Group-level entity is private — ESG raters cover mainly listed companies.")
print(" ESAP (centralized CSRD reports + API) launches January 2028.")
# --- Single lookup ---
def lookup_country(name: str):
"""Lookup a country in EU ETS and Climate TRACE."""
print(f"=== ESG Lookup: {name} ===\n")
# Map common names to ISO codes
name_to_code = {
"czech republic": "CZE", "czechia": "CZE", "cz": "CZE",
"slovakia": "SVK", "sk": "SVK",
"poland": "POL", "pl": "POL",
"hungary": "HUN", "hu": "HUN",
"bulgaria": "BGR", "bg": "BGR",
"serbia": "SRB", "rs": "SRB",
"romania": "ROU", "ro": "ROU",
}
code = name_to_code.get(name.lower(), name.upper())
print("--- Climate TRACE ---")
try:
data = fetch_climate_trace_country(code)
if data and isinstance(data, list) and data:
e = data[0].get("emissions", {})
print(f" CO2e (100yr): {e.get('co2e_100yr', 0)/1e6:.1f}M tonnes")
print(f" CO2: {e.get('co2', 0)/1e6:.1f}M tonnes")
print(f" CH4: {e.get('ch4', 0)/1e6:.2f}M tonnes")
print(f" Global rank: #{data[0].get('rank', '?')}")
else:
print(f" No data for {code}")
except Exception as e:
print(f" Error: {e}")
print("\n--- EU ETS ---")
# Map ISO3 to country names used in ETS CSV
code_to_name = {"CZE": "Czech Republic", "SVK": "Slovakia", "POL": "Poland",
"HUN": "Hungary", "BGR": "Bulgaria", "ROU": "Romania"}
ets_name = code_to_name.get(code, name)
print(f" Filter EU ETS CSV for country='{ets_name}'")
print(f" Run: python fetch_all.py ets")
ets_path = OUTPUT_DIR / "eu_ets.json"
if ets_path.exists():
with open(ets_path) as f:
ets = json.load(f)
rows = ets.get(ets_name, [])
print(f" Found {len(rows)} installations in cached data")
for r in rows[:3]:
print(f" {r.get('main activity sector name', '?')}: {r.get('value', '?')} {r.get('unit', '')}")
# --- MAIN ---
if __name__ == "__main__":
if len(sys.argv) > 2 and sys.argv[1] == "lookup":
lookup_country(" ".join(sys.argv[2:]))
else:
sources = sys.argv[1:] if len(sys.argv) > 1 else ["ets", "climate_trace", "eba_esg", "ratings"]
# Note: 'eba' downloads 100MB+ CSVs, run separately
runners = {
"ets": fetch_eu_ets,
"climate_trace": fetch_all_climate_trace,
"eba": fetch_eba_transparency,
"eba_esg": fetch_eba_esg,
"ratings": fetch_ratings_info,
}
for source in sources:
if source in runners:
try:
runners[source]()
except Exception as e:
print(f"FATAL {source}: {e}")
else:
print(f"Unknown source: {source}. Available: lookup <country>, {list(runners.keys())}")
{
"eu_ets": {
"csv_url": "https://raw.githubusercontent.com/EU-ETS/ets-data/main/data/verified_emissions.csv",
"countries": [
"BG",
"HU",
"PL",
"RO",
"SK"
]
},
"climate_trace": {
"countries": [
"CZE",
"SVK",
"POL",
"HUN",
"BGR",
"ROU"
]
},
"eba_transparency": {
"base_url": "https://www.eba.europa.eu/assets/TE2025/Full_database/883401",
"files": {
"credit_risk": "tr_cre.csv",
"market_risk": "tr_mrk.csv",
"sovereign": "tr_sov.csv"
},
"pillar3_esg": "https://www.eba.europa.eu/sites/default/files/2024-01/fbe34c1a-2e2a-4d89-b123-signposting_p3_esg.xlsx"
},
"listed_companies": {
"inpost": {
"name": "InPost S.A.",
"isin": "LU2290522684",
"spglobal_url": "https://www.spglobal.com/esg/scores/results?cid=4854825",
"sustainalytics_url": "https://www.sustainalytics.com/esg-rating/inpost-sa/2006987965"
},
"o2_cz": {
"name": "O2 Czech Republic a.s.",
"isin": "CZ0009093209",
"spglobal_url": "https://www.spglobal.com/esg/scores/results?cid=4074563"
}
},
"portfolio": {},
"competitors": {}
}#!/usr/bin/env python3
"""Fetch data from all EU-level sources for portfolio companies.
Usage:
python fetch_all.py # fetch all sources (except EBA)
python fetch_all.py gleif esma # fetch specific sources
python fetch_all.py eba # fetch EBA (100MB+ download!)
python fetch_all.py lookup PPF # search GLEIF + ESMA + TED for name
python fetch_all.py lookup_lei 31570048XH84U51GGT05 # lookup by LEI
Sources:
gleif — GLEIF REST API. LEI identifikátory + vlastnická struktura (parent/ultimate
parent chain). Nejcennější EU zdroj — mapuje vlastnické řetězce →
AMALAR Holding. 51 LEI záznamů nalezeno. Zdarma, bez auth.
esma — ESMA FIRDS (Solr API). Finanční instrumenty: dluhopisy, akcie, deriváty.
InPost: 4394 instrumentů, O2 CZ: 37, CETIN: 40, PPF Arena bonds: 2.
Zdarma, bez auth.
eba — EBA Transparency Exercise (CSV download, 100MB+ per soubor). Bankovní metriky:
kapitál, credit risk, market risk, sovereign exposure pro ~120 EU bank.
Filtruje se přes LEI kódy. Zdarma, bez auth.
ted — TED API (veřejné zakázky). Contract awards s hodnotou, buyer/winner.
NÍZKÁ HODNOTA: většina portfolio firem jsou soukromé a nezadávají
veřejné zakázky. Výjimka: CETIN (116 zakázek). Winner-name jen u
novějších eForms notices (~2024+).
eurostat — Eurostat SDMX API. Makroekonomické statistiky (GDP, sektorová data).
NÍZKÁ HODNOTA: příliš agregované, žádná firemní data. Jen jako kontextový
benchmark pro země kde portfolio operuje.
"""
import json
import os
import sys
import time
import urllib.request
import csv
import io
from pathlib import Path
BASE_DIR = Path(__file__).parent
OUTPUT_DIR = BASE_DIR / "output"
OUTPUT_DIR.mkdir(exist_ok=True)
with open(BASE_DIR / "lookup_targets.json") as f:
COMPANIES = json.load(f)
# Also load CZ companies for LEI cross-referencing
CZ_COMPANIES_PATH = BASE_DIR.parent / "CZ" / "lookup_targets.json"
CZ_COMPANIES = {}
if CZ_COMPANIES_PATH.exists():
with open(CZ_COMPANIES_PATH) as f:
CZ_COMPANIES = json.load(f)
# --- 1. GLEIF API (LEI + ownership) ---
def gleif_search_name(name: str) -> list:
encoded = urllib.parse.quote(name)
url = f"https://api.gleif.org/api/v1/lei-records?filter%5Bentity.legalName%5D={encoded}&page%5Bsize%5D=10"
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read()).get("data", [])
def gleif_get_lei(lei: str) -> dict:
url = f"https://api.gleif.org/api/v1/lei-records/{lei}"
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read()).get("data", {})
def gleif_get_parent(lei: str) -> dict:
url = f"https://api.gleif.org/api/v1/lei-records/{lei}/direct-parent-relationship"
req = urllib.request.Request(url)
try:
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read()).get("data", {})
except urllib.error.HTTPError:
return {}
def fetch_all_gleif():
print("=== GLEIF (LEI + Ownership) ===")
results = {}
# Search for all portfolio entities by name
for search_term in ["PPF", "Home Credit", "CETIN", "Air Bank", "O2 Czech", "Heureka", "SOTIO", "InPost"]:
try:
records = gleif_search_name(search_term)
for rec in records:
lei = rec["attributes"]["lei"]
entity = rec["attributes"]["entity"]
results[lei] = {
"lei": lei,
"name": entity["legalName"]["name"],
"jurisdiction": entity.get("jurisdiction"),
"status": entity["status"],
"registered_as": entity.get("registeredAs"),
"category": entity.get("category"),
}
print(f" Search '{search_term}': {len(records)} results")
time.sleep(0.3)
except Exception as e:
print(f" ERR search '{search_term}': {e}")
# Get parent relationships for known portfolio LEIs
portfolio_leis = list(COMPANIES["portfolio"].keys())
for lei in portfolio_leis:
try:
parent = gleif_get_parent(lei)
if parent:
rel = parent.get("attributes", {}).get("relationship", {})
end_lei = rel.get("endNode", {}).get("id", "")
if end_lei:
results.setdefault(lei, {})["parent_lei"] = end_lei
# Resolve parent name
parent_rec = gleif_get_lei(end_lei)
if parent_rec:
parent_name = parent_rec.get("attributes", {}).get("entity", {}).get("legalName", {}).get("name")
results[lei]["parent_name"] = parent_name
print(f" Ownership: {lei[:12]}... -> {parent_name}")
time.sleep(0.3)
except Exception as e:
print(f" ERR parent {lei}: {e}")
out = OUTPUT_DIR / "gleif.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} LEI records to {out}")
return results
# --- 2. TED (Public Procurement — contract awards only) ---
# TED expert query syntax: buyer-name ~ "*keyword*" AND notice-type = can-standard
# Output fields: total-value, winner-name, buyer-name, buyer-country, place-of-performance
# NOTE: winner-name is only populated in eForms notices (~2023+). Older notices have
# winner data only in the XML document (fetch via notice links.xml.MUL URL).
TED_OUTPUT_FIELDS = [
"publication-date", "notice-type", "buyer-name", "buyer-country",
"contract-nature", "procedure-type", "total-value",
"winner-name", "place-of-performance", "dispatch-date",
]
def fetch_ted_awards(query: str, limit: int = 50) -> list:
"""Search TED for contract award notices (won contracts) matching buyer name."""
url = "https://api.ted.europa.eu/v3/notices/search"
expert_query = f'buyer-name ~ "*{query}*" AND notice-type = can-standard'
body = json.dumps({"query": expert_query, "fields": TED_OUTPUT_FIELDS, "limit": limit})
req = urllib.request.Request(url, data=body.encode(), headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=30) as resp:
data = json.loads(resp.read())
return data.get("notices", []), data.get("totalNoticeCount", 0)
def _extract_name(field_val):
"""Extract name from TED multi-lang dict."""
if isinstance(field_val, dict):
return field_val.get("ces", field_val.get("eng", field_val.get("mul", [""])))[0] if field_val else ""
return str(field_val) if field_val else ""
def fetch_all_ted():
print("=== TED (Contract Awards) ===")
results = {}
search_terms = ["PPF", "O2 Czech", "CETIN", "Air Bank", "Home Credit",
"Škoda Transportation", "CzechToll", "InPost", "Heureka"]
for term in search_terms:
try:
notices, total = fetch_ted_awards(term, limit=200)
awards = []
for n in notices:
awards.append({
"id": n.get("publication-number"),
"date": n.get("publication-date", ""),
"buyer": _extract_name(n.get("buyer-name")),
"buyer_country": n.get("buyer-country", []),
"winner": _extract_name(n.get("winner-name")),
"value_eur": n.get("total-value"),
"nature": n.get("contract-nature", []),
"procedure": n.get("procedure-type", ""),
"nuts": n.get("place-of-performance", []),
})
results[term] = {"total": total, "awards": awards}
print(f" '{term}': {total} contract awards")
for a in awards[:3]:
val = f"€{a['value_eur']:,.0f}" if a.get("value_eur") else "?"
print(f" {a['date'][:10]} | {a['buyer'][:30]} | {val} | winner: {a['winner'][:30]}")
time.sleep(0.5)
except Exception as e:
results[term] = {"error": str(e)}
print(f" ERR '{term}': {e}")
out = OUTPUT_DIR / "ted.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} searches to {out}")
return results
# --- 3. ESMA FIRDS (Financial Instruments) ---
def fetch_esma_firds(query: str) -> dict:
encoded = urllib.parse.quote(f'"{query}"')
url = f"https://registers.esma.europa.eu/solr/esma_registers_firds/select?q=gnr_full_name:{encoded}&rows=20&wt=json&fl=id,isin,lei,gnr_full_name,status,gnr_cfi_code"
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
def fetch_all_esma():
print("=== ESMA FIRDS (Financial Instruments) ===")
results = {}
search_terms = ["PPF Arena", "PPF Group", "O2 Czech", "Home Credit", "CETIN", "InPost"]
for term in search_terms:
try:
data = fetch_esma_firds(term)
docs = data.get("response", {}).get("docs", [])
num_found = data.get("response", {}).get("numFound", 0)
results[term] = {
"total_found": num_found,
"instruments": [
{
"isin": d.get("isin"),
"name": d.get("gnr_full_name"),
"lei": d.get("lei"),
"status": d.get("status"),
"cfi": d.get("gnr_cfi_code"),
}
for d in docs
],
}
print(f" '{term}': {num_found} instruments")
time.sleep(0.3)
except Exception as e:
results[term] = {"error": str(e)}
print(f" ERR '{term}': {e}")
out = OUTPUT_DIR / "esma_firds.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} searches to {out}")
return results
# --- 4. EBA Transparency Exercise ---
EBA_BASE = "https://www.eba.europa.eu/assets/TE2025/Full_database/883401"
EBA_FILES = ["tr_cre.csv", "tr_mrk.csv", "tr_sov.csv"]
def fetch_eba_for_leis(lei_list: list):
"""Download EBA CSV and filter for specific LEI codes."""
print("=== EBA Transparency Exercise ===")
results = {}
lei_set = set(lei_list)
for fname in EBA_FILES:
url = f"{EBA_BASE}/{fname}"
print(f" Downloading {fname}...")
try:
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=120) as resp:
# Stream and filter - these files are 100MB+
reader = csv.DictReader(io.TextIOWrapper(resp, encoding="utf-8"))
matched_rows = []
total = 0
for row in reader:
total += 1
if row.get("LEI_Code") in lei_set:
matched_rows.append(dict(row))
results[fname] = {
"total_rows": total,
"matched_rows": len(matched_rows),
"data": matched_rows[:500], # cap to avoid huge files
}
print(f" {fname}: {total} total rows, {len(matched_rows)} matched for our LEIs")
except Exception as e:
results[fname] = {"error": str(e)}
print(f" ERR {fname}: {e}")
out = OUTPUT_DIR / "eba_transparency.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved to {out}")
return results
def fetch_all_eba():
# Get LEIs from GLEIF results or known list
gleif_path = OUTPUT_DIR / "gleif.json"
lei_list = list(COMPANIES["portfolio"].keys())
if gleif_path.exists():
with open(gleif_path) as f:
gleif_data = json.load(f)
lei_list.extend(gleif_data.keys())
return fetch_eba_for_leis(lei_list)
# --- 5. Eurostat (sector benchmarks) ---
def fetch_eurostat(dataset: str, params: dict) -> dict:
param_str = "&".join(f"{k}={v}" for k, v in params.items())
url = f"https://ec.europa.eu/eurostat/api/dissemination/sdmx/2.1/data/{dataset}?{param_str}&format=JSON&lang=en"
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=30) as resp:
return json.loads(resp.read())
def fetch_all_eurostat():
print("=== Eurostat (sector benchmarks) ===")
results = {}
queries = {
"gdp_cz_pl": {"dataset": "nama_10_gdp", "params": {"na_item": "B1GQ", "geo": "CZ+PL", "unit": "CP_MEUR", "time": "2021+2022+2023+2024"}},
}
for name, q in queries.items():
try:
data = fetch_eurostat(q["dataset"], q["params"])
results[name] = {
"label": data.get("label"),
"value_count": len(data.get("value", {})),
}
print(f" {name}: {len(data.get('value', {}))} data points")
except Exception as e:
results[name] = {"error": str(e)}
print(f" ERR {name}: {e}")
out = OUTPUT_DIR / "eurostat.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved to {out}")
return results
# --- Single company lookup ---
def lookup_by_name(name: str):
"""Search for a company across GLEIF, ESMA, and TED by name."""
print(f"=== Lookup: {name} ===\n")
print("--- GLEIF (LEI) ---")
try:
records = gleif_search_name(name)
for rec in records[:5]:
e = rec["attributes"]["entity"]
lei = rec["attributes"]["lei"]
print(f" LEI: {lei} {e['legalName']['name']} [{e.get('jurisdiction','?')}] {e['status']}")
except Exception as ex:
print(f" Error: {ex}")
print("\n--- ESMA FIRDS (instruments) ---")
try:
data = fetch_esma_firds(name)
docs = data.get("response", {}).get("docs", [])
num = data.get("response", {}).get("numFound", 0)
print(f" Found: {num} instruments")
for d in docs[:5]:
print(f" ISIN: {d.get('isin')} {d.get('gnr_full_name')} [{d.get('status')}]")
except Exception as ex:
print(f" Error: {ex}")
print("\n--- TED (contract awards) ---")
try:
awards, total = fetch_ted_awards(name, limit=10)
print(f" Found: {total} contract awards")
for a in awards[:5]:
buyer = _extract_name(a.get("buyer-name"))
winner = _extract_name(a.get("winner-name"))
val = a.get("total-value")
val_str = f"€{val:,.0f}" if val else "?"
print(f" {a.get('publication-date','')[:10]} | {buyer[:30]} | {val_str} | winner: {winner[:30]}")
except Exception as ex:
print(f" Error: {ex}")
def lookup_by_lei(lei: str):
"""Lookup a specific LEI with ownership chain."""
print(f"=== Lookup LEI: {lei} ===\n")
print("--- GLEIF record ---")
try:
rec = gleif_get_lei(lei)
e = rec.get("attributes", {}).get("entity", {})
print(f" Name: {e.get('legalName', {}).get('name')}")
print(f" Jurisdiction: {e.get('jurisdiction')}")
print(f" Status: {e.get('status')}")
print(f" Registered as: {e.get('registeredAs')}")
addr = e.get("legalAddress", {})
print(f" Address: {addr.get('addressLines', [''])} {addr.get('city', '')} {addr.get('country', '')}")
except Exception as ex:
print(f" Error: {ex}")
print("\n--- Ownership chain ---")
try:
parent = gleif_get_parent(lei)
if parent:
rel = parent.get("attributes", {}).get("relationship", {})
parent_lei = rel.get("endNode", {}).get("id", "")
if parent_lei:
parent_rec = gleif_get_lei(parent_lei)
parent_name = parent_rec.get("attributes", {}).get("entity", {}).get("legalName", {}).get("name")
print(f" Direct parent: {parent_name} (LEI: {parent_lei})")
else:
print(" No parent relationship found")
else:
print(" No parent relationship found")
except Exception as ex:
print(f" Error: {ex}")
# --- MAIN ---
if __name__ == "__main__":
if len(sys.argv) > 2 and sys.argv[1] == "lookup":
lookup_by_name(" ".join(sys.argv[2:]))
elif len(sys.argv) > 2 and sys.argv[1] == "lookup_lei":
lookup_by_lei(sys.argv[2])
else:
sources = sys.argv[1:] if len(sys.argv) > 1 else ["gleif", "ted", "esma", "eurostat"]
# Note: EBA download is 100MB+ per file, run separately with: python fetch_all.py eba
runners = {
"gleif": fetch_all_gleif,
"ted": fetch_all_ted,
"esma": fetch_all_esma,
"eba": fetch_all_eba,
"eurostat": fetch_all_eurostat,
}
for source in sources:
if source in runners:
try:
runners[source]()
except Exception as e:
print(f"FATAL {source}: {e}")
else:
print(f"Unknown source: {source}. Available: lookup <name>, lookup_lei <LEI>, {list(runners.keys())}")
{
"portfolio": {
"31570048XH84U51GGT05": {
"name": "PPF a.s."
},
"31570010000000049662": {
"name": "Air Bank a.s."
},
"31570010000000036567": {
"name": "PPF banka a.s."
}
},
"competitors": {}
}#!/usr/bin/env python3
"""Fetch data from Dutch KvK (Kamer van Koophandel) API.
REQUIRES: API key from https://developers.kvk.nl (see REGISTRATION.md)
Set env: KVK_API_KEY=<your-key>
Usage:
python fetch_all.py # fetch all NL companies (needs KVK_API_KEY)
Sources:
kvk — KvK REST API (Kamer van Koophandel). Základní profil firmy, adresy poboček,
obchodní jména. Nejdůležitější NL registr — PPF Group N.V. (KvK 33264887),
Home Credit N.V., e& PPF Telecom Group B.V., CME Media Enterprises B.V.
a dalších 3 NL holdings jsou tu registrovány.
Vyžaduje registraci na developers.kvk.nl + schválení → API klíč.
"""
import json
import os
import sys
import time
import urllib.request
from pathlib import Path
BASE_DIR = Path(__file__).parent
OUTPUT_DIR = BASE_DIR / "output"
OUTPUT_DIR.mkdir(exist_ok=True)
with open(BASE_DIR / "lookup_targets.json") as f:
COMPANIES = json.load(f)
API_KEY = os.environ.get("KVK_API_KEY")
BASE_URL = "https://api.kvk.nl/api/v1"
def kvk_request(endpoint: str) -> dict:
if not API_KEY:
raise RuntimeError("KVK_API_KEY not set. See REGISTRATION.md")
url = f"{BASE_URL}/{endpoint}"
req = urllib.request.Request(url, headers={"apikey": API_KEY})
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
def fetch_profile(kvk_number: str) -> dict:
return kvk_request(f"basisprofielen/{kvk_number}")
def fetch_all():
print("=== NL KvK (Kamer van Koophandel) ===")
if not API_KEY:
print(" ERROR: KVK_API_KEY not set.")
print(" Register at https://developers.kvk.nl — see REGISTRATION.md")
return {}
results = {}
all_companies = dict(COMPANIES["portfolio"])
for sector_companies in COMPANIES.get("competitors", {}).values():
all_companies.update(sector_companies)
for kvk, info in all_companies.items():
try:
data = fetch_profile(kvk)
results[kvk] = data
print(f" OK {kvk} {info.get('name', '')}")
time.sleep(0.5)
except Exception as e:
results[kvk] = {"error": str(e), "name": info.get("name", "")}
print(f" ERR {kvk} {e}")
out = OUTPUT_DIR / "kvk.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} records to {out}")
return results
if __name__ == "__main__":
fetch_all()
{
"portfolio": {
"0000536554": {
"name": "InPost S.A.",
"nip": "6793087624",
"regon": "12272626000000"
}
},
"competitors": {}
}#!/usr/bin/env python3
"""Fetch data from Romanian sources for portfolio (PRO TV) + competitors.
Usage:
python fetch_all.py # fetch ANAF for all companies
python fetch_all.py listafirme # scrape ListaFirme via Apify
python fetch_all.py status # check Apify run status
python fetch_all.py lookup 2835636 # lookup single company by CUI (ANAF)
Sources:
listafirme — ListaFirme.ro (via Apify, Cloudflare-protected). Firemní profily z rumunského
registru: CUI, adresa, CAEN kódy, bilanční data. Portfolio entita: PRO TV S.R.L.
Vyžaduje Apify residential proxy.
anaf — ANAF (Agenția Națională de Administrare Fiscală) REST API. Status plátce DPH,
adresa, aktivní/neaktivní.
NEFUNKČNÍ od března 2026 — endpoint webservicesp.anaf.ro vrací 404.
Alternativa: openapi.ro nebo termene.ro (vyžadují API klíč).
Original sources:
1. ListaFirme.ro — company profiles (via Apify, Cloudflare-protected)
2. ANAF public data — tax/VAT status (direct API)
"""
import json
import os
import subprocess
import sys
import time
import urllib.request
from pathlib import Path
BASE_DIR = Path(__file__).parent
OUTPUT_DIR = BASE_DIR / "output"
OUTPUT_DIR.mkdir(exist_ok=True)
with open(BASE_DIR / "lookup_targets.json") as f:
COMPANIES = json.load(f)
UA = "User-Agent: apify-awesome-skills/apify-mcpc-1.4.1/call_actor"
def all_cuis():
"""Return all CUI numbers."""
companies = dict(COMPANIES["portfolio"])
for sector_companies in COMPANIES["competitors"].values():
companies.update(sector_companies)
return companies
# --- 1. ListaFirme.ro via Apify ---
def fetch_listafirme_apify(cui: str, name: str) -> dict:
"""Scrape company profile from listafirme.ro via Apify."""
slug = name.lower().replace(" ", "-").replace(".", "").replace(",", "")
url = f"https://www.listafirme.ro/{slug}-{cui}/"
input_data = {
"startUrls": [{"url": url}],
"maxCrawlPages": 1,
"crawlerType": "playwright:firefox",
"proxyConfiguration": {"useApifyProxy": True, "apifyProxyGroups": ["RESIDENTIAL"]},
}
input_json = json.dumps(input_data)
cmd = [
"mcpc", "-H", UA, "@apify", "tools-call", "call-actor",
"actor:=apify/website-content-crawler",
f"input:={input_json}",
'callOptions:={"memory": 2048, "timeout": 60}',
"previewOutput:=false", "async:=true", "--json",
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=90)
if result.returncode != 0:
return {"error": result.stderr[:300]}
return json.loads(result.stdout).get("structuredContent", {})
def fetch_all_listafirme():
print("=== ListaFirme.ro (via Apify) ===")
runs = {}
for cui, info in all_cuis().items():
name = info.get("name", "")
print(f" Launching: {cui} {name}...")
try:
result = fetch_listafirme_apify(cui, name)
run_id = result.get("runId", "?")
runs[cui] = {"name": name, "run_id": run_id}
print(f" runId={run_id}")
time.sleep(1.0)
except Exception as e:
runs[cui] = {"name": name, "error": str(e)}
print(f" ERR: {e}")
out = OUTPUT_DIR / "listafirme_runs.json"
with open(out, "w") as f:
json.dump(runs, f, ensure_ascii=False, indent=2)
print(f" Saved {len(runs)} async runs to {out}")
print(" Check status: python fetch_all.py status")
return runs
# --- 2. ANAF tax validation ---
# NOTE: ANAF webservicesp.anaf.ro API appears offline as of March 2026.
# They may have migrated to a new endpoint. Check https://www.anaf.ro for updates.
# Alternative: use https://termene.ro or https://openapi.ro (need API key)
def fetch_anaf(cui: str) -> dict:
"""Check company VAT status via ANAF public API."""
from datetime import date
today = date.today().isoformat()
url = "https://webservicesp.anaf.ro/AsynchWebApi/api/v8/interogare/getInformatii"
body = json.dumps([{"cui": int(cui), "data": today}])
req = urllib.request.Request(url, data=body.encode(), headers={
"Content-Type": "application/json",
})
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
def fetch_all_anaf():
print("=== ANAF (tax/VAT status) ===")
results = {}
for cui, info in all_cuis().items():
try:
data = fetch_anaf(cui)
found = data.get("found", [])
if found:
f = found[0]
results[cui] = {
"name": f.get("denumire", ""),
"address": f.get("adresa", ""),
"vat_payer": f.get("scpTVA", False),
"vat_split": f.get("statusTvaIncasare", False),
"active": f.get("statusInactivi", False) is False,
"reactivated": f.get("dataReactivare"),
}
status = "TVA" if f.get("scpTVA") else "non-TVA"
print(f" OK {cui} {f.get('denumire','')} [{status}]")
else:
not_found = data.get("notfound", [])
results[cui] = {"cui": cui, "found": False}
print(f" NOTFOUND {cui} {info.get('name', '')}")
time.sleep(0.3)
except Exception as e:
results[cui] = {"error": str(e)}
print(f" ERR {cui} {e}")
out = OUTPUT_DIR / "anaf.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} records to {out}")
return results
# --- Status check ---
def check_status():
fpath = OUTPUT_DIR / "listafirme_runs.json"
if not fpath.exists():
print("No runs to check")
return
with open(fpath) as f:
runs = json.load(f)
for cui, info in runs.items():
run_id = info.get("run_id")
if not run_id or run_id == "?":
continue
cmd = [
"mcpc", "-H", UA, "@apify", "tools-call", "get-actor-run",
f"runId:={run_id}", "--json",
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode == 0:
sc = json.loads(result.stdout).get("structuredContent", {})
ds = sc.get("dataset", {})
print(f" {cui} ({info.get('name','')}): status={sc.get('status')} items={ds.get('itemCount','?')}")
# --- Single company lookup ---
def lookup_company(cui: str):
"""Lookup a single Romanian company by CUI."""
print(f"=== Lookup CUI: {cui} ===\n")
print("--- ANAF ---")
try:
data = fetch_anaf(cui)
found = data.get("found", [])
if found:
f = found[0]
print(f" Denumire: {f.get('denumire')}")
print(f" Adresa: {f.get('adresa')}")
print(f" Plătitor TVA: {f.get('scpTVA')}")
print(f" Activ: {f.get('statusInactivi', False) is False}")
else:
print(f" Not found (ANAF API may be offline — check https://www.anaf.ro)")
except Exception as e:
print(f" Error: {e}")
print("\n--- ListaFirme (Apify) ---")
print(f" Run: python fetch_all.py listafirme")
print(f" Or manually: https://www.listafirme.ro/search?query={cui}")
# --- MAIN ---
if __name__ == "__main__":
if len(sys.argv) > 2 and sys.argv[1] == "lookup":
lookup_company(sys.argv[2])
else:
sources = sys.argv[1:] if len(sys.argv) > 1 else ["anaf"]
runners = {
"anaf": fetch_all_anaf,
"listafirme": fetch_all_listafirme,
"status": check_status,
}
for source in sources:
if source in runners:
try:
runners[source]()
except Exception as e:
print(f"FATAL {source}: {e}")
else:
print(f"Unknown source: {source}. Available: lookup <CUI>, {list(runners.keys())}")
{
"portfolio": {
"2835636": {
"name": "PRO TV S.R.L."
}
},
"competitors": {}
}{
"portfolio": {
"48074560": {
"name": "CETIN Slovakia s.r.o."
}
},
"competitors": {}
}#!/usr/bin/env python3
"""Fetch data from UK Companies House via Apify actor.
Requires: mcpc CLI with authenticated @apify session.
Actor: dhrumil/company-house-scraper (pay-per-event, 95.7% success, rating 5.0)
Usage:
python fetch_all.py # fetch all companies
python fetch_all.py search NAME # search by name
Sources:
companies_house — UK Companies House (via Apify). Company number, status, adresa,
SIC kódy, datum inkorporace, officers (directors + secretary),
accounts timeline, confirmation statement.
Portfolio entita: ClearBank Group Holdings Ltd (#14254435).
Konkurenti: Modulr, Starling Bank, Monzo Bank.
"""
import json
import os
import subprocess
import sys
import time
from pathlib import Path
BASE_DIR = Path(__file__).parent
OUTPUT_DIR = BASE_DIR / "output"
OUTPUT_DIR.mkdir(exist_ok=True)
with open(BASE_DIR / "lookup_targets.json") as f:
COMPANIES = json.load(f)
ACTOR = "dhrumil/company-house-scraper"
UA = "User-Agent: apify-awesome-skills/apify-mcpc-1.4.1/call_actor"
CH_SEARCH_BASE = "https://find-and-update.company-information.service.gov.uk/advanced-search/get-results"
def build_search_url(company_name: str) -> str:
"""Build Companies House advanced search URL."""
from urllib.parse import urlencode
params = {
"companyNameIncludes": company_name,
"companyNameExcludes": "",
}
return f"{CH_SEARCH_BASE}?{urlencode(params)}"
def mcpc_call_actor(input_data: dict, timeout: int = 180) -> dict:
"""Call Apify actor via mcpc and return structured result."""
input_json = json.dumps(input_data)
cmd = [
"mcpc", "-H", UA, "@apify", "tools-call", "call-actor",
f"actor:={ACTOR}",
f"input:={input_json}",
f'callOptions:={{"timeout": {timeout}}}',
"--json",
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout + 30)
if result.returncode != 0:
return {"error": result.stderr[:500]}
return json.loads(result.stdout).get("structuredContent", {})
def search_company(name: str, max_companies: int = 10) -> dict:
"""Search Companies House by company name."""
search_url = build_search_url(name)
return mcpc_call_actor({
"listUrls": [{"url": search_url}],
"maxCompanies": max_companies,
})
def fetch_all():
print(f"=== UK Companies House (via {ACTOR}) ===")
results = {}
# Collect all companies to search
all_searches = {}
for key, info in COMPANIES.get("portfolio", {}).items():
if isinstance(info, dict) and "keyword" in info:
all_searches[key] = info
for sector, companies in COMPANIES.get("competitors", {}).items():
for key, info in companies.items():
all_searches[key] = {**info, "sector": sector}
for key, info in all_searches.items():
keyword = info.get("keyword", info.get("name", ""))
print(f" Searching: {keyword}...")
try:
result = search_company(keyword, max_companies=5)
run_id = result.get("runId")
item_count = result.get("itemCount", 0)
items = result.get("items", [])
results[key] = {
"keyword": keyword,
"sector": info.get("sector", "unclassified"),
"run_id": run_id,
"item_count": item_count,
"data": items[:3],
}
print(f" OK: {item_count} results")
time.sleep(1.0)
except Exception as e:
results[key] = {"keyword": keyword, "error": str(e)}
print(f" ERR: {e}")
out = OUTPUT_DIR / "companies_house.json"
with open(out, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f" Saved {len(results)} searches to {out}")
return results
if __name__ == "__main__":
if len(sys.argv) > 2 and sys.argv[1] == "search":
name = " ".join(sys.argv[2:])
print(f"Searching: {name}")
result = search_company(name)
print(json.dumps(result, indent=2, ensure_ascii=False)[:2000])
else:
fetch_all()
Related skills
FAQ
Which countries are covered?
CZ, SK, PL, DE, UK, NL, RO, HR, SE plus EU-level and ESG sources, 11 countries/regions in total.
Does every lookup need Apify?
No. Most use stdlib Python REST scripts; Apify access is only needed for DE, UK, PL financials, CZ justice.cz, and RO fallback.