registercheckby openlaw group
Understand the data

Filtering

Building a segment with a structured query rather than a search term.

POST /search/companies/filter answers a structured question — "GmbHs in Bavaria, founded since 2025, with a managing director over 60" — rather than a text query. It costs 1 credit per 10 returned results, nothing when none is found, and a page holds up to 1,000 companies.

Shape

{
  "company": { "…": "criteria on the register entry itself" },
  "financials": { "…": "criteria on the most recent statement" },
  "roles": { "conditions": [] },
  "shareholders": { "conditions": [] },
  "limit": 20
}

Four groups, and at least one is required — an empty filter is a 400, not the whole register. Everything you give must hold: the groups combine with AND, and so do the fields inside company and financials.

Criteria on the company

{
  "company": {
    "status": ["active"],
    "legal_form": ["gmbh", "gmbh_co_kg"],
    "city": { "equals": "Berlin" },
    "founding_date": { "gte": "2025-01-01" },
    "capital": { "gte": 25000, "lte": 100000 }
  },
  "limit": 20
}

Three kinds of value, and which one a field takes is fixed:

KindLooks likeUsed by
A set["gmbh", "ug"] — any of thesestatus, legal_form, register_court, register_type, industry
Text{"equals": …}, {"contains": …} or {"starts_with": …}, exactly onename, city, state, purpose
Range{"gte": …}, {"lte": …}, or bothfounding_date, capital

near is its own thing: {"latitude": 48.13, "longitude": 11.58, "radius_meters": 5000}.

Criteria on roles and shareholders

These take conditions, because a company has many of each and it matters whether one role holder satisfies the whole condition or three holders satisfy a third of it each. A role is an office in the company: who acts for it.

{
  "roles": {
    "conditions": [
      { "last_name": { "contains": "Müller" }, "status": "current" }
    ]
  },
  "limit": 20
}

Every field inside one condition must match the same role. The example finds companies where someone named Müller holds an office now, not companies with a Müller and, separately, someone current.

  • name matches the name of a company that holds a role, or a person's first, last or full name ("Hans Müller"); first_name and last_name match one of a person's names alone. All three match a substring (contains).
  • role_type can only be ["authorized_signatory"] (Prokuristen) for now: the register data records no role type for the other roles, so any other value is answered 400.
  • age is whole years as of today in Europe/Berlin, from 0 to 120. A company matches when the role holder's age is inside the bounds (gte and lte, one or both, inclusive). An age on its own answers 400: combine it with a narrowing criterion, for example a name, a register, a location or another company filter. A role's, a shareholder's or the company's status does not count: it leaves almost every row in the scan. A shareholder's holder_type does not count either: it only picks person or company holders. A shareholder criterion, such as a person_id, does count for a role's age. The same rule covers a Kommanditist's age or birth_date (type: ["limited_partner"] only picks that table). A fraction, a value outside 0–120, or gte greater than lte also answers 400. Plain shareholders have no date of birth, so age there answers 400.
{
  "company": { "city": { "equals": "München" } },
  "roles": { "conditions": [{ "age": { "gte": 60, "lte": 69 } }] }
}

match says how several conditions combine (all, the default, or any), and min_matching / max_matching count how many role holders must meet a condition. The data store cannot combine conditions yet, so a criterion with more than one condition, or with a matching bound, is answered 400: send one condition.

shareholders works the same way, with type, holder_type (person or company), percentage, held_since, tenure_years and status (current or former). Filtering type: ["limited_partner"] selects Kommanditisten.

When a filter cannot be expressed

Some questions have no honest translation, and those return 400 with a problem document saying so rather than a result that quietly means something else:

  • status: ["unknown"]. active, liquidation and terminated are selected on the status each company's record publishes, alone or together, so an active segment never contains a company in liquidation and total_count is the size of the segment. unknown is what a company says when the register data gives no status at all, and it cannot be asked for as a segment.
  • legal_form: ["foreign_entity"]. Foreign forms are written 1,281 different ways in the register, so there is no set of spellings to match on.

A filter that silently widened would be worse than one that refuses: you would build a segment on it and never know.

Paging

limit and cursor in the body page the result set: send each page's next_cursor back as cursor — see Pagination. Each call costs 1 credit per 10 results it returns; your balance must hold the price of the limit you ask for before the call.

On this page