Enrich customer data
Add company data to your customer list.
You have a list of company names, cities or register numbers and want to add official company data to it. All you need is fetch-organization; you don't need to search first.
Match companies
Send one request per customer with the best detail you have. Register court and register number are best, because they are unique. If you don't have them, use the company name with legal form and city. Our example request looks up Hetzner Online GmbH, Ansbach HRB 6089, by name and city.
curl -G "https://handelsregister.ai/api/v1/fetch-organization" \ -H "x-api-key: YOUR_API_KEY" \ --data-urlencode 'q=Hetzner Online GmbH Gunzenhausen'
import requests response = requests.get( "https://handelsregister.ai/api/v1/fetch-organization", headers={"x-api-key": "YOUR_API_KEY"}, params={ "q": "Hetzner Online GmbH Gunzenhausen", }, ) data = response.json()
const url = new URL("https://handelsregister.ai/api/v1/fetch-organization"); url.searchParams.append("q", "Hetzner Online GmbH Gunzenhausen"); const response = await fetch(url, { headers: { "x-api-key": "YOUR_API_KEY" }, }); const data = await response.json();
1{2 "entity_id": "94eb910fef13f94585c48c263fa446d4",3 "name": "Hetzner Online GmbH",4 "status": "ACTIVE",5 "registration": {6 "court": "Ansbach",7 "register_type": "HRB",8 "register_number": "6089"9 },10 "address": {11 "house_number": "25",12 "street": "Industriestraße",13 "postal_code": "91710",14 "city": "Gunzenhausen",15 "county": "Weißenburg-Gunzenhausen",16 "state": "Bayern",17 "country": "DEU",18 "coordinates": {19 "latitude": 49.12483,20 "longitude": 10.7805221 }22 },23 "meta": {24 "request_credit_cost": 5,25 "credits_remaining": 14526 }27}
Check the response against your data, for example the postal code or city in address. With common names, a company with the same name could come back otherwise.
Store the entity_id with your customer. All later fetches, documents, Signals and monitors then run on this identifier.
ai_search=on-default) selectively for fuzzy entries; it costs an extra 20 credits, even without a match.
Fetch many companies
fetch-organization allows 60 requests per minute. Send the requests evenly, one after another. On HTTP 429, wait the seconds from Retry-After. If you need more, Enterprise offers higher limits, see Pricing.
Give each request an Idempotency-Key, for example the customer number. If you repeat it with the same key and the same parameters within 24 hours, it costs nothing.
On HTTP 408 (the request took too long), the API charges nothing, not even AI Mode. On an error with status 500 or higher, only AI Mode is charged, if you chose it. Try again later with the same Idempotency-Key.
The script reads customers.csv with the columns id, name, city and register. The column register holds the register number with its court, such as Ansbach HRB 6089, or nothing. The script writes a copy with entity_id, register court and register number and counts the credits used.
import csv import time import requests API = "https://handelsregister.ai/api/v1/fetch-organization" HEADERS = {"x-api-key": "YOUR_API_KEY", "Accept": "application/json"} PER_MINUTE = 60 # limit of fetch-organization def lookup(row): # Register court plus register number is unique; otherwise name and city q = row["register"] or f'{row["name"]} {row["city"]}' headers = {**HEADERS, "Idempotency-Key": f'customer-{row["id"]}'} for attempt in range(5): response = requests.get(API, params={"q": q}, headers=headers, timeout=120) if response.status_code == 429: time.sleep(int(response.headers.get("Retry-After", "10"))) elif response.status_code in (408, 500, 502, 503, 504): time.sleep(30 * (attempt + 1)) else: break return response spent = 0 with open("customers.csv", newline="") as source, open("customers_enriched.csv", "w", newline="") as target: reader = csv.DictReader(source) writer = csv.DictWriter(target, fieldnames=reader.fieldnames + ["entity_id", "register_court", "register_number"]) writer.writeheader() for row in reader: response = lookup(row) if response.status_code == 402: print("Not enough credits, run stopped") break data = response.json() spent += data.get("meta", {}).get("request_credit_cost", 0) if response.status_code == 200: registration = data.get("registration") or {} row["entity_id"] = data["entity_id"] row["register_court"] = registration.get("court") row["register_number"] = f'{registration.get("register_type")} {registration.get("register_number")}' writer.writerow(row) time.sleep(60 / PER_MINUTE) print(f"Used: {spent} credits")
A second run within 24 hours costs nothing. The response then carries Idempotency-Status: replayed and request_credit_cost 0.
1{2 "entity_id": "94eb910fef13f94585c48c263fa446d4",3 "name": "Hetzner Online GmbH",4 "meta": {5 "request_credit_cost": 0,6 "credits_remaining": 1457 }8}
enrich, a ready-made enrichment for CSV, JSON and Excel files.
Keep an eye on costs
Estimate in advance with the price list: 5 credits per company for the basic data, plus the price of each feature. The basic data costs with every match. Features without data cost nothing, so the actual costs are often lower. The surcharges are not features: AI Mode costs even without a match, Realtime with every successful fetch.
| What | Credits |
|---|---|
| Company profile with the basic data | 5 |
| Each feature, only when it returns data | 1 to 80 |
| AI Mode, even without a match | +20 |
| Realtime, for every successful live fetch | +10 |
Limit: 60 requests per minute.
What a request actually cost is in every response under meta.request_credit_cost.
What a request cost is in meta.request_credit_cost, the remaining balance in meta.credits_remaining. Add up the costs as you go, as in the script above.
Before each request, the API checks whether your balance covers the highest possible price. If it doesn't, the API responds with HTTP 402 and charges nothing. The script then stops.
You can check your balance and usage at any time for free through account.
Common pitfalls
- Register number without court: If your data only says “HRB 6089”, the API finds no company. Add the register court or use name and city.
- One key, one request: The same
Idempotency-Keywith different parameters returns HTTP 422. For a changed request, use a new key. - Key format: Up to 128 characters from letters, digits and
. _ : -are allowed, starting with a letter or digit. The API ignores a key in any other format. The request then runs without this protection. - Timeout: With Realtime or many features, a request takes longer. Set your client's timeout to at least 120 seconds.