firmendata-python
Official Python client for the firmendata API — data on 2.4 million German companies from the Unternehmensregister and Handelsregister: register profiles, parsed annual financial statements, shareholder cap tables, UBO chains, insolvency notices and public-tender links.
pip install firmendata
Try it without signing up
Company-name autocomplete is free and needs no API key:
from firmendata import FirmenData
for hit in FirmenData().autocomplete("siemens")["data"]:
print(hit["eu_id"], hit["display_name"])
Keyless calls are rate limited, modestly and by address — enough to try the
API, back a search box, or run low-volume queries. Add a key for substantially
higher limits plus every other endpoint. On a 429, honour Retry-After;
the client already does this for you.
With an API key
Create one at firmendata.com — the free plan includes 100 credits.
from firmendata import FirmenData
fd = FirmenData(api_key="firmendata_live_...")
# Advanced search — filters combine with AND, lists with OR
results = fd.search(
city=["Berlin", "Hamburg"],
revenue_min=1_000_000,
legal_status=["insolvent"],
limit=25,
)
for hit in results["data"]:
print(hit["display_name"], hit["address"]["city"])
# Paginate
if results["pagination"]["has_more"]:
next_page = fd.search(cursor=results["pagination"]["next_cursor"])
eu_id = "DEB1103R_HRB123456"
fd.get_company(eu_id) # full profile
fd.get_financials(eu_id) # multi-year statements, parsed into figures
fd.get_shareholders(eu_id) # cap table from the Gesellschafterliste
fd.get_ubo(eu_id) # beneficial owners through ownership chains
fd.get_history(eu_id) # chronological register history
Async
Same methods, same semantics:
import asyncio
from firmendata import AsyncFirmenData
async def main():
async with AsyncFirmenData(api_key="firmendata_live_...") as fd:
company = await fd.get_company("DEB1103R_HRB123456")
print(company["display_name"])
asyncio.run(main())
Errors
Every failure is a typed exception carrying the API's RFC 7807 problem detail,
including a request_id you can quote to support.
from firmendata import FirmenData, InsufficientCreditsError, RateLimitError
try:
fd.get_ubo(eu_id)
except InsufficientCreditsError:
... # top up or upgrade
except RateLimitError as e:
... # e.retry_after is the server's own hint
| Exception | Status | Meaning |
|---|---|---|
AuthenticationError |
401 | Missing/invalid key, or a keyless call used a paid feature |
TokenExpiredError |
401 | Key expired |
InsufficientCreditsError |
402 | Balance too low for this call |
NotFoundError |
404 | No such company, subscription or event |
ConflictError |
409 | Conflicts with existing state |
ValidationError |
422 | Bad parameters — see .errors for the fields |
RateLimitError |
429 | Retry budget exhausted — see .retry_after |
ServerError |
5xx | Retried automatically for idempotent calls |
APIConnectionError / APITimeoutError |
— | No response at all |
Retries
Automatic and deliberately conservative:
- 429 is always retried, on any method — the server rejects rate-limited
calls before the handler runs, so nothing happened and nothing was billed.
The server's
Retry-Afteris used verbatim. - 5xx and connection failures are retried only for idempotent methods. A
create_subscriptionthat times out may already have been applied; replaying it would create a second one. - Backoff is exponential with full jitter, so clients that trip the same limit together don't all return at the same instant.
Tune with FirmenData(max_retries=...); 0 disables it.
Types
Responses are plain dictionaries described by generated TypedDicts, so editors
complete every field and mypy checks them — with no pydantic dependency to
collide with your own. The only runtime requirement is httpx.
Both src/firmendata/types.py and src/firmendata/params.py are generated from
contracts/openapi.v1.json, a vendored copy of the
published spec:
python scripts/generate_types.py
CI regenerates them and fails if the result differs from what is committed, so the SDK cannot silently drift from the API it targets.
Development
pip install -e '.[dev]'
pytest # no network, no credentials
mypy && ruff check
Links
- API reference — https://api.firmendata.com/v1/docs
- TypeScript SDK — https://github.com/FirmenData/firmendata-node
- n8n node — https://github.com/FirmenData/n8n-nodes-firmendata
- MCP server (for AI agents) —
https://mcp.firmendata.com/mcp - Website — https://firmendata.com
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file firmendata-0.1.0.tar.gz.
File metadata
- Download URL: firmendata-0.1.0.tar.gz
- Upload date:
- Size: 82.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
726b8a0fbe4e9d0b6b06b4625ab471c824c81e702d9fb0dc2c006f332084a4de
|
|
| MD5 |
ebc8d77cbea66d79bb4e00dee88983b2
|
|
| BLAKE2b-256 |
7145db7d9f960309b401e65b1f75a33922e9f9d20ccce6f66fe333d1dbb3be70
|
Provenance
The following attestation bundles were made for firmendata-0.1.0.tar.gz:
Publisher:
publish.yml on FirmenData/firmendata-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
firmendata-0.1.0.tar.gz -
Subject digest:
726b8a0fbe4e9d0b6b06b4625ab471c824c81e702d9fb0dc2c006f332084a4de - Sigstore transparency entry: 2522687938
- Sigstore integration time:
-
Permalink:
FirmenData/firmendata-python@f276cacc4cbac96e1809574902973bc6da31bc1a -
Branch / Tag:
refs/tags/0.1.0 - Owner: https://github.com/FirmenData
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f276cacc4cbac96e1809574902973bc6da31bc1a -
Trigger Event:
push
-
Statement type:
File details
Details for the file firmendata-0.1.0-py3-none-any.whl.
File metadata
- Download URL: firmendata-0.1.0-py3-none-any.whl
- Upload date:
- Size: 25.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f26d47db165024e94a2118b971eb71738a2c170444c0406e5b6f0060c820f3d9
|
|
| MD5 |
adeb47b78b461f0ecfa5c452acbcc154
|
|
| BLAKE2b-256 |
9e77277fab389b75a177a8548b3bcccca8e73418c965016a8bb1b6002811fd49
|
Provenance
The following attestation bundles were made for firmendata-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on FirmenData/firmendata-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
firmendata-0.1.0-py3-none-any.whl -
Subject digest:
f26d47db165024e94a2118b971eb71738a2c170444c0406e5b6f0060c820f3d9 - Sigstore transparency entry: 2522688032
- Sigstore integration time:
-
Permalink:
FirmenData/firmendata-python@f276cacc4cbac96e1809574902973bc6da31bc1a -
Branch / Tag:
refs/tags/0.1.0 - Owner: https://github.com/FirmenData
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f276cacc4cbac96e1809574902973bc6da31bc1a -
Trigger Event:
push
-
Statement type: