Use case · Data & RevOps
CRM Company Data Enrichment API
Your account table has three spellings of the same company and no way to know it. Resolve every account to one official registry number, then enrich it with the legal name, status, address and activity that number belongs to.
The problem
RevOps, data and CRM-admin teams inherit an account table built from imports, manual entry and whatever a sales rep typed before a demo. The same company ends up as several rows — a legal suffix here, a missing article there, a rebrand nobody updated — because nothing in the CRM enforces one identity per company. Finance carries a related version of the same problem: an invoice names a counterparty, and someone has to work out which legal entity that actually is before a credit decision or a revenue number can rely on it.
The fix is not a smarter dedupe pass over the names you already have. It is replacing the name with a key that does not vary: the country a company is registered in, plus the number that registry itself uses.
The pattern
Four endpoints, five steps.
- Resolve in bulk.
POST /companies/lookup(see the company lookup API) takes up to 100 items per call: anamefor a fuzzy match, or an exactcompany_number,nif,sirenorvatwhen you already have one. This is entity resolution — turning whatever the CRM has on file into the one identifier the registry itself issues. - Deduplicate by number, not by name. Take
countrypluscompany_numberfrom the result and use that pair as the key on every account from now on. Validate the check digit before you spend a lookup on a typo, with the free company identifier validator — Spain, France, Poland and Norway all carry a real check digit; UK and Irish numbers do not, so only their format can be checked. Country-by-country rules are in EU + UK company identifiers. - Enrich the record. The result from step 1 already carries the core registry fields inline — legal form, status, founding and dissolution dates, address, activity code and description, share capital, former names. Call
GET /companies/{id}?country=(theidfrom step 1) for the fuller profile, including embedded officers where the country publishes them. - Check the VAT number separately. If you invoice the account,
GET /vat/{vatNumber}validates it against VIES and returns the registered name and address as a second, independent source. - Keep it current.
POST /monitorsubscribes acompany_idfrom every live country except France and Chile to a webhook that fires on status changes, dissolution and sanctions matches (beta). For France, the UK and Norway, re-run the batch lookup for accounts that changed, on whatever schedule fits.
curl -X POST 'https://api.prometiam.com/functions/v1/risk-api/companies/lookup' \
-H 'Authorization: Bearer rk_live_...' \
-H 'Content-Type: application/json' \
-d '{
"items": [
{ "country": "ES", "name": "Acme Soluciones SL" },
{ "country": "FR", "siren": "552032534" },
{ "country": "GB", "company_number": "00445790" }
]
}'
# data[] is one result per item, in request order:
# { "index": 0, "status": "found", "match_score": 92,
# "company": { "company_number": "B12345678", "country": "ES", "status": "active", ... } }
# meta: { "items": 3, "found": 3, "not_found": 0 }status in data[] is the lookup outcome (found / not_found / error / timeout); company.status is the registry status (active, dissolved, in_liquidation…) — do not confuse the two when you write results back.


A real example
The script below reads a CRM export with account_name and country columns, resolves it in batches of 100, and writes back only what clears a match_score of 85 — anything lower is marked needs_review alongside its score, so a person decides instead of the script guessing on your behalf.
import csv
import requests
API_KEY = "rk_live_..." # masked — never commit a real key
BASE = "https://api.prometiam.com/functions/v1/risk-api"
MATCH_FLOOR = 85 # below this, a human reviews the match
BATCH_SIZE = 100
def chunks(rows, size):
for i in range(0, len(rows), size):
yield rows[i:i + size]
def lookup(batch):
items = [{"country": r["country"], "name": r["account_name"]} for r in batch]
resp = requests.post(f"{BASE}/companies/lookup",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"items": items}, timeout=30)
resp.raise_for_status()
return resp.json()["data"]
def enrich(accounts):
rows = []
for batch in chunks(accounts, BATCH_SIZE):
for account, result in zip(batch, lookup(batch)):
company, score = result.get("company"), result.get("match_score")
ok = result["status"] == "found" and company and (score is None or score >= MATCH_FLOOR)
rows.append({
"account_name": account["account_name"],
"country": company["country"] if ok else account["country"],
"company_number": company["company_number"] if ok else "",
"registry_status": company["status"] if ok else "needs_review",
"match_score": score if score is not None else "",
})
return rows
with open("crm_accounts.csv", newline="", encoding="utf-8") as f:
accounts = list(csv.DictReader(f)) # columns: account_name, country
enriched = enrich(accounts)
with open("crm_accounts_enriched.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=list(enriched[0].keys()))
writer.writeheader()
writer.writerows(enriched)About 40 lines end to end. Run with python -u; requests is the only dependency.
What comes back
The fields below come back on the company object embedded in POST /companies/lookup and on GET /companies/search; GET /companies/{id} returns the same fields plus embedded officers where the country publishes them.
| Field | What it is |
|---|---|
company_number (+ nif / siren) | The registry primary key — the value to store as your dedupe key, alongside country. |
company_name | Registered legal name, always uppercase. |
legal_form | e.g. S.A., SARL, Ltd — null where the registry does not publish one. |
status | Registry status in that country's own vocabulary (active, dissolved, in_liquidation, bankrupt…). Values are not a shared enum across countries. |
founding_date / dissolution_date | Incorporation date and, where it applies, the date the entity closed. |
address, postal_code, city, province | Registered address, uppercase. |
activity_code / activity_description | CNAE (ES), NAF (FR), SIC (GB/IE), PKD (PL), NACE (NO). The description is text only for ES/FR/NO. |
capital_amount / capital_currency | Share capital as last published, in the registry's own currency (EUR for ES/FR, PLN for PL, NOK for NO). |
previous_names | Former registered names — sourced for the UK and Norway; the other countries typically return none. |
last_seen_date | The most recent registry publication in which Prometiam has seen this record. |


Pricing fit
A 50,000-account CRM run through /companies/lookup in batches of 100 is 500 calls, but the plan meter counts every item: 50,000 requests and 50,000 credits. That one-off backfill is a month of the Scale tier (€99.99/month, 50,000 credits/month, 300 requests/minute), or a few months on Professional (€29.99/month, 10,000 credits/month, 120 requests/minute). After the backfill, a nightly refresh only has to touch accounts that actually changed — a few hundred a night for most books, roughly 6,000 to 10,000 credits a month — which fits Professional; a few thousand a night needs Scale.
A smaller list, or a first test against real accounts, fits inside the Free trial's 500 credits over 14 days, with a card required and nothing charged for 14 days.
Scope limits, stated plainly
- Fuzzy matching returns a best guess with a score, not a certainty. Keep anything under the threshold you choose — this page uses 85 as an example — on a review queue instead of writing it back automatically. For accounts typed in by hand, a company autocomplete field lets the user pick the registry record instead of typing a free-text name.
- No personal emails, no inferred contacts. What Prometiam returns about a company is registry data: name, status, address, activity and, where published, officers — not a lead list.
- No estimated financials, no employee counts, no credit score of any kind. Share capital is the only money field on the company record, and only where the registry itself published it. Filed annual accounts for GB, FR, DK, SE, NO and SEC filers in the United States, for Finland (statements filed digitally with PRH, about one filer in twenty, and listed groups) and for listed companies in ES, PL, HR and BE, are a separate endpoint from the Scale plan.
- Ireland is company-level today — no officers yet.
previous_namesis populated for the UK and Norway; the other countries typically return none, so a rebrand elsewhere will not surface there.- Norway has register-change events only, from 14 Oct 2026 (no gazette), so a Norwegian account can be watched for register changes from that date.
- Monitoring (
POST /monitor) covers every live country except France and Chile. Refresh France, the UK and Norway on your own schedule.
FAQ
How do I match messy CRM company names to an official registry record?
Send up to 100 account names per call to POST /companies/lookup. Each fuzzy name match returns the best candidate with a match_score from 0 to 100; an exact company_number, nif, siren or vat resolves directly with no score needed.
What should I store as the dedupe key instead of the company name?
Country plus company_number — the identifier the registry itself assigns: NIF for Spain, SIREN for France, the Companies House number for the UK, the CRO number for Ireland, KRS for Poland, the organisation number for Norway, the Y-tunnus for Finland, the organisationsnummer for Sweden, the enterprise number for Belgium, the MBS or OIB for Croatia, the CVR number for Denmark, the registry code for Estonia, the IČO for Slovakia, the UID for Switzerland, the registration number for Latvia, Cyprus and Romania, the legal entity code for Lithuania, the corporation number for Canada, the ACN or ARBN for Australia, the corporate number for Japan, the company number for Israel, the UEN for Singapore, the NIT for Colombia, the unified business number for Taiwan, the IČO for the Czech Republic, the CNPJ for Brazil, the CUIT for Argentina, the LEI for Germany, the state-prefixed number for the United States (such as NY-4424185). Validate the check digit first with the free company identifier validator.
How many CRM accounts can I resolve in one request?
Up to 100 items per POST /companies/lookup call. Each item still counts as one request against your rate limit and costs 1 credit, so 50,000 accounts is 500 batch calls but 50,000 counted requests and 50,000 credits.
Does Prometiam return emails or phone numbers for CRM contacts?
No. Prometiam returns no personal emails and no inferred contacts — what comes back is registry data about the company itself: name, status, address, activity and, where published, officers. It is not a contact-finder product.
How do I keep enriched CRM records up to date?
Subscribe companies registered in any live country except France and Chile to POST /monitor for a webhook on status changes, dissolution and sanctions matches (beta); Mexico covers its LEI-registered entities only and Argentina has no dissolution alert. For France and Chile, re-run the batch lookup for changed accounts on a schedule — nightly is typical.
Related
- Company identifier validator — check digits before you spend a lookup, free and client-side
- EU + UK company identifiers — the identifier reference table by country
- SIREN vs SIRET vs NIF — which French or Spanish identifier to store
- VAT validation against VIES
- New incorporations feed — the same registries, pointed at finding accounts instead of cleaning them
- Batch screening — screen the same account list against sanctions in bulk
- HitHorizons alternative
- API documentation