KYB Company Verifier — Cross-Registry Business Verification API
Pricing
from $5.50 / 1,000 results
KYB Company Verifier — Cross-Registry Business Verification API
KYB/AML company verification API. Given a company name, fans out to France (INSEE/RNE), GLEIF LEI, and US state registries and returns, per registry: exists, normalized status, jurisdiction, identifiers (SIREN/LEI), officers, address, and a match-confidence score. Keyless.
Pricing
from $5.50 / 1,000 results
Rating
0.0
(0)
Developer
Kyle Maloney
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
11 days ago
Last modified
Categories
Share
KYB Company Verifier - Cross-Registry Business Verification API
Verify a company name against eight official, keyless company registries in one call and get, per registry: whether a record exists, the normalized legal status, jurisdiction, identifiers, formation date, registered agent, officers, and a graded name match.
This is a screening and grounding tool over public government registries. It is not a KYB, AML or compliance determination. A registry record is evidence, not a decision. Confirm identifiers against the source registry before onboarding, contracting or paying.
The rule this actor now enforces: a partial check is never presented as a complete one
Three things could previously make a partial verification look like a finished one. All were reproduced live and fixed on 2026-08-01.
- A registry that failed was skipped entirely - no row, no field, nothing. You got seven
rows instead of eight and no way to tell which registry was never checked. If every
registry failed, the run emitted zero rows and reported SUCCESS: a silent, confident
"we found nothing". Now every unreachable registry emits an explicit row with
exists: null,registry_status: "unavailable"and the error, and a run where no registry answered fails and bills nothing. - A near name was presented as a match. Registry name search is not relevance-ranked.
Live: querying GLEIF for
Siemens AGreturns ten records with zero exact matches, led by Siemens Energy AG (CH) - a different, spun-off company - at confidence 0.667. GLEIF registers the parent as Siemens Aktiengesellschaft, which is not on page one at all. WithmaxPerRegistry: 1that wrong company was the answer. Every row now carriesname_match_gradeandverification_outcome, and only an exact normalized name match is ever calledverified_exact_name_match. - A negative was over-read.
US-DEis the Delaware business licence list, not the Delaware corporate registry. Danone US, Inc. is a Delaware entity - Colorado publishesjurisdictonofformation: "DE"for it - andUS-DEreturnedexists: false. Every row now carriesregistry_scopeandregistry_false_means, spelling out what a negative on that particular registry does and does not prove.
exists is tri-state: true matched, false the registry answered and nothing matched,
null the registry was not checked. Never read null as a negative.
Three status defects fixed at the same time
| Registry | What was wrong | Now |
|---|---|---|
| US-CO | Registered Agent Resigned (663 live entities) matched the word "registered" and was reported active. | unknown, with the registry's own words in status_raw. |
| US-DE | Status was hard-coded to Licensed (so, active) while the licence expiry date was fetched and thrown away. An expired Delaware licence read as active. | Status is computed from current_license_valid_to; an expired licence is inactive. |
| US-PA | typeofbusinessregistration was mapped to status. All 18 distinct live values are entity types ("Domestic Limited Liability Company"), so every one of ~4.5M rows produced unknown from a column that never held a status. | PA publishes no status: status_basis says not_published_by_registry, and the value is surfaced in entity_type where it belongs. |
| US-NY / US-OR | Active was hard-coded. | Still active - the datasets are scoped to active registrations - but status_basis now reads implied_by_dataset_scope, not fetched. |
status_raw carries the registry's own string on every row. The normalizer collapses 15
distinct Colorado statuses and 26 Connecticut ones into four buckets, and status_raw is
what was actually published.
Who it's for
- KYB / AML onboarding and vendor-risk teams grounding a company claim in an official registry record before contracting or paying.
- Sales and RevOps enriching and de-duplicating accounts with a registry identifier.
- Fintech and marketplace compliance confirming a merchant entity exists and is in good standing in its stated jurisdiction.
- AI agents that need a chainable verification tool which can say "not checked" rather than guessing.
Registries covered
| Code | Registry | What a negative means here |
|---|---|---|
FR-INSEE | French national register (INSEE SIRENE + RNE) | No French entity matched. Says nothing about entities outside France. |
GLEIF | Global LEI register | No LEI matched. Most companies worldwide have no LEI, so this is not evidence the company does not exist. |
US-CO | Colorado SoS business entities (all statuses) | No Colorado-registered entity matched. |
US-CT | Connecticut SoS registrations (all statuses) | No Connecticut registration matched. |
US-NY | New York DOS, "Active Corporations: Beginning 1800" | No active New York corporation matched. A dissolved NY entity also returns false. |
US-OR | Oregon SoS, "Active Businesses - ALL" | No active Oregon registration matched. |
US-PA | Pennsylvania DOS, current registered businesses | No current Pennsylvania registration matched. |
US-DE | Delaware business licence list | No Delaware licence matched. Not evidence the company is not a Delaware-incorporated entity - the Delaware Division of Corporations publishes no open bulk dataset. |
Iowa was removed in July 2026: data.iowa.gov migrated off Socrata and every Iowa request returned the portal's HTML 404 page.
Example input
{ "companyName": "Danone", "maxPerRegistry": 5 }
Restrict the fan-out with country (FR or US; GLEIF is global and always included) or
with an explicit registries list. maxPerRegistry caps candidates per registry, ranked by
name-match confidence - but read name_match_grade rather than assuming the top row is the
company you meant.
{ "companyName": "Acme Holdings LLC", "registries": ["US-CO", "US-NY", "GLEIF"] }
Output fields (53)
Verification verdict
| Field | Meaning |
|---|---|
input_name | The company name you queried. |
registry | Registry code this row came from. |
verification_outcome | verified_exact_name_match, candidate_match_review_required, no_match_on_registry, or registry_unavailable_not_checked. |
outcome_reason | Plain-language explanation, including what a negative does and does not prove here. |
exists | Tri-state: true matched, false checked and no match, null not checked. |
name_match_grade | exact, strong, partial, weak, none. Only exact is a name verification. |
match_confidence | 0-1 token similarity after legal-form tokens are normalized away. null when not checked. |
matched_name | The registry's record name. |
entity_id | Registry identifier: SIREN, LEI, entity id, filing number, licence number. |
Status
| Field | Meaning |
|---|---|
status | Normalized active, inactive, dissolved, unknown. null when not checked. |
status_raw | The registry's own status string, before normalization. |
status_basis | fetched, implied_by_dataset_scope, or not_published_by_registry. |
Per-registry outcome contract (on every row)
| Field | Meaning |
|---|---|
registry_status | ok or unavailable for the registry this row came from. |
registry_error | Why it did not answer, when unavailable. |
registry_scope | What this registry actually covers. |
registry_false_means | What exists: false does and does not prove here. |
verification_complete | true only when every requested registry answered and passed its drift assertions. |
registries_requested | Every registry this run attempted. |
registries_checked | The ones that answered. The result is valid only against these. |
registries_unavailable | The ones that did not. null on a complete run. |
registry_errors | Per-registry failure detail. |
registries_expected_count, registries_checked_count | Coverage of this run. |
fr_insee_status, gleif_status, us_co_status, us_ct_status, us_ny_status, us_or_status, us_pa_status, us_de_status | ok / unavailable / not_requested per registry. |
The registry record
| Field | Meaning |
|---|---|
jurisdiction | Registry jurisdiction, e.g. US-CO, FR, GLOBAL. |
entity_type | Legal entity type as published. |
formation_date | Formation or first-registration date, YYYY-MM-DD. |
jurisdiction_of_formation | Where the entity was originally formed - often the key KYB fact. |
address | Principal or legal address. |
mailing_address | Mailing or agent address, where published separately. |
registered_agent | Registered agent or entity of record. |
officers | Directors, officers or agent name, where published. |
county | County of record (New York, Pennsylvania). |
legal_form, registration_authority, entity_category, other_names | GLEIF LEI attributes. |
trade_name, license_category, license_valid_from, license_valid_to | Delaware business-licence detail. |
activity_code, activity_section, employee_range | INSEE activity and size data for French entities. The INSEE API publishes no human-readable activity label, only the NAF code and section letter. |
source_url | Link to the registry record or search page. |
retrieved_at | ISO 8601 timestamp of the query. |
Everything in the last block except address, officers, jurisdiction, source_url and
retrieved_at was already being fetched on every run since v1.0 and thrown away.
Sparse columns, with verified populating inputs
A dead-column audit over 22 live rows from the prefill (2026-08-01) found the Delaware licence block empty, because Danone holds no Delaware business licence. Each sparse column has an input recorded here so it can be re-verified:
| Column | Input that populates it (verified live 2026-08-01) |
|---|---|
trade_name, license_category, license_valid_from, license_valid_to | {"companyName":"Verizon","registries":["US-DE"]} returns VERIZON SERVICES CORP, category GENERAL SERVICES, valid 2026-01-01 to 2026-12-31 |
registry_error, registries_unavailable, registry_errors | any run where a registry does not answer, e.g. {"companyName":"Danone","registries":["US-CO","US-XX"]} |
legal_form, registration_authority, other_names, entity_category | GLEIF rows only: {"companyName":"Danone","registries":["GLEIF"]} |
activity_code, activity_section, employee_range | FR-INSEE rows only: {"companyName":"Danone","country":"FR"} |
mailing_address | Colorado and Connecticut rows |
county | New York and Pennsylvania rows |
Live drift assertions
The dangerous failure here is not an outage. It is a registry that answers HTTP 200 with rows that were never actually filtered - arbitrary companies that read as matches. Every run asserts, before any billable row:
- the name filter was really applied: every row a Socrata registry returns must contain
the queried substring in its name column. One that does not fails that registry, which is
then reported as
unavailablerather than letting unfiltered rows through as matches. - the dataset was not replaced: at least half the expected columns must still be present. An unknown Socrata column simply comes back absent, which is indistinguishable from an empty value.
- fuzzy results are related to the query: FR-INSEE and GLEIF run their own search, so
containment cannot be asserted (querying
Danonelegitimately returnsOLIVIA DANON), but at least one returned record must share a name token with the query. - a negative control: the nonsense name
Qzxjvbmpwl Kdfhrtynugs Holdingsis queried once per run and must match nothing. This is what catches a filter that has started matching everything. - not one registry answered fails the run and bills nothing.
Use as an MCP tool
Callable by AI agents (Claude, Cursor, etc.) via mcp.apify.com. An agent can verify a
company and read back verification_outcome, name_match_grade, verification_complete and
registry_false_means, so it can distinguish "verified", "candidate", "checked and absent"
and "not checked" without guessing.
Pricing
Pay-per-result: one dataset record per registry match, per no-match verdict, or per unavailable registry. A run where no registry answered emits nothing and bills nothing beyond the fractional actor start.
FAQ
Does a false mean the company does not exist? No, and the row tells you what it does
mean. Read registry_false_means. Most companies have no LEI, and most Delaware corporations
hold no Delaware business licence.
Why does an exact-looking name come back as a candidate? Because registry name search is
not relevance-ranked. Siemens AG on GLEIF returns Siemens Energy AG first. Only a match
that is exact after legal-form normalization is graded exact.
What if a registry is down? You get a row with exists: null,
registry_status: "unavailable" and the error, and verification_complete is false on
every row of that run. Nothing is reported as "not found" that was not actually checked.
Do I need an API key? No. All eight sources are keyless public registries.
Related actors
- Sanctions Screening List Change Monitor - OFAC / BIS / State denied-party screening for the entity you just verified.
- Medicaid Exclusion Screener - federal and state healthcare exclusion screening for clinician and vendor checks.
- GLEIF Ownership Graph - parent and subsidiary structure for an entity with an LEI.