Getting Started
End-to-end guide for retrieving German company data
This guide walks through a complete German company retrieval workflow—from searching for a company to setting up ongoing monitoring.
Getting an API Key
To use the Kausate API, you'll need an API key. There are two ways to get one:
- Self-serve signup: Create an account at kausate.com/signup and generate an API key from your dashboard
- Get in touch: Contact us for enterprise plans or custom requirements
Once you have your API key, include it in all requests using the X-API-Key header.
Data Flow Overview
A typical integration follows this pattern:
| Step | Endpoint | Use Case |
|---|---|---|
| Search | POST /v2/companies/search/ | Find companies by name |
| Prefill | POST /v2/companies/{id}/prefill | Fast form prefill (~200ms) |
| Report | POST /v2/companies/{id}/report | Full real-time company data |
| Monitor | POST /v2/monitors | Track changes over time |
Complete Example: German Company Retrieval
Search for a Company
Find the company using live search. This fetches real-time results directly from the official registry.
curl -X POST https://api.kausate.com/v2/companies/search/ \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"companyName": "Bundesanzeiger Verlag",
"jurisdictionCode": "de"
}'Response:
{
"orderId": "de-live-search-bundesanzeiger-verlag-20250115103000",
"status": "completed",
"requestTime": "2025-01-15T10:30:00Z",
"responseTime": "2025-01-15T10:30:02Z",
"result": {
"type": "liveSearch",
"searchResults": [
{
"kausateId": "co_de_7KGHtucR88u2omSx3KhaoH",
"name": "Bundesanzeiger Verlag GmbH",
"jurisdictionCode": "de",
"identifiers": [
{
"type": "de_registernumber_weak",
"value": "HRB 31248",
"description": "Amtsgericht Köln"
},
{
"type": "de_registernumber_full",
"value": "R2201_HRB 31248"
}
],
"addresses": [
{
"type": "registered",
"streetAddress": "Amsterdamer Str. 192",
"postalCode": "50735",
"city": "Köln"
}
]
}
]
}
}Save the kausateId for subsequent calls.
Quick Data with Prefill
For onboarding flows where speed matters, use the prefill endpoint. It returns indexed data with a real-time fallback, typically in under 200ms.
curl -X POST https://api.kausate.com/v2/companies/co_de_7KGHtucR88u2omSx3KhaoH/prefill \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{"customerReference": "onboarding-123"}'Response:
{
"orderId": "ord_abc123",
"status": "completed",
"requestTime": "2025-01-15T10:30:00Z",
"responseTime": "2025-01-15T10:30:00.180Z",
"result": {
"basicInformation": {
"legalName": "Bundesanzeiger Verlag GmbH",
"legalForm": "GmbH",
"registrationDate": "1998-12-22",
"addresses": [...],
"identifiers": [...]
}
}
}Prefill is optimized for speed. For comprehensive data including legal representatives and shareholders, use the report endpoint.
Full Company Report (Real-Time)
For complete company data fetched directly from the Handelsregister, use the report endpoint.
Synchronous mode (sync=true) is not recommended. Government business
registries are inherently unreliable—timeouts and temporary unavailability are
common. Use the asynchronous approach with webhooks (recommended) or polling
using the orderId to receive results reliably.
Asynchronous request (recommended) — returns immediately with orderId:
curl -X POST https://api.kausate.com/v2/companies/co_de_7KGHtucR88u2omSx3KhaoH/report \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{"customerReference": "kyc-check-456"}'The async request returns:
{
"orderId": "ord_xyz789",
"customerReference": "kyc-check-456",
"status": "running"
}Option A: Set up a webhook (recommended) to receive results automatically:
curl -X POST https://api.kausate.com/v2/webhooks \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Order Results",
"url": "https://your-server.com/webhooks/kausate",
"customHeaders": {
"Authorization": "Bearer your-webhook-secret",
"X-Team": "compliance"
}
}'Custom headers. customHeaders is an arbitrary map of request headers
Kausate attaches to every delivery for this webhook — use it to send an
Authorization: Bearer … token your endpoint validates, or any tagging header
you route on. Up to 20 headers are allowed; a few reserved names
(Content-Type, Host, Content-Length, Transfer-Encoding, Connection,
Kausate-Version) are set by Kausate and can't be overridden. Header values
are encrypted at rest. Deliveries also come from a fixed set of static source
IPs you can allowlist — see Static source IPs in the Monitoring &
Webhooks guide.
The response includes a per-endpoint signingSecret. Follow the
webhook verification guide to authenticate the raw
payload, deduplicate retries, and configure an optional IP allowlist.
Option B: Poll for results:
curl https://api.kausate.com/v2/companies/report/runs/ord_xyz789 \
-H "X-API-Key: your_api_key"Completed response:
{
"orderId": "ord_xyz789",
"status": "completed",
"result": {
"sources": {
"registrar": "Amtsgericht Köln",
"retrievalTimestamp": "2025-01-15T10:35:00Z"
},
"basicInformation": {
"legalName": "Bundesanzeiger Verlag GmbH",
"legalForm": "GmbH",
"capital": {
"amount": 1000000,
"currency": "EUR",
"type": "share_capital"
},
"addresses": [...],
"identifiers": [...],
"businessActivities": [...]
},
"relationships": {
"legalRepresentatives": [...],
"shareholders": [...]
}
}
}Synchronous mode (not recommended)
While a sync=true parameter is available, it is not recommended for production use. Government business registries experience frequent timeouts, rate limiting, and temporary outages. Synchronous requests may fail with HTTP 408 (timeout) errors even when the data would eventually become available.
curl -X POST "https://api.kausate.com/v2/companies/co_de_7KGHtucR88u2omSx3KhaoH/report?sync=true" \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{"customerReference": "kyc-check-456"}'Set Up Monitoring
To track changes to a company over time, create a monitor. When changes are detected, you'll receive a webhook notification.
First, create a webhook:
curl -X POST https://api.kausate.com/v2/webhooks \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Company Changes",
"url": "https://your-server.com/webhooks/kausate"
}'Response:
{
"id": "wh_def456",
"name": "Company Changes",
"url": "https://your-server.com/webhooks/kausate",
"status": "ACTIVE",
"createdAt": "2025-01-15T10:40:00Z"
}Discover the sources you can monitor for this company:
Each company supports a different set of monitoring sources depending on its jurisdiction and the registry capabilities available. Pick from the response when creating the monitor.
curl https://api.kausate.com/v2/monitors/sources?kausateId=co_de_7KGHtucR88u2omSx3KhaoH \
-H "X-API-Key: your_api_key"Then, create a monitor:
curl -X POST https://api.kausate.com/v2/monitors \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"kausateId": "co_de_7KGHtucR88u2omSx3KhaoH",
"sources": [
"company_report",
"shareholder_graph",
"de_insolvenzbekanntmachungen.feed"
],
"scheduleCron": "0 8 * * *",
"webhookUrl": "https://your-server.com/webhooks/kausate"
}'Response:
{
"monitorId": "mon_ghi789",
"kausateId": "co_de_7KGHtucR88u2omSx3KhaoH",
"companyName": "Bundesanzeiger Verlag GmbH",
"sources": [
"company_report",
"shareholder_graph",
"de_insolvenzbekanntmachungen.feed"
],
"categoriesFilter": ["all"],
"autoDeactivateCategories": ["disappeared"],
"scheduleCron": "0 8 * * *",
"webhookUrl": "https://your-server.com/webhooks/kausate",
"isActive": true,
"createdAt": "2025-01-15T10:45:00Z"
}Per-company sources (company_report, shareholder_graph) run on the
schedule you set; global feed sources (e.g.
de_insolvenzbekanntmachungen.feed) are continuously monitored — the cron
field is ignored for those. When a change is detected your webhook URL
receives a monitor.change_detected payload tagged with a generic
event_code like INSOLVENCY_OPENED or COMPANY_STATUS_CHANGED. See
the monitoring guide for the full event taxonomy and
filter options.
Choosing the Right Endpoint
| Need | Endpoint | Speed | Data Freshness |
|---|---|---|---|
| Form autocomplete | /v2/companies/search/autocomplete | ~50ms | Indexed |
| Find companies | /v2/companies/search/ | 2-5s | Real-time |
| Prefill forms | /v2/companies/{id}/prefill | ~200ms | Indexed + fallback |
| Full company data | /v2/companies/{id}/report | 2-30s | Real-time |
| Ownership structure | /v2/companies/{id}/shareholder-graph | 5-60s | Real-time |
Handling Errors
Every error response has the same body: a human-readable detail, a stable
dotted code to branch on, and a request_id to quote to support.
{
"detail": "Company not found in Transparenzregister",
"code": "company.not_found.transparenzregister",
"request_id": "req_01J8Z5V4Q2X9N7B3C6D1E0F2G4"
}Branch on code, never on detail — the wording of detail is not part of
the contract. Codes are hierarchical and published at full depth, so match a
prefix to handle a whole family at once:
if (error.code.startsWith("company.not_found")) {
showCompanyNotFound();
}The statuses you can receive:
| Status | Meaning | Retry? |
|---|---|---|
| 200 | Success | — |
| 400 | Invalid request (check parameters and body), or a capability that jurisdiction doesn't offer | No |
| 401 | No API key was supplied | No, send X-API-Key |
| 403 | The API key is invalid, or valid but not entitled to this resource | No |
| 404 | Company, document or order not found — including "no data available" | No |
| 405 | Wrong HTTP method for that path | No |
| 408 | Upstream registry timed out (sync mode only) | Yes, or go async |
| 409 | The resource's state rejects this request | No |
| 410 | The referenced state has expired | No, start a new order |
| 422 | Well-formed but unprocessable (validation, or data that can't be served) | No |
| 429 | An upstream registry rate-limited us — honour Retry-After | Yes, after Retry-After |
| 500 | Unexpected failure on our side | Yes, with backoff |
| 501 | Offered for that jurisdiction, but this path isn't implemented (rare) | No |
| 502 | Transient upstream-registry failure | Yes, shortly |
| 503 | Upstream registry degraded or unreachable | Yes, longer backoff |
Credit exhaustion is a 403 carrying billing.credit_limit_exceeded. There is
no 402. A capability a jurisdiction doesn't offer is a 400 (a 403 while
it's coming soon) — see the Errors guide.
For async operations the HTTP response is a 200 and the failure lives in the
payload — check the status field, which is one of six values:
running— Still processingcompleted— Result available inresultfieldfailed— The order ran and failedcanceled— The order was canceledterminated— The order was forcefully stoppedtimedOut— The order exceeded its time limit
The last four are terminal failures and all carry error (display text) and
code (what you branch on), so handle them together rather than switching on
failed alone. On this surface code is versioned: it is present from
2026-05-01 onward and absent for a client pinned to 2025-04-01. The sync
error body above is not versioned and always carries code.
See the Errors guide for the full code vocabulary and the prefix-matching contract.
Why timeouts happen
Kausate fetches data directly from official government registries (Handelsregister, Companies House, etc.). These external systems are inherently unreliable:
- Rate limiting — Registries limit requests to prevent abuse
- Maintenance windows — Government systems have scheduled and unscheduled downtime
- Slow responses — Some queries take 30+ seconds depending on registry load
- Temporary outages — Network issues and server errors are common
This is why we recommend asynchronous requests with webhooks (recommended) or polling using the orderId. Our retry logic handles temporary failures automatically, and you'll receive results as soon as they're available.
Last updated on