Find a company
Turning a name your user typed into a company id you can rely on.
Almost every integration starts here: you have a string, and you need the right company. There are three ways in, and they are not interchangeable.
If you have a register number
This is the only exact route. Give the number and the court's code (D2505 is
Amtsgericht Memmingen):
curl -G "https://api.registercheck.de/v1/search/companies" \
--data-urlencode "register_number=13557" \
--data-urlencode "register_court=D2505" \
-H "Authorization: Bearer $REGISTERCHECK_API_KEY"Register numbers repeat across courts — HRB 670 exists at most of them — so a number without a court will match many unrelated companies.
If a human is typing
Use /search/suggestions. It is
built for autocomplete: one call per keystroke-ish, cheap, and ranked.
const res = await fetch(
`${BASE}/search/suggestions?name=${encodeURIComponent(term)}&limit=8`,
{ headers: { Authorization: `Bearer ${key}` } },
);
const { data } = await res.json();Each hit is a summary, and its type says whether it is a company or a person. For a company, show
register.formatted and status next to the name. Two companies in the same town with
nearly the same name are common, and the register line is how your user tells them apart.
Debounce to ~250 ms, and start at the second character: a term shorter than 2 characters
(or longer than 200) is a 400 and costs nothing. At 1 credit a call, a busy search box is
the one place this API can quietly get expensive.
If you are matching a list
Use /search/companies with as many
fields as you have. They combine, and name or register_number is required:
| Parameter | Matching |
|---|---|
name | the name or part of it, by words (see below) |
register_number, register_court (the court's code), register_type | exact |
city | exact, the city of the registered address |
status | any of the statuses given |
Unknown parameters are rejected
A parameter the endpoint does not read answers 400 validation_failed, naming it in
errors[].name, and costs nothing. ?name=Siemens®ister_court_code=D2601 (the name before
2026-10-02) is refused rather than answered with Siemens companies at every court.
How name matches
name matches by words, ignoring case, on all three searches:
- Every word must appear, in any order:
name=Enduro Reisefinds Enduro Reise GmbH and Reise Enduro UG. - The last word also matches as the start of a word:
name=Beispfinds Beispiel GmbH. - Small typos are tolerated:
name=Siemsnfinds Siemens. - A fragment from the middle of a word does not match:
name=analyticsdoes not find Dataanalytics GmbH. - When no name contains every word, names that contain fewer of them are returned instead, so check the hits rather than assuming each one carries every word.
Company search ranks active companies first, then the best match; person search and suggestions rank by match.
`q` is the old name of `name`
Until 2026-12-31 the searches still accept q and treat it exactly like name. Every
response to a request that uses it carries Deprecation (RFC 9745)
and Sunset: Thu, 31 Dec 2026 23:59:59 GMT (RFC 8594)
headers, and a Link with rel="deprecation" to this section. After that date q is removed, and a request that uses it is refused like any
unknown parameter. Sending both name and q is a 400.
Matching well
- Strip the legal form before comparing.
legal_formtells you which one the name carries. - Use the city.
namepluscityresolves most ambiguity in one call. - Expect branches. A name that matches several entries at different courts is usually one business with registered branches, not a bad match.
- Score, do not guess.
total_countof 1 is a match;total_countof 40 means you need another field.
Find a person's companies
The routes above start from a company's name or number, and /search/companies takes no
person. When you start from a person, use
POST /search/companies/filter, at 1 credit
per 10 returned results, with a condition on the company's roles.
curl -X POST "https://api.registercheck.de/v1/search/companies/filter" \
-H "Authorization: Bearer $REGISTERCHECK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"roles": {
"conditions": [{ "person_id": "per_3v3w754f3t9w79tajtdgf8pkcg" }]
},
"company": { "status": ["active"] },
"limit": 20
}'The person_id is the id of a hit from
GET /search/persons, at 1 credit a call. A
condition can also ask by name, as a substring: {"name": {"contains": "Hans Müller"}} matches a
person's first, last or full name as well as the name of a company that holds a role, and
first_name and last_name match one of a person's names. Only contains is applied to these
three (equals and starts_with answer 400), and a substring also matches longer names
(Müller finds Müllermann), so the id is the precise way when you have one.
The answer is a page of summary hits, as from /search/companies: here, the active
companies where that person holds or held a role, as a managing director, a board member, a
liquidator and the like. Page through it with cursor: send the same filter again, with cursor set to the page's
next_cursor. A cursor holds its filter: sent with a changed filter, it answers
400 validation_failed naming /cursor. These limits apply today:
- One
person_idper condition, and onerolescondition per filter. A second condition, ormin_matching/max_matchingeven with one condition, answers400: the data store does not combine conditions yet. One human who appears under two person ids takes two filters, each priced by itslimit. role_typenarrows to Prokura only. Prokura is held apart from the other roles: withoutrole_typethe condition reads a person's other roles, and"role_type": ["authorized_signatory"]reads the companies where they hold Prokura instead. Any other role type answers400: the register data records no role type for the other roles. Prokura holders are found byperson_id,statusand the date fields, not by name:name,first_nameorlast_nametogether with"role_type": ["authorized_signatory"]answers400.
If one person's roles are all you need,
GET /persons/{person_id}/roles lists them for
10 credits. Filtering has the other conditions, and
Persons explains why one human can appear under several ids.
Then store the id
{ "id": "cmp_63b6n0c6p09pnsrr6nrtd0dzsc" }Store that id. Names change, companies are renamed and re-registered, and register
numbers are reused across courts. The id is the only stable handle.