Download documents
Register extracts, shareholder lists and articles of association as files.
fetch-document fetches a document from the Handelsregister (commercial register) and returns it as a file: as PDF, or as XML for the structured register content. All you need is the company's entity_id, see Fetch a company profile.
Choose the document type
There are five document types. You pass the type in document_type, written exactly as in the table, including upper and lower case.
| document_type | Document | Format | For |
|---|---|---|---|
| AD | Aktueller Abdruck (current printout): all entries that apply today | every registered company | |
| CD | Chronologischer Abdruck (chronological printout): all entries in chronological order | every registered company | |
| SI | Strukturierter Registerinhalt (structured register content) in the XJustiz format, machine-readable | XML | every registered company |
| shareholders_list | Gesellschafterliste (shareholder list) | GmbH and UG | |
| articles_of_association | Satzung or Gesellschaftsvertrag (articles of association) | Corporations and cooperatives |
Fetch a document
Pass the entity_id as company_id and the type as document_type. The response is the file itself, not JSON. Our example request saves the Aktueller Abdruck of Hetzner Online GmbH, Ansbach HRB 6089.
curl -G "https://handelsregister.ai/api/v1/fetch-document" \ -H "x-api-key: YOUR_API_KEY" \ --data-urlencode "company_id=94eb910fef13f94585c48c263fa446d4" \ --data-urlencode "document_type=AD" \ --fail-with-body --max-time 120 \ -o hetzner-ad.pdf
import requests response = requests.get( "https://handelsregister.ai/api/v1/fetch-document", headers={"x-api-key": "YOUR_API_KEY"}, params={ "company_id": "94eb910fef13f94585c48c263fa446d4", "document_type": "AD", }, timeout=120, ) response.raise_for_status() with open("hetzner-ad.pdf", "wb") as file: file.write(response.content) print(response.headers["X-Credits-Charged"], "credits charged")
import { writeFile } from "node:fs/promises"; const url = new URL("https://handelsregister.ai/api/v1/fetch-document"); url.searchParams.append("company_id", "94eb910fef13f94585c48c263fa446d4"); url.searchParams.append("document_type", "AD"); const response = await fetch(url, { headers: { "x-api-key": "YOUR_API_KEY" }, signal: AbortSignal.timeout(120_000), }); if (!response.ok) throw new Error(`HTTP ${response.status}`); await writeFile("hetzner-ad.pdf", Buffer.from(await response.arrayBuffer())); console.log(response.headers.get("x-credits-charged"), "credits charged");
Because the response is not JSON, the details about it are in the headers:
| Field | Meaning |
|---|---|
| Content-Type |
application/pdf, for the structured register content application/xml. |
| Content-Disposition | The file name with entity_id, type and the day the document came from the register. |
| X-Credits-Charged | What the request cost. |
| X-Credits-Remaining | Your balance afterwards. |
If the document doesn't exist for the company, you get HTTP 404 at no cost.
1{2 "error": "Document fetch failed",3 "message": "Document not available for this company. It may not exist or may become available later.",4 "meta": {5 "request_credit_cost": 0,6 "credits_remaining": 1457 }8}
Fetch in the background
If your client can't wait that long, set async=true. If the document is already available, it comes right away. Otherwise the API responds with HTTP 202 and gives the wait time in seconds in Retry-After. In the example we fetch the Chronologischer Abdruck of SAP SE, Mannheim HRB 719915.
curl -G "https://handelsregister.ai/api/v1/fetch-document" \ -H "x-api-key: YOUR_API_KEY" \ --data-urlencode 'company_id=e3918174fb6c5d04e5e217e6ee4a6ffe' \ --data-urlencode 'document_type=CD' \ --data-urlencode 'async=true'
import requests response = requests.get( "https://handelsregister.ai/api/v1/fetch-document", headers={"x-api-key": "YOUR_API_KEY"}, params={ "company_id": "e3918174fb6c5d04e5e217e6ee4a6ffe", "document_type": "CD", "async": "true", }, ) data = response.json()
const url = new URL("https://handelsregister.ai/api/v1/fetch-document"); url.searchParams.append("company_id", "e3918174fb6c5d04e5e217e6ee4a6ffe"); url.searchParams.append("document_type", "CD"); url.searchParams.append("async", "true"); const response = await fetch(url, { headers: { "x-api-key": "YOUR_API_KEY" }, }); const data = await response.json();
1{2 "status": "processing",3 "meta": {4 "message": "The document is being retrieved. Repeat this request after Retry-After seconds to receive it.",5 "retry_after": 20,6 "request_credit_cost": 0,7 "credits_remaining": 1458 }9}
Repeat the same request after this time, and the file comes with HTTP 200. Only the delivered file costs credits; the 202 response is free. If no capacity is free right now, you get HTTP 503, also with Retry-After.
Each repeat counts toward the limit. So wait the given time instead of asking again at short intervals.
Costs and limits
| What | Credits |
|---|---|
| One delivered document | 15 |
Limit: 5 requests per minute. Search, documents and Signals share a quota of 60 requests per minute.
Each delivered document costs 15 credits, whatever the type. Because each document comes from the register, fetch-document has its own, lower limit of 5 requests per minute.
With an Idempotency-Key, you pay for a document only once, even if you repeat the request after it was cut off. More under Limits.
Retry-After. The API charges nothing. Try again after a few minutes.
Common pitfalls
- Register number instead of entity_id:
company_idonly takes the 32-character entity_id.Ansbach HRB 6089returns HTTP 400. - Shareholder list for other legal forms: It only exists for GmbH and UG. For a KG or a sole trader, you get HTTP 404.
- Documents as image files: If a document is only available as TIFF in the register, the API responds with HTTP 415 and charges nothing.