Handelsregister Python SDK
A modern Python client for the Handelsregister.ai API. Structured, reliable, and fast access to the German commercial register (Handelsregister): company master data, financials, management, shareholders, UBOs, person profiles, and official PDF documents.
Features
- Company lookup —
fetch-organizationwith configurable feature flags - Person profiles —
fetch-person(Handelsregister roles + web data) - Search — query or filters-only search with geo, registry, size, and financial filters
- Signals — cursor-paginated company changes with topic, company, and date filters
- Monitoring & webhooks — per-company monitors with signed webhook push, endpoint lifecycle, and receiver-side signature verification
- Account — profile, credits, usage, subscription, and API-key management
- Financial data — KPIs, balance sheet, P&L, full annual reports (MD/HTML)
- Management — current and past related persons with roles
- Shareholders, UBOs, shareholdings — who owns the company, who the company owns
- Mergers & acquisitions — transactions, succession, enterprise agreements, and control relationships
- Representation schemes — current and historical company- and person-role representation rules
- News, publications, insolvency publications
- Website content — structured Markdown, optimized for LLMs
- Document downloads — Gesellschafterliste, Gesellschaftsvertrag, AD/CD PDFs, and SI XML
- Auth —
x-api-keyheader or Bearer token, plus token management - Batch enrichment — resilient CSV/JSON/XLSX enrichment with snapshots
- Live mode — opt-in realtime lookups against the Handelsregister
Installation
pip install handelsregister
Authentication
You can authenticate in two ways:
API key (recommended for server-to-server):
export HANDELSREGISTER_API_KEY=your_api_key_here
from handelsregister import Handelsregister
client = Handelsregister(api_key="your_api_key_here")
Bearer token (fine-grained control, expiration):
export HANDELSREGISTER_BEARER_TOKEN=your_token_here
client = Handelsregister(bearer_token="your_token_here")
When both are provided, the bearer token wins.
For gateways or proxies that require additional request headers, provide them explicitly. Managed authentication and User-Agent headers cannot be overridden:
import os
from handelsregister import Handelsregister
client = Handelsregister(
api_key="your_api_key_here",
extra_headers={
"X-Gateway-Client-Id": os.environ["GATEWAY_CLIENT_ID"],
"X-Gateway-Client-Secret": os.environ["GATEWAY_CLIENT_SECRET"],
},
)
Additional headers can also come from the environment:
export HANDELSREGISTER_EXTRA_HEADERS='{"X-Gateway-Client-Id": "...", "X-Gateway-Client-Secret": "..."}'
Explicit extra_headers always win over this variable.
Quick Start
Company lookup
from handelsregister import Handelsregister
client = Handelsregister()
result = client.fetch_organization(
q="KONUX GmbH München",
features=["related_persons", "financial_kpi", "shareholders"],
ai_search="on-default", # optional: enable AI search
# realtime_mode="handelsregister-default", # +10 credits for live data
)
print(result["name"], result["registration"]["register_number"])
Object-oriented Company interface
from handelsregister import Company
company = Company(
"OroraTech GmbH München",
features=[
"related_persons",
"financial_kpi",
"balance_sheet_accounts",
"shareholders",
"ubos",
"shareholdings",
"mergers_and_acquisitions",
"annual_financial_statements",
"news",
],
)
print(company.name, company.is_active)
print(company.formatted_address)
# Management
for person in company.current_related_persons:
print(person["name"], "-", person["role"]["en"]["long"])
# Shareholders (who owns the company)
for entry in company.shareholders.entries:
print(entry.display_name, entry.percentage)
# Ultimate beneficial owners
for ubo in company.ubos.resolved:
print(ubo.name, ubo.percentage)
# Outbound shareholdings (what the company owns)
for holding in company.shareholdings.current:
print(holding.organization_name, holding.percentage)
# Company- and person-level representation rules
for rule in company.representation_scheme.active:
print(rule)
for director in company.related_person_entries.current:
print(director.display_name, director.role_representation_scheme.active)
# M&A transactions
for transaction in company.mergers_and_acquisitions.transactions:
print(transaction.date, transaction.headline_text("en"))
# News
for article in company.news:
print(article["publication_date"], article["title"])
Person profiles
The /v1/fetch-person endpoint merges Handelsregister records with public web data. ai_search is always on for this endpoint (the 15-credit base cost includes the AI enrichment). organization_q is required to disambiguate common names.
from handelsregister import Person
person = Person(
person_q="Max Mustermann",
organization_q="Beispielwerk Analytics GmbH",
features=["shareholdings"], # +5 credits, only if data is returned
)
print(person.canonical_name, "-", person.home_city)
print(person.bio)
for role in person.handelsregister_roles:
print(role["name"], role["label"], role.get("start_date"), role.get("end_date"))
for holding in person.shareholdings.current:
print(holding.organization_name, holding.percentage, holding.as_of)
Search
from handelsregister import Handelsregister, RangeFilter, SearchFilters
client = Handelsregister()
page = client.search_organizations(
limit=10,
skip=0,
filters=SearchFilters(
city="München",
legal_form_code=["GmbH", "AG"],
active=True,
pl_revenue=RangeFilter(gte=1_000_000, lte=5_000_000),
),
ai_mode="on-default", # optional; makes the search cost 5 credits
)
print(page["total"])
for item in page["results"]:
print(item["name"], item["registration"]["register_number"])
The API returns at most 30 organizations per request. Passing limit=31
or higher raises ValueError instead of silently returning a truncated page.
Use skip for manual pagination, or let the lazy iterator fetch successive
pages:
organizations = list(
client.iter_search_organizations(
q="tech",
page_size=30,
max_results=100,
)
)
For 100 available matches this makes four requests with page sizes
30, 30, 30, and 10. Each page is a separate billable API request;
stopping iteration early prevents subsequent pages from being fetched.
q may be omitted when at least one filter is supplied. filters may also be
an ordinary dictionary. Supported keys cover registration dates, legal forms,
WZ/NACE industries, active status, postal code/city/state, radius search,
register court/type/number, company size, employee ranges, seven balance-sheet
ranges, and revenue/net-income/EBIT ranges. Range dictionaries use
{"gte": minimum, "lte": maximum}; either bound may be omitted.
The SDK automatically translates these documented flat financial keys to the
live API's nested financial_filters wire format.
Signals
Signals expose company changes through seven stable topic codes. Catalog requests are free; successful list and detail requests cost 20 credits. Pages contain 20 signals and use opaque cursor pagination.
Signals endpoints
| HTTP endpoint | Python method | Successful request cost |
|---|---|---|
GET /api/v1/signals |
list_signals() |
20 credits per page |
GET /api/v1/signals |
iter_signals() |
20 credits per fetched page |
GET /api/v1/signals/catalog |
get_signal_catalog() |
Free |
GET /api/v1/signals/{signal_id} |
get_signal() |
20 credits |
list_signals() accepts these arguments:
| Python argument | Description |
|---|---|
cursor |
Opaque pagination.next_cursor value returned by the previous page |
topics |
One topic, a comma-separated string, or an iterable of SignalTopic/string values |
organization_ids |
One entity ID or an iterable of entity IDs |
from_date |
Inclusive publication-date lower bound as an ISO 8601 string, date, or datetime |
to_date |
Inclusive publication-date upper bound as an ISO 8601 string, date, or datetime |
iter_signals() accepts the same filters and adds max_results. It requests
the next page only when iteration reaches it.
from handelsregister import Handelsregister, SignalTopic
client = Handelsregister()
page = client.list_signals(
topics=[
SignalTopic.CAPITAL_CHANGES,
SignalTopic.TRANSFORMATIONS,
],
organization_ids=[
"0123456789abcdef0123456789abcdef",
"fedcba9876543210fedcba9876543210",
],
from_date="2026-07-01",
to_date="2026-07-30",
)
for signal in page["signals"]:
print(signal["event"]["id"], signal["event"]["topic"])
catalog = client.get_signal_catalog()
if page["signals"]:
detail = client.get_signal(page["signals"][0]["event"]["id"])
print(detail["signal"]["event"]["topic"])
For manual cursor navigation, send the cursor unchanged and preserve the filters used for the first page:
filters = {
"topics": [SignalTopic.NEW_REGISTRATIONS],
"from_date": "2026-07-01",
"to_date": "2026-07-30",
}
first_page = client.list_signals(**filters)
next_cursor = first_page["pagination"].get("next_cursor")
if next_cursor:
second_page = client.list_signals(cursor=next_cursor, **filters)
Multiple organization_ids use OR semantics: a returned Signal may belong to
any supplied entity ID. The SDK sends the IDs as one comma-separated query
value and preserves them while following cursors.
The lazy iterator handles this automatically. Every fetched page is a separate billable request:
for signal in client.iter_signals(
topics=[SignalTopic.NEW_REGISTRATIONS],
max_results=50,
):
print(signal["organization"]["current_profile"]["name"])
Signal topics
The public topics are available as both SignalTopic and SIGNAL_TOPICS.
| Code | Data covered | Plan requirement |
|---|---|---|
NEW_REGISTRATIONS |
Newly registered organizations | No additional topic gate |
MASTER_DATA_CHANGES |
Name, registered seat, address, or register changes | No additional topic gate |
CLOSURES |
Dissolution, liquidation, deletion, or expiration | No additional topic gate |
ROLE_HOLDER_CHANGES |
Management, board, and procuration changes | No additional topic gate |
CAPITAL_CHANGES |
Share, nominal, liable, or authorized capital changes | No additional topic gate |
INSOLVENCIES |
Openings, protective measures, and completed proceedings | Pro |
TRANSFORMATIONS |
Mergers, divisions, conversions, asset transfers, enterprise agreements, and squeeze-outs | Max |
Requests below the required plan return HTTP 403 with
PLAN_REQUIRED and cost zero credits. The SDK maps this response to
SubscriptionRequiredError.
Signal response data
Each list entry contains:
event: stable ID, topic, localized topic name, occurrence/publication dates, and date basis.ROLE_HOLDER_CHANGESevents additionally carry atype(ROLE_HOLDER_ENTRYorROLE_HOLDER_EXIT) with a localizedtype_name.organization: entity ID and the current organization profile.parties: topic-specific participants - forROLE_HOLDER_CHANGESarole_holderwith the person/organization entity plus its rolecodeandrepresentation_scheme.register_entry: entry number/date, phase, description, context, and flags.source: source kind.details: topic-specific structured data identified bydetails.schema.
Fields without a value are omitted rather than returned as null. A list
response also includes pagination, applied filters, warnings, and meta.
The pagination object reports the fixed limit, returned count, has_more, and
the next opaque cursor. There is no total count.
get_signal() returns the event inside a signal envelope:
detail = client.get_signal("0123456789abcdef0123456789abcdef")
signal = detail["signal"]
request_cost = detail["meta"]["request_credit_cost"]
The catalog response contains the public topics and their descriptions,
whether data has been observed for each topic, catalog_version, and server
capabilities.
Monitoring & Webhooks
Monitoring watches companies you select and pushes new normalized commercial-register changes to your HTTPS endpoints through signed webhooks. It shares the topic vocabulary with Signals but is an independent product; each webhook links to the Signals detail API for on-demand deep data.
Reads are free. Monitor mutations work with an API key or a Bearer token
carrying account:read plus monitoring:manage. Endpoint creation, secret
rotation, enable/disable, and archive additionally require a Bearer token
with account:read plus account:keys.
Setting up a receiver
from handelsregister import Handelsregister
client = Handelsregister(bearer_token="YOUR_ADMIN_TOKEN")
# 1. Register the endpoint; store the one-time whsec_ secret immediately.
created = client.create_webhook_endpoint(
name="Production receiver",
url="https://hooks.example.com/handelsregister",
headers={"x-tenant": "customer-42"}, # optional, write-only
)
endpoint_id = created["endpoint"]["id"]
signing_secret = created["signing_secret"] # shown exactly once
# 2. Your receiver must echo data.challenge in a `webhook-verification`
# header with any 2xx status; then trigger the challenge. A successful
# first verification activates the endpoint immediately.
result = client.verify_webhook_endpoint(endpoint_id) # {"verified": true/false}
# 3. Optionally send a signed test event. enable_webhook_endpoint() is only
# needed to reactivate an endpoint after a disable.
client.test_webhook_endpoint(endpoint_id)
Creating a monitor
# Pricing is informational and useful for estimating the cycle cost.
pricing = client.get_monitoring_pricing(poll_interval_days=7)
created = client.create_monitor(
entity_id="cc78cf0b230aeae35c6df7ba31989bb9",
poll_interval_days=7,
endpoint_ids=[endpoint_id],
label="BMW AG",
)
monitor = created["monitor"] # status: "initializing", baseline queued, 0 credits
detail = client.get_monitor(monitor["id"])
detail["billing_cycle"] # active cycle summary, or None
detail["recent_runs"] # newest 20 poll runs
client.update_monitor(monitor["id"], 14) # prospective interval change
client.pause_monitor(monitor["id"])
client.resume_monitor(monitor["id"])
client.archive_monitor(monitor["id"]) # archive, never hard-delete
The free all-topic baseline runs asynchronously and suppresses historical
observations. It can complete within seconds, at which point activation
charges a 10-credit cycle floor covering five complete successful checks in
a rolling 30-day cycle; each further complete successful check costs
2 credits (max(10, 2 * checks)). Failed, partial, superseded, or unfunded
checks add no run charge, and pausing or archiving never refunds the floor —
archive while still initializing to stop a monitor before activation.
Every account receives the five core topics; INSOLVENCIES needs Pro or
Max and TRANSFORMATIONS needs Max. Inaccessible observations are
terminally suppressed, not replayed after an upgrade.
Verifying deliveries in your receiver
Delivery is at-least-once with no ordering guarantee, so verify the exact raw request bytes and deduplicate on the message id:
from handelsregister.webhooks import construct_event, verification_response_headers
# e.g. in a Flask/FastAPI handler
event = construct_event(raw_body_bytes, request_headers, signing_secret)
if event["type"] == "endpoint.verification":
return Response(status=204, headers=verification_response_headers(event))
if event["type"] == "organization.signal.detected":
signal = event["data"]["signal"]
link = event["data"]["links"]["signal"] # Signals detail API (20 credits on success)
construct_event() checks the v1,<base64> HMAC-SHA256 signature over
webhook-id.webhook-timestamp.raw_body, accepts the current and predecessor
secret during the seven-day rotation grace (pass a list of secrets), and
enforces a configurable timestamp tolerance. Samples always set
data.sample=true; detected events never do. Respond with any 2xx quickly;
3xx/4xx/5xx and timeouts are retried for roughly three days across ten
attempts, HTTP 410 disables the endpoint immediately, and five consecutive
exhausted deliveries disable it too.
Idempotency
Every mutation requires an Idempotency-Key. The SDK generates a compliant
key automatically and reuses it across its internal retries, so transient
errors never double-charge or double-create. Pass idempotency_key= to make
retries across process restarts safe as well: an exact retry within 24 hours
replays the original response — including the same resource id — with
client.last_idempotency_status set to "replayed" instead of
"created". Reusing a key with different parameters raises
IdempotencyConflictError. Requests rejected by validation (HTTP 400/422)
never claim their key, so the same key can be retried after fixing the
request. Never re-drive an ambiguous 409 on a verify/test operation with a
fresh key, because the API cannot prove whether your receiver saw the
ambiguous request.
Delivery history
client.list_webhook_endpoints() # all non-archived endpoints (max 10)
client.list_webhook_deliveries(endpoint_id) # newest 50 delivery summaries
client.retry_webhook_delivery("del_...") # re-drive a retained failed delivery
client.list_webhook_events() # newest 50 event summaries
client.rotate_webhook_endpoint_secret(endpoint_id) # new one-time whsec_ secret
client.disable_webhook_endpoint(endpoint_id)
client.archive_webhook_endpoint(endpoint_id)
Event payloads are retained encrypted for 30 days, delivery attempt audit rows for 90 days.
Account and Usage
Account endpoints are read-only except for API-key creation and revocation. Every Account request costs zero credits.
Account endpoints
| HTTP endpoint | Python method | Authentication |
|---|---|---|
GET /api/v1/account |
get_account() |
API key or account:read Bearer token |
GET /api/v1/account/credits |
get_account_credits() |
API key or account:read Bearer token |
GET /api/v1/account/usage |
get_account_usage() |
API key or account:read Bearer token |
GET /api/v1/account/usage/transactions |
get_account_usage_transactions() |
API key or account:read Bearer token |
GET /api/v1/account/subscription |
get_account_subscription() |
API key or account:read Bearer token |
GET /api/v1/account/api-keys |
list_api_keys() |
API key or account:read Bearer token |
POST /api/v1/account/api-keys |
create_api_key() |
Bearer token with account:keys |
DELETE /api/v1/account/api-keys/{id} |
revoke_api_key() |
Bearer token with account:keys |
from handelsregister import Handelsregister
client = Handelsregister()
profile = client.get_account()
credits = client.get_account_credits()
subscription = client.get_account_subscription()
keys = client.list_api_keys() # masked values only
usage = client.get_account_usage(
from_date="2026-07-01",
to_date="2026-07-30",
group_by="day",
)
transactions = client.get_account_usage_transactions(
endpoint="/api/v1/signals",
per_page=25,
)
get_account_usage() and get_account_usage_transactions() accept:
| Python argument | Applies to | Description |
|---|---|---|
from_date / to_date |
Both | ISO 8601 string, date, or datetime; defaults to the current month; maximum range is 366 days |
group_by |
Usage | "day" or "month"; the server chooses a default based on range length |
endpoint |
Transactions | Exact endpoint filter, for example /api/v1/signals |
per_page |
Transactions | Page size from 1 to 100; default is 25 |
cursor |
Transactions | Opaque cursor returned in pagination.next_cursor |
A date-only to_date includes that entire day. Transactions can also be
consumed across all cursor pages:
for transaction in client.iter_account_usage_transactions(per_page=100):
print(transaction["endpoint"], transaction["credits"])
Account responses provide:
- Profile data: name, email, language, and current plan.
- Credits: remaining balance, bookings, and the next expiration date.
- Usage: selected period, request/credit totals, endpoint breakdown, and daily or monthly time-series buckets.
- Transactions: individual billed requests plus cursor pagination.
- Subscription: plan, status, billing period, and included features.
- API keys: active keys in masked form, creation time, and last usage time.
Creating or revoking an API key requires a Bearer token with the
account:keys ability. The full key is returned only by the creation response:
import os
from handelsregister import Handelsregister
admin = Handelsregister(
bearer_token=os.environ["HANDELSREGISTER_ADMIN_BEARER_TOKEN"],
)
created = admin.create_api_key()
try:
new_key = created["api_key"]["key"]
finally:
admin.revoke_api_key(created["api_key"]["id"])
End-to-end Account and Signals demo
The repository includes a runnable script that pretty-prints the live responses while redacting credentials:
# Account reads are free. Signals catalog + list + detail cost up to 40 credits.
python examples/account_signals_demo.py
# Account only (free)
python examples/account_signals_demo.py --account
# Signals only, without the 20-credit detail call
python examples/account_signals_demo.py --signals --skip-detail
For a temporary API-key create/verify/revoke round trip, set
HANDELSREGISTER_ADMIN_BEARER_TOKEN and run:
python examples/account_signals_demo.py \
--account \
--admin-key-roundtrip
Document Downloads
from handelsregister import Handelsregister, Company
client = Handelsregister()
# Get the company's entity_id
result = client.fetch_organization(q="KONUX GmbH München")
entity_id = result["entity_id"]
# Download documents directly from the client
client.fetch_document(
company_id=entity_id,
document_type="shareholders_list", # Gesellschafterliste
output_file="konux_shareholders.pdf",
)
client.fetch_document(
company_id=entity_id,
document_type="articles_of_association", # Gesellschaftsvertrag / Satzung
output_file="konux_articles.pdf",
)
client.fetch_document(
company_id=entity_id,
document_type="AD", # Aktueller Ausdruck
output_file="konux_current.pdf",
)
pdf_bytes = client.fetch_document(
company_id=entity_id,
document_type="CD", # Chronologischer Ausdruck
)
xml_bytes = client.fetch_document(
company_id=entity_id,
document_type="SI", # Structured information (XML)
output_file="konux_structured.xml",
)
# Or via the Company helper
company = Company("OroraTech GmbH München")
company.fetch_document(
document_type="shareholders_list",
output_file="ororatech_shareholders.pdf",
)
Available document types
| Document Type | Description |
|---|---|
shareholders_list |
Gesellschafterliste |
articles_of_association |
Gesellschaftsvertrag / Satzung / Statut |
AD |
Aktuelle Daten (current excerpt) |
CD |
Chronologische Daten (historical excerpt) |
SI |
Strukturierter Inhalt (XML) |
Bearer Token Management
If you prefer managing bearer tokens over sharing an API key:
client = Handelsregister(api_key="your_api_key_here")
# Create a new token. expires_at must lie in the future; omit it for a
# non-expiring token.
created = client.create_token(
token_name="My Application",
abilities=["account:read", "monitoring:manage"],
expires_at="2027-01-01 00:00:00",
)
created["token"] # the bearer token value - shown exactly once
created["abilities"] # abilities actually granted
# List tokens; the create response has no id, so look it up here.
tokens = client.list_tokens()
token_id = next(
t["id"] for t in tokens["tokens"] if t["name"] == "My Application"
)
client.revoke_token(token_id=token_id)
# Revokes every bearer token of the account - use deliberately.
client.revoke_all_tokens()
Ability notes: passing ["*"] does not grant a wildcard - the server
replaces it with the defaults api:data and account:read. Request
additional abilities such as monitoring:manage explicitly. account:keys
cannot be self-granted through this endpoint; tokens for webhook-endpoint
administration must be created in the dashboard.
Data Enrichment
Enrich a CSV/JSON/XLSX file of companies with Handelsregister data. Intermediate snapshots let you resume long-running jobs.
from handelsregister import Handelsregister
client = Handelsregister()
client.enrich(
file_path="companies.csv",
input_type="csv",
query_properties={
"name": "company_name", # map 'company_name' column to query
"location": "city", # map 'city' column to query
},
snapshot_dir="snapshots",
params={
"features": ["related_persons", "financial_kpi", "ubos"],
"ai_search": "on-default",
},
output_file="companies_enriched.csv",
output_type="csv",
)
Each output row keeps the input columns and adds the API response under
_handelsregister_result plus a _in_file marker.
There is also a DataFrame convenience:
import pandas as pd
from handelsregister import Handelsregister
client = Handelsregister()
df = pd.read_csv("companies.csv")
enriched = client.enrich_dataframe(
df,
query_properties={"name": "company_name", "location": "city"},
params={"features": ["financial_kpi"]},
)
Command Line Interface
Installing the package exposes the handelsregister CLI. If the optional rich dependency is installed, commands render colorful tables.
# Company lookup (defaults: all standard features + AI search)
$ handelsregister fetch "KONUX GmbH München"
# Raw JSON
$ handelsregister fetch json "KONUX GmbH München"
# Opt-in to realtime mode for live register data
$ handelsregister fetch "KONUX GmbH München" --realtime-mode handelsregister-default
# Person profile
$ handelsregister person \
--person "Max Mustermann" \
--organization "Beispielwerk Analytics GmbH" \
--feature shareholdings
# Search (maximum 30 results per request)
$ handelsregister search "tech" --postal-code 80992 --limit 20
# Filters-only search (JSON or repeated key=value)
$ handelsregister search \
--filters '{"city":"München","pl_revenue":{"gte":1000000}}' \
--ai-mode on-default
# Enrich a file
$ handelsregister enrich companies.csv --input csv \
--query-properties name=company_name location=city \
--snapshot-dir snapshots \
--feature related_persons --feature financial_kpi \
--output-format csv
# Download documents
$ handelsregister document "KONUX GmbH München" \
--type shareholders_list --output konux_shareholders.pdf
$ handelsregister document "KONUX GmbH München" \
--type articles_of_association --output konux_articles.pdf
$ handelsregister document "KONUX GmbH München" \
--type SI --output konux_structured.xml
# Monitoring
$ handelsregister monitors pricing --interval 7
$ handelsregister monitors list
$ handelsregister monitors create --entity-id cc78cf0b230aeae35c6df7ba31989bb9 \
--interval 7 --endpoint wep_01hzy2q6j3g5m8v9x0abcde123 \
--label "BMW AG"
$ handelsregister monitors show mon_01hzy2q6j3g5m8v9x0abcde123
$ handelsregister monitors pause mon_01hzy2q6j3g5m8v9x0abcde123
# Webhook endpoints, deliveries, events
$ handelsregister webhooks create --name "Production receiver" \
--url https://hooks.example.com/handelsregister --header x-tenant=customer-42
$ handelsregister webhooks verify wep_01hzy2q6j3g5m8v9x0abcde123
$ handelsregister webhooks deliveries --endpoint wep_01hzy2q6j3g5m8v9x0abcde123
$ handelsregister webhooks events
Available Features (fetch-organization)
| Feature Flag | Description |
|---|---|
related_persons |
Current and past management |
financial_kpi |
Yearly revenue, net income, employees, … |
balance_sheet_accounts |
Hierarchical balance sheet data |
profit_and_loss_account |
Profit & loss statements |
annual_financial_statements |
Full annual reports as Markdown |
annual_financial_statements__html |
Full annual reports as HTML |
publications |
Official Handelsregister publications |
insolvency_publications |
Insolvency court publications |
news |
News articles about the company |
website_content |
Company website as structured Markdown (AI mode, 0 credits) |
shareholders (beta) |
Shareholders with capital contribution and ratio |
ubos (beta) |
Ultimate beneficial owners (resolved / unresolved / coverage) |
shareholdings (beta) |
Outbound shareholdings (what the company owns in others) |
mergers_and_acquisitions (beta) |
M&A transactions, succession, agreements, and control |
realtime_mode="handelsregister-default" forces a live Handelsregister lookup (+10 credits), independent of the feature flags above.
It cannot be combined with related_persons or publications.
The base response includes representation_scheme. Entries in
related_persons may include both organization_representation_scheme and
role_representation_scheme. Historical person records can expose their last
applicable rules as latest; the SDK normalizes current and latest through
the .active property.
Company properties
# Basic
company.name
company.entity_id
company.status
company.is_active
company.purpose
company.representation_scheme # RepresentationScheme
# Registration
company.registration_number
company.registration_court
company.registration_type
company.registration_date
# Contact & address
company.address
company.formatted_address
company.coordinates
company.website
company.phone_number
company.email
# Financial
company.financial_kpi
company.financial_years
company.balance_sheet_accounts
company.profit_and_loss_account
company.annual_financial_statements
company.annual_financial_statements_html
company.get_financial_kpi_for_year(2023)
company.get_balance_sheet_for_year(2023)
company.get_profit_and_loss_for_year(2023)
company.get_annual_financial_statement_for_year(2023) # Markdown
company.get_annual_financial_statement_for_year(2023, html=True)
# People & ownership
company.current_related_persons
company.past_related_persons
company.get_related_persons_by_role("MANAGING_DIRECTOR")
company.related_person_entries # typed persons + representation schemes
company.shareholders # ShareholderInfo
company.ubos # UBOInfo
company.shareholdings # ShareholdingsInfo
company.mergers_and_acquisitions # MergersAndAcquisitions
# News & publications
company.publications
company.insolvency_publications
company.news
company.website_content
Person properties
person.entity_id
person.name
person.canonical_name
person.given_name
person.family_name
person.maiden_name
person.previous_names
person.birth_date
person.home_city
person.home_location
person.bio
person.expertise
person.emails
person.phones
person.linkedin
person.github
person.other_profiles
person.handelsregister_roles
person.current_handelsregister_roles
person.get_handelsregister_roles_by_label("MANAGING_DIRECTOR")
person.affiliations
person.shareholdings # PersonShareholdings (requires feature flag)
Error handling
All API exceptions inherit from HandelsregisterError. Documented HTTP
responses are mapped to RequestValidationError (HTTP 400/422), AuthenticationError,
InsufficientCreditsError, ForbiddenError /
SubscriptionRequiredError, NotFoundError, ConflictError /
IdempotencyConflictError (HTTP 409), IdempotencyKeyRequiredError
(HTTP 428), RateLimitError, and RequestTimeoutError / ServerError /
ServiceUnavailableError (503 kill switch). Receiver-side signature
failures raise WebhookSignatureError. API exceptions preserve
status_code, the raw JSON payload, and billing metadata through .meta.
Only network failures, HTTP 408/429, and server errors are retried. When supplied,
the API's Retry-After header controls the delay. Monitoring mutations retry
with the same idempotency key; HTTP 409 is never retried, and endpoint
verify/test retry only the pre-operation 503 kill switch and HTTP 429
because other failures are ambiguous once the receiver may have been
contacted.
Security
Do not commit API keys or Bearer tokens. Load credentials from environment variables or a secret manager, and revoke any credential that may have been exposed. Report vulnerabilities privately as described in SECURITY.md.
License
GNU Affero General Public License v3.0 — 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 handelsregister-0.7.1.tar.gz.
File metadata
- Download URL: handelsregister-0.7.1.tar.gz
- Upload date:
- Size: 110.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0422d9350914900c4a327627594d61f5f495660059fcc3a10a447538533a807
|
|
| MD5 |
5846f10c76b8a7d04118cf0619045fbf
|
|
| BLAKE2b-256 |
f6d152df29f22546e77cc9358306239c7d5a4d2a0cc6389b7349fbb6377ac8b9
|
Provenance
The following attestation bundles were made for handelsregister-0.7.1.tar.gz:
Publisher:
publish.yml on Handelsregister-AI/handelsregister
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
handelsregister-0.7.1.tar.gz -
Subject digest:
f0422d9350914900c4a327627594d61f5f495660059fcc3a10a447538533a807 - Sigstore transparency entry: 2368727523
- Sigstore integration time:
-
Permalink:
Handelsregister-AI/handelsregister@fc3b0667ecbe33934f5806711d4eb30a5ac9a4e9 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/Handelsregister-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fc3b0667ecbe33934f5806711d4eb30a5ac9a4e9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file handelsregister-0.7.1-py3-none-any.whl.
File metadata
- Download URL: handelsregister-0.7.1-py3-none-any.whl
- Upload date:
- Size: 72.6 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 |
77ad9398edbd5d777428fd90cef8438139b9daffadd6f8b2d100f59c7728bbf1
|
|
| MD5 |
689c785f9a2fab4497f32504b641fada
|
|
| BLAKE2b-256 |
ccb06aba6cd56c86d7573ba303b9315c8f82e1e65aed0f42c4d4555c9563a786
|
Provenance
The following attestation bundles were made for handelsregister-0.7.1-py3-none-any.whl:
Publisher:
publish.yml on Handelsregister-AI/handelsregister
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
handelsregister-0.7.1-py3-none-any.whl -
Subject digest:
77ad9398edbd5d777428fd90cef8438139b9daffadd6f8b2d100f59c7728bbf1 - Sigstore transparency entry: 2368727788
- Sigstore integration time:
-
Permalink:
Handelsregister-AI/handelsregister@fc3b0667ecbe33934f5806711d4eb30a5ac9a4e9 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/Handelsregister-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fc3b0667ecbe33934f5806711d4eb30a5ac9a4e9 -
Trigger Event:
push
-
Statement type: