EU Company ID Resolver – VAT, KVK, KBO & LEI avatar

EU Company ID Resolver – VAT, KVK, KBO & LEI

Pricing

from $40.00 / 1,000 entity resolveds

Go to Apify Store
EU Company ID Resolver – VAT, KVK, KBO & LEI

EU Company ID Resolver – VAT, KVK, KBO & LEI

EU company ID resolver: turn a VAT number, KvK, KBO, SIREN, SIRET, LEI or company name into all the other identifiers plus official name, legal form and status, each with source and confidence, from VIES, GLEIF, KBO, SIRENE and the Peppol Directory. Not found comes with a reason, never a guess.

Pricing

from $40.00 / 1,000 entity resolveds

Rating

0.0

(0)

Developer

Leyten Data

Leyten Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

10 hours ago

Last modified

Share

What does EU Company ID Resolver do?

EU company ID resolver: give it one identifier of a company, get all the others back. A VAT number, a Dutch KvK number, a Belgian KBO number, a French SIREN or SIRET, an LEI, or a company name with a country in; the VAT number, the national register number, the LEI, the official name, legal form and status out, each field with the register it came from and a confidence score. Under the hood it combines VIES, GLEIF, the Belgian KBO public search, the French SIRENE register and the Peppol Directory, and it never guesses: what cannot be derived comes back as not found with the reason.

Why every EU customer file needs this

Your ERP has VAT numbers, your credit insurer wants KvK or KBO numbers, your bank asks for an LEI, your e-invoicing provider needs a Peppol participant ID, and the sanctions screening tool wants the registered name exactly as the register spells it. Every system keys the same company differently, and nobody publishes the crosswalk. Today that gap is closed by hand, or by a KYB subscription priced for compliance departments. This Actor is the crosswalk, per company, for a few cents, with every link explained.

FromToHowConfidence
Belgian VAT numberKBO number (and back)The KBO number is the VAT number without the prefix0.60 until confirmed (VIES for either number; the KBO page for the KBO number, and for the VAT number when its qualities list the enterprise as liable to VAT and VIES has not reported that number as not valid), then 1.00 verified
French VAT number, SIRETSIREN (and back)The SIREN is inside the VAT number and the SIRET; the key is computed0.60 until confirmed (VIES for either number, SIRENE for the SIREN), then 1.00 verified; 0.98 for the VAT number SIRENE lists when it contains the SIREN
SIRENSIRET, name, legal form, statusSIRENE (recherche-entreprises.api.gouv.fr)1.00
KBOname, legal form, status, seatKBO public search page1.00
VAT numbername, address, validityVIES; member states that withhold names (Germany, Spain) are reported as such1.00
KvK / KBO / SIRENLEI, legal form, statusGLEIF registeredAs (the register number recorded with the LEI)the LEI 1.00 verified (legal form 0.97 verified, status 0.95) when that number is one the company has for sure: the input, a number its register confirmed, or the number inside an input VAT number or SIRET; otherwise at most 0.97 and no more than the number it was found by (0.90 for a KvK number from a Peppol card)
LEIKvK / KBO / SIRENthe same GLEIF field, read the other way0.97 (a SIRET 0.95); a KBO number rises to 1.00 verified when the KBO page confirms it, a SIREN when SIRENE does; a KvK number stays at 0.97
registered name (from VIES, the KBO, SIRENE or a Peppol card)LEI, legal form, statusGLEIF records of that name in the same country, at least 90% similar (or Minimum name similarity when higher); two records that match about equally well link neither0.95 × similarity, with the match in via; the LEI 1.00 verified only when its record lists a number the company has for sure, as in the first GLEIF row
KvK / KBO / SIREN / VATthe other numbersthe entity's Peppol business card, published by the company for e-invoicing0.90; raised to 1.00 verified when the register for the number confirms it (VIES for a VAT number, the KBO page for a KBO number, SIRENE for a SIREN), and a Belgian VAT number also when the KBO page lists the enterprise as liable to VAT and VIES has not reported that number as not valid; a KvK number stays at 0.90
name + countryeverything aboveGLEIF (LEI holders), Peppol Directory, and for France SIRENE; the best clear match above Minimum name similarity is taken, near-ties are reported as ambiguous≤ 0.95 × similarity for what the match gives, raised as above when a register confirms it (the match stays in via); the overall confidence stays ≤ 0.95 × similarity whatever the registers confirm, and ≤ 0.75 for one-word names or when GLEIF, the Peppol Directory or SIRENE did not answer

Facts are resolved in rounds until nothing new appears, so a KvK number can lead to a Peppol card, the card to a VAT number, VIES to the registered name, and the name to an LEI. A number that follows by arithmetic is never swapped for a different one from a Peppol card or a GLEIF record, whichever source answers first (also for a name, where the VAT number comes from the match): the contradiction is reported in warnings, a VAT number or SIRET that does not fit the other number of the pair is not taken either, and a GLEIF record that lists another register number than the company's is not linked at all. The KBO page or SIRENE record of the contradicting number is never looked up.

Honest about coverage

  • Netherlands. The KvK does not offer a free lookup API, and Dutch VAT numbers have been assigned independently of the KvK number since 2020. A KvK number is therefore found only when the company has an LEI (GLEIF records it) or a Peppol business card that lists it; a VAT number for a KvK number only through Peppol. When neither exists the record says so, with that reason, instead of a number that might belong to someone else.
  • Belgium. Complete: the KBO number, the VAT number and the KBO public page are one chain; the LEI where one exists.
  • France. Complete: SIREN, SIRET, VAT and the SIRENE record are one chain; the LEI where one exists.
  • Other member states. VAT validity and, where the member state discloses it, the registered name from VIES; the LEI and the register number GLEIF holds when the company has an LEI; Peppol identifiers where the company is registered. No national register is consulted, and the record's notFound says which link is missing and why.
  • LEIs exist only for a minority of companies (they are mandatory for financial-market participants). lei: not found is the normal case for a bakery.

Features

  • Company identifier resolution across VIES, GLEIF, KBO, SIRENE and the Peppol Directory in one call
  • VAT number to KvK, KBO, SIREN, SIRET and LEI, and every direction back
  • Company name to VAT number, register number and LEI, with similarity score, alternatives and an explicit ambiguity flag
  • Official name, legal form (with ELF code) and status from the register that is authoritative for it
  • Source, confidence and verification per field, so every value in your master data has a provenance
  • Explicit notFound with a reason for every identifier that applies but could not be established; never a guess
  • Natural persons protected: identifiers delivered, names and addresses withheld; directors and contacts never read
  • Charged per resolved entity only; unrecognised inputs, dead ends, ambiguous names and numbers only derived by arithmetic are free
  • Runs through the Apify API, on a schedule, or from Make, Zapier and n8n

Use cases

Master data teams: one key for every system

Run the VAT numbers from your ERP through the resolver and store kvk, kbo, siren, lei and the registered legalName next to them, with source and confidence as audit fields. Re-run quarterly; status: inactive and vatValid: false are the rows to look at.

// npm install apify-client
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('lwsdjfls/eu-company-id-resolver').call({ identifiers: customers.map((c) => c.vatNumber) });
const { items } = await client.dataset(run.defaultDatasetId).listItems({ clean: true });
for (const { payload } of items) {
if (!payload.resolved) continue;
await updateCustomer(payload.input, {
legalName: payload.entity.legalName?.value ?? null,
kvk: payload.identifiers.kvk?.value ?? null,
lei: payload.identifiers.lei?.value ?? null,
status: payload.entity.status?.value ?? 'unknown',
confidence: payload.confidence,
missing: payload.notFound.map((n) => `${n.identifier}: ${n.reason}`),
});
}

Onboarding and KYB pre-checks

A new customer gives you a KvK or KBO number: get the registered name, legal form, status and VAT number in one call before the account is created, and hand the lei to the bank when it asks.

E-invoicing teams

Find the Peppol participant IDs a company is registered under from any of its numbers (peppolParticipants), and the reverse: a Peppol ID's company numbers.

How to use it

  1. Put whatever identifiers you already hold into Identifiers: a VAT number, a KvK or KBO number, a SIREN or SIRET, an LEI, or simply a company name. Mixing kinds in one run is fine, and a prefix such as KvK 24330087 removes any ambiguity. Set Default country when you pass bare names.
  2. Press Start and read one record. Every input produces exactly one record, including the ones that resolved nothing, and each field carries the source that confirmed it together with a confidence. Nothing in the output is inferred silently.
  3. Run it over a customer or supplier file to fill the gaps in your CRM or ERP. The resolution view is the filled-in row per company; the notFound view lists what could not be resolved and why, which is the part you can actually act on.

A register that does not answer is reported as unavailable and never as "not found", so a bad afternoon at VIES cannot quietly empty a column in your master data. Where a number can be derived arithmetically, such as a Belgian VAT number from a KBO number, it is only delivered once a register confirms it.

Two boundaries are worth knowing before you plan around this. Dutch KvK numbers can only be reached through GLEIF or the Peppol Directory, because the KvK API is paid and scraping their site breaks their terms, so Dutch coverage is real but not complete. And no personal data is delivered: company records only, never directors and never contact persons, which also means a sole trader gives you the business fields and nothing about the person behind it.

curl "https://api.apify.com/v2/acts/lwsdjfls~eu-company-id-resolver/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"identifiers":["NL810433941B01","BE0403170701","Danone; FR"],"defaultCountry":"NL"}'

Input

FieldWhat it doesExample
identifiersOne per line: a VAT number, a prefixed register number (KvK 24330087, KBO 0403.170.701, SIREN 552032534, SIRET 55203253400703, LEI 72450020ONP2TGFMWS03) or a company name with country (Coolblue; NL). Bare numbers use the default country.["NL810433941B01", "KvK 24330087", "Danone; FR"]
defaultCountryCountry for bare numbers and names without a country suffix.NL
minNameSimilarityHow similar a registered name must be to a name you gave, or to link an LEI to an entity found by number (100 = identical).85
maxConcurrencyInputs resolved at the same time; every register keeps its own rate limit regardless.4
maxWaitMinutesHow long a member state's VIES service may keep failing before its VAT numbers are reported as unavailable (never as invalid).3
proxyConfigurationNot needed normally; only when VIES answers IP_BLOCKED.{ "useApifyProxy": false }
{
"identifiers": ["NL810433941B01", "KvK 24330087", "BE0403170701", "SIREN 552032534", "LEI 72450020ONP2TGFMWS03", "Danone; FR"],
"defaultCountry": "NL",
"minNameSimilarity": 85
}

Prefixes are understood in the usual spellings (KvK, KBO, BCE, ondernemingsnummer, SIREN, SIRET, LEI, VAT, BTW, TVA). A bare number is read with the default country; a bare name needs ; NL-style country or the default country.

Output

One record per input:

identifiers.vat NL810433941B01 source input confidence 1.00 verified (VIES: valid)
identifiers.kvk 24330087 source gleif confidence 0.95 via GLEIF registeredAs at Handelsregister (KvK) (name match with GLEIF (100%))
identifiers.lei 72450020ONP2TGFMWS03 source gleif confidence 0.95 via name match with GLEIF (100%)
entity.legalName COOLBLUE B.V. source vies confidence 1.00 verified
entity.legalForm 54M6 · besloten vennootschap met beperkte aansprakelijkheid source gleif confidence 0.95
entity.status active source gleif
notFound (none)
  • identifiers: vat (with vatValid from VIES), kvk, kbo, siren, siret, lei, peppolParticipants
  • entity: legalName, legalForm (code and label), status (active, inactive, unknown) with statusDetail, registered address, and naturalPerson
  • every fact carries source (vies, gleif, kbo, sirene, peppol, derived or input), via (what it was derived or matched from), confidence (0–1) and verified (confirmed by the register that is authoritative for it)
  • notFound[]: each identifier that applies to the entity's country but could not be established, with the reason
  • alternatives[] (at most five, each at least 70% similar) and ambiguous for names that match more than one entity, sourcesConsulted, unavailable (registers that did not answer), warnings, outcome in one sentence, and an overall confidence (the weakest link, including numbers only derived by arithmetic; for a name input at most 0.95 × the similarity of the match)

A Dutch VAT number: VIES confirms it and gives the registered name; GLEIF's LEI record for that name supplies the LEI, the KvK number and the legal form. They are linked by name, so they carry 0.95 × the similarity of the name (100% here); no free register can confirm a KvK number that would tie them to the company for sure.

{
"envelopeVersion": 1,
"id": "vat:NL:nl810433941b01",
"scope": "vat:NL:nl810433941b01",
"changeType": "added",
"sourceUrl": "https://search.gleif.org/#/record/72450020ONP2TGFMWS03",
"scrapedAt": "2026-09-15T23:11:34.340Z",
"firstSeenAt": "2026-09-15T23:11:34.340Z",
"hash": "18afba6481b1e07cf84d071f4c555c16f50bc69d306663808a2ed40cfcfd9806",
"previousHash": null,
"changes": [],
"summary": "Added: NL810433941B01: COOLBLUE B.V. (NL810433941B01, KvK 24330087, LEI 72450020ONP2TGFMWS03)",
"diffText": null,
"payload": {
"input": "NL810433941B01",
"inputType": "vat",
"country": "NL",
"resolved": true,
"outcome": "KVK via gleif (GLEIF registeredAs at Handelsregister (Kamer van Koophandel) (name match with GLEIF (100%))); LEI via gleif (name match with GLEIF (100%)); name from VIES",
"entity": {
"legalName": {
"value": "COOLBLUE B.V.",
"source": "vies",
"via": null,
"confidence": 1,
"verified": true
},
"naturalPerson": false,
"legalForm": {
"value": {
"code": "54M6",
"label": "besloten vennootschap met beperkte aansprakelijkheid"
},
"source": "gleif",
"via": "name match with GLEIF (100%)",
"confidence": 0.95,
"verified": false
},
"status": {
"value": "active",
"source": "gleif",
"via": "name match with GLEIF (100%)",
"confidence": 0.95,
"verified": false
},
"statusDetail": "GLEIF entity status ACTIVE, registration ISSUED",
"address": {
"value": {
"lines": [
"WEENA 00664",
"3012CN ROTTERDAM"
],
"city": null,
"postalCode": null,
"country": "NL"
},
"source": "vies",
"via": null,
"confidence": 1,
"verified": true
}
},
"identifiers": {
"vat": {
"value": "NL810433941B01",
"source": "input",
"via": null,
"confidence": 1,
"verified": true
},
"vatValid": {
"value": true,
"source": "vies",
"via": null,
"confidence": 1,
"verified": true
},
"kvk": {
"value": "24330087",
"source": "gleif",
"via": "GLEIF registeredAs at Handelsregister (Kamer van Koophandel) (name match with GLEIF (100%))",
"confidence": 0.95,
"verified": false
},
"kbo": null,
"siren": null,
"siret": null,
"lei": {
"value": "72450020ONP2TGFMWS03",
"source": "gleif",
"via": "name match with GLEIF (100%)",
"confidence": 0.95,
"verified": false
},
"peppolParticipants": [
"0106:24330087",
"9944:nl810433941b01"
]
},
"notFound": [],
"alternatives": [],
"ambiguous": false,
"sourcesConsulted": [
"GLEIF",
"Peppol Directory",
"VIES"
],
"unavailable": [],
"warnings": [],
"confidence": 0.95,
"checkedAt": "2026-09-15T23:11:34.340Z"
}
}

Pricing

EventNameWhat it meansPrice
apify-actor-startActor startCharged by Apify when a run starts: once for a run of up to 1 GB of memory, and once more for every extra GB. It covers the first five seconds of compute.$0.00005 per run up to 1 GB of memory ($0.05 per 1,000)
entity-resolved (primary)Entity resolvedOne input (VAT, KvK, KBO, SIREN/SIRET, LEI or name + country) resolved to at least one further identifier or entity fact (official name, legal form, status), each with its source and confidence, across VIES, GLEIF, the Belgian KBO, the French SIRENE register and the Peppol Directory. Not charged when nothing beyond the input could be established, or when the only extra number is one derived arithmetically from the input that no register confirmed.$0.04 per resolved entity ($40.00 per 1,000)

A customer file of 1,000 companies costs at most $40; inputs that resolve to nothing new (an unknown KvK number, a name nobody has registered), ambiguous names and unrecognised inputs are free. A Belgian or French number whose derived counterpart (VAT number, KBO number, SIREN) no register confirmed counts as nothing new too: arithmetic on your input is not a lookup, so a run during an outage of every register costs nothing. Each resolution consults two to six sources.

FAQ

Why is kvk not found for a Dutch VAT number that clearly belongs to a real company?

Because no free public register maps the two. The KvK API is paid, and the VAT number is not printed in it anyway. The resolver links them only through GLEIF (companies with an LEI) or a Peppol business card. The reason is in notFound, and no number is invented.

The name matched something, but is it the right company?

alternatives lists up to five entities that came close (at least 70% similar, whatever minimum you set) with their similarity, and ambiguous says when two matched equally well. Registers can confirm the numbers of the company the name matched, and those fields then show 1.00 verified with the match in via; that proves the numbers belong to that company, not that it is the one you meant. The overall confidence therefore stays at most 0.95 × the similarity of the match (0.79 for an 83% match), and one-word names are capped at 0.75 with a warning. The same holds for an LEI found through the registered name of a company you gave by number: it keeps 0.95 × the similarity and the match in via, unless its GLEIF record lists a number the company has for sure. An ambiguous name is free: it carries only those candidates, not a resolved entity, so pick one and resolve it by number. When it matters, resolve by number instead of by name.

Does it give the same answer as a KYB provider?

For the identifiers, the sources are the same primary registers KYB providers read (VIES, GLEIF, KBO, SIRENE). What it does not do is beneficial-owner checks, credit scores or document retrieval.

Why is there no name for a sole trader, and is EU company ID resolution GDPR-compliant?

Sole traders (eenmanszaken, entreprises individuelles, natural persons in the KBO) are natural persons, so their data falls under the GDPR. The resolver delivers their identifiers and legal form but withholds the name and address when a register classifies the entity as a natural person, and also when the only name available comes from VIES or a Peppol card without any legal form in it and no register confirms a legal person. Directors, representatives and contact persons are never read from any source: the KBO page's "Functies" block, GLEIF's relationship data and SIRENE's dirigeants are skipped by design. French companies that opted out of publication keep their name withheld. Results exist only in your own run's dataset; the Actor keeps no state between runs.

What are the limitations?

  • VIES member-state outages delay or block the VAT check; the VAT number is then reported as unavailable, never as invalid, and the other sources still answer.
  • GLEIF covers LEI holders only; KBO and SIRENE cover Belgium and France; the Netherlands has no free register API.
  • The Peppol Directory rate-limits aggressively; large runs are paced at one lookup per two seconds for that source.
  • Names are matched on the registered legal name; trade names are not searched except where Peppol cards carry them.
  • The Actor reads the public interfaces of VIES (European Commission), GLEIF, the FPS Economy's KBO public search, INSEE/DINUM's recherche-entreprises and the Peppol Directory, and is affiliated with none of them.

Support

A register with a free public lookup that should be added (Denmark's CVR, Norway's Brønnøysund, Finland's YTJ)? Open an issue on the Actor page.