registercheckby openlaw group
Guides

Build a company report

Assembling the register entry, management, ownership and financials into one view.

A full report is four calls on top of the company record. Fire them concurrently — they do not depend on each other.

import os, requests
from concurrent.futures import ThreadPoolExecutor

BASE = "https://api.registercheck.de/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['REGISTERCHECK_API_KEY']}"

def report(company_id: str) -> dict:
    parts = {
        "company":      f"/companies/{company_id}",
        "management":   f"/companies/{company_id}/officer-contacts",
        "shareholders": f"/companies/{company_id}/shareholders",
        "history":      f"/companies/{company_id}/events",
    }

    def get(path):
        r = session.get(BASE + path, timeout=60)
        return r.json() if r.ok else None

    with ThreadPoolExecutor(max_workers=4) as pool:
        results = dict(zip(parts, pool.map(get, parts.values())))

    company = results["company"] or {}
    # Financials cost 10 credits whether or not anything is filed - check first.
    if (company.get("counts") or {}).get("financial_statements"):
        results["financials"] = get(f"/companies/{company_id}/financial-statements")

    return results

That is 40 credits, or 50 with financials.

Cost control

Check before you fetch. The company record already tells you whether there is anything to find:

Field on the company recordSkip the call when
counts.financial_statements0 — nothing has been filed
counts.documents0 — no document is on file to download
counts.current_officers0 — there is no management to list

That second row is worth taking: representation on the company record covers most of what /management/contact returns, and the record costs 10 credits against the contact endpoint's 25.

Presenting it honestly

Three things will make your report defensible, and their absence will make it wrong:

Date every claim

Show source_document_date next to shareholdings, fiscal_year next to financial figures, and last_entry_date next to the register entry. A cap table with no as-of date is a claim you cannot support when challenged.

Distinguish "no data" from "no such thing". An empty shareholders array on an AG means AGs do not file shareholder lists. The same empty array on a GmbH whose address and purpose are also null means no extract has been parsed. Render those two differently or your users will draw the wrong conclusion.

Take the status from search. The status field on the company record is currently unreliable — see Companies. Until that is fixed, read is_active from the search result you used to find the company.

Keeping it current

Do not re-run the report on a schedule. Create a monitoring subscription and rebuild only when an event says something moved.

On this page