Corporate Registry Conflict Resolver
Pricing
from $24.50 / 1,000 identity assessments
Corporate Registry Conflict Resolver
Reconcile corporate registry datasets using explicit typed identifiers. Compare reported names, statuses and dates, preserve conflicts, and prepare evidence-linked CRM field review assessments.
Pricing
from $24.50 / 1,000 identity assessments
Rating
0.0
(0)
Developer
Tim Zinin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
15 hours ago
Last modified
Categories
Share
Corporate Registry Conflict Resolver — prepare safe registry-to-CRM merge proposals from typed LEI/UK identifiers, never a fuzzy name join
Feed this Actor rows from your own zinin/company-registry-enricher and zinin/new-company-detector runs, plus any scrapesage/companies-house-scraper-shaped rows, and it returns one identity assessment per exact, validated typed identifier — a checksum-verified LEI or an authorized UK Companies House number — reconciling name/status/jurisdiction/legal-form fields as either agreed evidence or a blocked overwrite requiring a human decision, so your CRM merge never silently overwrites a genuine disagreement between sources.

What you get
You give this Actor a dataset (or an inline list) of corporate-registry rows — the three structurally different shapes produced by zinin/company-registry-enricher (recordType: "registry_card", explicit lei/ukCompanyNumber fields), zinin/new-company-detector (recordType: "new_company_intelligence", a bare companyNumber typed via a uk-company: prefixed entityId), and scrapesage/companies-house-scraper (no recordType of its own, identified by its own distinctive schema fingerprint). It never looks up a registry itself, never calls a model, and never merges two records because their names merely look similar — it reads exactly the rows you supply and reports, per exact typed identifier, an identity assessment: a factual reconciliation of every contributing row's fields, with every value traceable back to its source row.
Concretely, for each typed identity observed in your batch, you receive:
identifierType/identifierValue—'lei'for a checksum-verified ISO 17442 Legal Entity Identifier (structural shape plus real ISO 7064 MOD 97-10 checksum), or'uk'for a format-validated, source-authorized UK Companies House number. A UK identity is only ever typed from one of three explicit channels (see Evidence and boundaries) — never from a barecompanyNumberfield alone.name/legalStatus/jurisdiction/legalForm/companyType/incorporationDate— six independent field-reconciliation objects, each{ status, value, candidates, omittedCandidateCount }.compatible_observationmeans every contributing row that supplied the field agreed on one value.blocked_overwritemeans rows disagreed —valueisnull, every distinct candidate is listed, and this Actor never auto-resolves the conflict to a "winning" value.absentmeans no row ever supplied it.incorporationDateInvalidObserved—truewhen a contributing row's incorporation date failed strict calendar validation; that raw string is preserved only in evidence, never used as the reconciled date.blockedFields— the field names currently inblocked_overwritestate, for quick filtering of results that need a human merge decision before anything is written to a CRM.sicCodesObserved/sicCodesOmittedCount— the union of SIC classification codes observed across all contributing rows (both plain-string and{code,description}source shapes are extracted), an aggregation, never a conflict field.bridgeCandidates/bridgeCandidatesOmittedCount— when a single contributing row carried BOTH a valid LEI and a valid, authorized UK company number, this lists the other typed identity evidenced by that same row. This is a cross-reference candidate for human review only — the two typed identities remain fully separate results and are never silently unified into one.
What this Actor deliberately does not do, so a merge-preparation convenience can never become an unsafe CRM write:
- It does not perform name-only or fuzzy identity matching of any kind. Grouping is strictly the exact, validated typed identifier — an LEI checksum or an authorized UK company number — never a similarity join across company names.
- It does not auto-resolve a
blocked_overwritefield to any "best guess" value. Every distinct candidate is preserved and listed; a human decides which value is correct, or whether both are legitimately true at different points in time. - It does not unify an LEI identity and a UK company-number identity into one record, even when the same source row evidences both.
bridgeCandidatesis a documented cross-reference, never an automatic merge. - It does not assert current legal status, solvency, ownership, or any compliance-clearance claim.
legalStatus/legalForm/companyTypeare reconciled observations from your source rows, never a live registry verdict. - It does not read or output any officer, director, or other personal-name field. Officer/appointment data present on Companies House scraper rows is never surfaced in this Actor's output — see Sources and rights.
- It does not call any network, AI model, or system clock from inside its transform step, and it does not launch
zinin/company-registry-enricher,zinin/new-company-detector, or any scraper on your behalf.

Who uses it
- RevOps and data-quality teams preparing a registry-to-CRM merge or dedup pass, who need a safe pre-flight step that flags genuine disagreements (a company's status reported both
ActiveandDissolvedby two sources) instead of silently overwriting one value with another during an automated sync. - KYB/onboarding analysts verifying a counterparty's corporate identity across
zinin/company-registry-enricher(global LEI-scoped) and UK-specific sources, who needblockedFieldsas an explicit worklist of exactly which facts require a manual decision before onboarding proceeds. - Data engineers building a company master-data pipeline who need a dependable, pure post-processing reconciliation step between two or three scrapers' raw output and a single-source-of-truth table — one that never silently collapses a real conflict into a "most recent wins" default.
- Entity-resolution teams working across LEI and UK Companies House namespaces who need
bridgeCandidatesas a documented, evidence-linked starting point for cross-referencing a global LEI-scoped identity against its UK national registration, without a system that pretends the two are automatically the same record. - Search-term note for master-data and entity-resolution teams: if your own vocabulary uses terms like "LEI checksum validation", "Companies House number format validation", "registry conflict resolution before CRM merge", or "corporate identity deduplication typed identifiers", this Actor's identity and reconciliation rules apply directly to that workflow.
How to run
- Open the Apify Console and start a new run of Corporate Registry Conflict Resolver.
- Choose a source, in order of precedence (an explicit dataset always wins over a run reference, which always wins over the inline example — a dataset/run source never merges with inline rows):
- Source Dataset (
datasetId) — point at an existing Dataset from azinin/company-registry-enricher,zinin/new-company-detector, orscrapesage/companies-house-scraperrun (or a combination, merged by you into one dataset — this Actor does not auto-concatenate multiple dataset IDs). - Source run ID (
runId) — supply a run ID instead if you have one but not its Dataset ID directly; its default Dataset is resolved automatically, using your own run's granted permissions. - Integration payload (
payload.resource) — supplied by Apify's Integrations "Actor/task run" template when you configure one chaining this Actor after an upstream registry lookup (empty otherwise — this Actor never fills it in itself); carries{{resource.defaultDatasetId}}/{{resource.id}}/{{resource.actId}}so no manual mapping is needed. - Source records (inline) — paste or edit rows directly, or leave the prefilled real public sample in place for a first test run: six real rows spanning all three known adapters (Apple Inc. with a real LEI, three real UK
new_company_intelligencecompanies, and Tesco PLC / Tesco Stores Limited from real Companies House scraper data).
- Source Dataset (
- Optionally set Max source rows (
maxInputRows, default 100, up to 1000) and Max results (maxResults, default 2, up to 1000). The platform's own Max total charge USD run option is a separate, independent stop: whichever limit is hit first ends delivery. - Run it. Delivered rows land in the run's default Dataset, one per typed identity,
lei:results beforeuk:results, then exact identifier value ascending. Each row carriessourceRowIndexesback into your original batch so you can trace any figure to its source rows. - Read
blockedFields,partial, and the summary'sresultsCapped/sourcePartialflags before treating a run's output as ready to write into your CRM without review — see Evidence and boundaries for exactly when those flags are set and why.
For a repeatable pipeline (e.g. a periodic master-data refresh), save this configuration as an Apify Task and chain it after your registry-enrichment runs via Apify's Integrations, or trigger it from your own system via the API — see Integration recipes below for both paths.
Pricing
This Actor bills on the Apify Pay-Per-Event model under a single primary event, result-found — described to buyers under the pricing noun "identity assessment." There is no start fee and no per-row charge: only a delivered, useful identity assessment is billed. Free diagnostics (invalid rows, unauthorized/untyped identifiers, source failures, insufficient evidence, budget stops, empty-batch outcomes) never request the paid event and are never charged.
| Tier | Price per identity assessment |
|---|---|
| Free | $0.0350 |
| Bronze | $0.0315 |
| Silver | $0.0280 |
| Gold | $0.0245 |
| Platinum | $0.0245 |
| Diamond | $0.0245 |
Bronze, Silver and Gold apply Apify's standard 10%/20%/30% volume discounts off the Free-tier price; Platinum and Diamond are held at the Gold rate. There is no owner-run revenue claim and no guarantee of any particular run volume in this pricing table — it states only the price actually configured on this Actor's result-found event, verified against the live Actor record at publication time.
A useful identity assessment is a real aggregate result — a reconciled, evidence-linked identity with at least one substantive registry field or SIC code observed — never a raw source row passed through unprocessed. A partial: true assessment (for example, one delivered while maxInputRows cut off part of your batch, or one carrying a genuine blocked_overwrite conflict) is still a useful aggregate and is still billed; only genuinely empty, invalid, unauthorized, or insufficient-evidence outcomes are free. See Evidence and boundaries for the exact delivery-and-charging mechanics.
Input contract
This Actor's input schema is deliberately small: a source selector plus two bounds. There are no product-specific configuration fields — identity typing and reconciliation are driven entirely by the row shape.
{"items": [{"recordType": "registry_card","schemaVersion": "1.0.0","found": true,"input": "Apple Inc.","lei": "HWUPKR0MPOU8FGXBT394","legalName": "Apple Inc.","status": "ACTIVE","jurisdiction": "US-CA","legalForm": "H1UM","ukCompanyNumber": null,"sicCodes": []},{"companyNumber": "00445790","companyName": "TESCO PLC","companyStatus": "Active","companyType": "Public limited Company","incorporatedOn": "1947-11-27","sicCodes": [{ "code": "47110", "description": "Retail sale in non-specialised stores with food, beverages or tobacco predominating" }],"accountsOverdue": false,"confirmationStatementOverdue": false}],"maxInputRows": 100,"maxResults": 2}
This example is a trimmed projection of the Actor's own real prefill: six real rows spanning all three known adapters — one registry_card row for Apple Inc. with a genuine, checksum-valid LEI; three real new_company_intelligence rows for newly registered UK companies; and two real Companies House scraper rows for Tesco PLC and Tesco Stores Limited (their officer/director arrays are read but never surfaced, see Sources and rights). Every LEI, company number, name, and status in the prefill is a real value observed from a real upstream source on 2026-09-22/23, not synthetic fixture data. maxResults defaults to 2, so a full run of this six-identity prefill delivers only the first two identities and reports the remaining four via a free max_results_reached diagnostic — raise maxResults to see the full batch reconciled in one run.
| Field | Type | Notes |
|---|---|---|
items | array, optional | Inline source rows. Ignored if datasetId or a resolvable runId/payload.resource is present. Bounded to 1000 rows / 4 MiB total / 64 KiB per row. |
datasetId | string, optional | Reads an existing Dataset with your run's own granted permissions (resourcePicker, READ). Overrides inline items. For Integrations, map {{resource.defaultDatasetId}} here. |
runId | string, optional | Reads a run's default Dataset when you have a run ID but not its Dataset ID directly. No elevated access — the run's own default Dataset is resolved and read exactly as datasetId would be. |
payload | object, optional | Absent/empty by default — this Actor never populates it itself. When you configure Apify's Integrations "Actor/task run" template, that template supplies resource.id / resource.defaultDatasetId / resource.actId. A raw webhook envelope alone does not grant private Dataset access. |
maxInputRows | integer, default 100, max 1000 | Hard cap on source rows read for this run, independent of maxResults. |
maxResults | integer, default 2, max 1000 | Hard cap on paid identity assessments delivered this run. Free diagnostics are never counted against this cap. |
Recognized row shapes and UK typing channels
| Field / channel | Which source carries it | Role in the assessment |
|---|---|---|
lei | registry_card | Identity — trusted only after ISO 17442 shape + ISO 7064 MOD 97-10 checksum validation |
ukCompanyNumber on a recordType: "registry_card" row | registry_card | UK identity channel 1 — the exact field name SPEC-authorizes on this exact adapter only |
uk-company:<number> entityId whose suffix equals the row's own companyNumber | new_company_intelligence | UK identity channel 2 — a mismatched suffix/companyNumber pair is rejected outright, never resolved to either value |
The scraper's own schema fingerprint (companyNumber + companyStatus + no recordType + officers/accountsOverdue/confirmationStatementOverdue) | scrapesage/companies-house-scraper | UK identity channel 3 — the only way this shape is trusted, since it carries no explicit recordType/entityId of its own |
legalName / companyName | either | name field |
status / companyStatus | either | legalStatus field |
jurisdiction / legalForm | registry_card only | Reconciled fields, never merged with companyType |
companyType | new_company_intelligence / scraper | Reconciled field, never merged with legalForm |
incorporatedOn | new_company_intelligence / scraper | incorporationDate — strict YYYY-MM-DD; an invalid value is preserved as evidence only |
sicCodes | registry_card (may be empty) / scraper ({code,description} objects) | Aggregated into sicCodesObserved, never a conflict field |
found / error / failureType | any | found: false (explicit no-registry-match) or a truthy error/failureType excludes the row entirely as a free diagnostic |
Any other field present on a row — matchBasis, matchConfidence, registrationStatus, officialCompanyUrl, scrapedAt, nextAccountsDueBy, lastAccountsMadeUpTo, source, and (critically) the scraper's officers array — is read as part of the row but is never surfaced in the output and never used to infer anything about the underlying company or the people named in it.
Output examples
Every row and diagnostic below is copied verbatim from real private cloud canary runs of this Actor's value-add-candidate build, never hand-written. Field order and values match the real Dataset item exactly, one example per listed evidence scenario.
Happy path — the full six-entity prefill, maxResults: 2 (default)
Real run against the complete real prefill with default maxResults: 2 — the run's summary reported "rowsProcessed": 6, "resultsCount": 6, "leiIdentitiesCount": 1, "ukIdentitiesCount": 5, "conflictCount": 0", delivering the first two identities and reporting the remaining four via a free max_results_reached diagnostic ("delivered": 2, "totalUseful": 6"). The first delivered row, a real, fully reconciled LEI identity:
{"entityId": "lei:HWUPKR0MPOU8FGXBT394","found": true,"status": "no_conflicts_observed","action": "propose_merge_candidate","confidence": "medium","sourceRowCount": 1,"sourceRowIndexesOmittedCount": 0,"identifierType": "lei","identifierValue": "HWUPKR0MPOU8FGXBT394","name": { "status": "compatible_observation", "value": "Apple Inc.", "candidates": [{ "value": "Apple Inc.", "sourceRowIndex": 0 }], "omittedCandidateCount": 0 },"legalStatus": { "status": "compatible_observation", "value": "ACTIVE", "candidates": [{ "value": "ACTIVE", "sourceRowIndex": 0 }], "omittedCandidateCount": 0 },"jurisdiction": { "status": "compatible_observation", "value": "US-CA", "candidates": [{ "value": "US-CA", "sourceRowIndex": 0 }], "omittedCandidateCount": 0 },"legalForm": { "status": "compatible_observation", "value": "H1UM", "candidates": [{ "value": "H1UM", "sourceRowIndex": 0 }], "omittedCandidateCount": 0 },"companyType": { "status": "absent", "value": null, "candidates": [], "omittedCandidateCount": 0 },"incorporationDate": { "status": "absent", "value": null, "candidates": [], "omittedCandidateCount": 0 },"incorporationDateInvalidObserved": false,"blockedFields": [],"sicCodesObserved": [],"sicCodesOmittedCount": 0,"bridgeCandidates": [],"bridgeCandidatesOmittedCount": 0,"evidence": [{ "field": "name", "value": "Apple Inc.", "rule": "compatible_observation", "sourceRowIndex": 0 },{ "field": "legalStatus", "value": "ACTIVE", "rule": "compatible_observation", "sourceRowIndex": 0 },{ "field": "jurisdiction", "value": "US-CA", "rule": "compatible_observation", "sourceRowIndex": 0 },{ "field": "legalForm", "value": "H1UM", "rule": "compatible_observation", "sourceRowIndex": 0 }],"businessPartial": false,"sourceRowIndexes": [0],"partial": false,"sourceCoverage": { "complete": true, "reason": null, "droppedOversized": 0 },"product": "corporate-registry-conflict-resolver","schemaVersion": "1.0","sourceDatasetId": null,"sourceRunId": null,"suppliedSourceRunId": null,"sourceRunIdVerified": null,"processedAt": "2026-09-23T08:04:09.069Z"}
status: "no_conflicts_observed" with confidence: "medium" reflects four genuinely agreed fields (each compatible_observation, since only one row contributed) and zero blockedFields — companyType/incorporationDate are honestly absent because this real registry_card row simply never carried them, never fabricated. action: "propose_merge_candidate" is a routing hint recommending this identity as safe to propose into a CRM merge — still a human decision, never an automatic write.
Partial path — a real maxInputRows: 1 cutoff, with a genuinely delivered result
Real run against the same six-row batch with maxInputRows: 1 (so only the batch's first row — the Apple LEI row — was actually read) and maxResults: 2. The run wrote a free partial_source diagnostic ("reason": "max_input_rows_reached") plus the one identity assessment it could reconcile from the single row it read:
{"entityId": "lei:HWUPKR0MPOU8FGXBT394","found": true,"status": "no_conflicts_observed","action": "propose_merge_candidate","confidence": "medium","sourceRowCount": 1,"sourceRowIndexesOmittedCount": 0,"identifierType": "lei","identifierValue": "HWUPKR0MPOU8FGXBT394","name": { "status": "compatible_observation", "value": "Apple Inc.", "candidates": [{ "value": "Apple Inc.", "sourceRowIndex": 0 }], "omittedCandidateCount": 0 },"legalStatus": { "status": "compatible_observation", "value": "ACTIVE", "candidates": [{ "value": "ACTIVE", "sourceRowIndex": 0 }], "omittedCandidateCount": 0 },"jurisdiction": { "status": "compatible_observation", "value": "US-CA", "candidates": [{ "value": "US-CA", "sourceRowIndex": 0 }], "omittedCandidateCount": 0 },"legalForm": { "status": "compatible_observation", "value": "H1UM", "candidates": [{ "value": "H1UM", "sourceRowIndex": 0 }], "omittedCandidateCount": 0 },"companyType": { "status": "absent", "value": null, "candidates": [], "omittedCandidateCount": 0 },"incorporationDate": { "status": "absent", "value": null, "candidates": [], "omittedCandidateCount": 0 },"incorporationDateInvalidObserved": false,"blockedFields": [],"sicCodesObserved": [],"sicCodesOmittedCount": 0,"bridgeCandidates": [],"bridgeCandidatesOmittedCount": 0,"evidence": [{ "field": "name", "value": "Apple Inc.", "rule": "compatible_observation", "sourceRowIndex": 0 },{ "field": "legalStatus", "value": "ACTIVE", "rule": "compatible_observation", "sourceRowIndex": 0 },{ "field": "jurisdiction", "value": "US-CA", "rule": "compatible_observation", "sourceRowIndex": 0 },{ "field": "legalForm", "value": "H1UM", "rule": "compatible_observation", "sourceRowIndex": 0 }],"businessPartial": false,"sourceRowIndexes": [0],"partial": true,"sourceCoverage": { "complete": false, "reason": "max_input_rows_reached", "droppedOversized": 0 },"product": "corporate-registry-conflict-resolver","schemaVersion": "1.0","sourceDatasetId": null,"sourceRunId": null,"suppliedSourceRunId": null,"sourceRunIdVerified": null,"processedAt": "2026-09-23T08:05:31.062Z"}
This row's business content is identical to the happy-path row above — the one row this narrower run actually read was the same first row — but partial is now true and sourceCoverage names the exact reason. This states explicitly that the batch's remaining five real rows (the three UK new_company_intelligence companies and the two Companies House scraper rows) were never read this run — not dropped or degraded, simply outside the row window configured for this run.
Failure path — the platform's own charge limit stops delivery before any row is read
Real run with the platform's Max total charge USD run option set to $0.005 — below the configured $0.035 Free-tier price of a single identity assessment:
{"product": "corporate-registry-conflict-resolver","schemaVersion": "1.0","status": "budget_stopped","reason": "Run charge limit cannot cover any result; no source was read.","found": false,"processedAt": "2026-09-23T08:05:08.654Z"}
This diagnostic is free — the real run's terminal record reported "paid": 0, "free": 1, "budgetStopped": true". The Actor checks whether the run's own charge limit can cover even a single result before reading any source rows, so a misconfigured (too-low) Max total charge USD fails safely and instantly rather than partially reading your batch and then stalling mid-run.
Empty-source path — a batch with nothing usable in it
Real run with items: [] (an explicitly empty inline batch):
{"product": "corporate-registry-conflict-resolver","schemaVersion": "1.0","status": "no_results","found": false,"reason": "no_usable_rows_in_batch","sourceCoverage": { "complete": true, "reason": null, "droppedOversized": 0 },"processedAt": "2026-09-23T08:04:59.363Z"}
Also free. sourceCoverage.complete: true here means exactly what it says: the Actor read the entire (empty) batch you supplied — the emptiness is a fact about your input, not a read failure on the Actor's part.
Field dictionary
| Field | Meaning |
|---|---|
entityId | lei:<value> or uk:<value> — the stable typed identity string for this delivered row. |
found | true for a useful result eligible for the result-found event; every free diagnostic row has found: false. |
status | conflicts_present or no_conflicts_observed on a delivered row; otherwise a diagnostic status listed under Evidence and boundaries. |
action | resolve_conflicts_before_merge or propose_merge_candidate — a routing hint, never an automatic CRM write. |
confidence | medium when no field is blocked_overwrite and no invalid incorporation date was observed; low otherwise. |
identifierType / identifierValue | lei (checksum-verified) or uk (format-validated, source-authorized), and its exact normalized value. |
name / legalStatus / jurisdiction / legalForm / companyType / incorporationDate | Each { status: 'compatible_observation'|'blocked_overwrite'|'absent', value, candidates (cap 8), omittedCandidateCount }. legalForm (ISO 20275 code) and companyType (UK classification string) are always kept separate. |
incorporationDateInvalidObserved | true when a contributing row's date failed strict calendar validation; never used as the reconciled value. |
blockedFields | Field names currently blocked_overwrite — the worklist of facts needing a human merge decision. |
sicCodesObserved / sicCodesOmittedCount | Union of SIC codes across all contributing rows, capped to 30, with an honest omitted count — an aggregation, not a conflict. |
bridgeCandidates / bridgeCandidatesOmittedCount | The other typed identity evidenced by a row that carried both a valid LEI and a valid UK number, capped to 10 — a cross-reference for review only, never an automatic unification. |
evidence | Bounded list (cap 20) of { field, value, rule, sourceRowIndex } sample candidates for every field, plus any ignored invalid incorporation date. |
sourceRowIndexes / sourceRowIndexesOmittedCount | The first 50 original batch offsets contributing to this identity, plus exact count beyond that cap. |
sourceRowCount | Total accepted rows that contributed to this identity. |
businessPartial | Product-level incompleteness from the reconciliation itself: any field blocked_overwrite, an invalid incorporation date observed, any candidate/SIC/bridge/sourceRowIndexes list capped, or a contributing source row itself marked partial: true. false in the displayed clean examples, not universally. |
partial | The combined run-level flag: businessPartial OR source-reader limits (the configured row window wasn't fully read, or oversized source rows were dropped). |
sourceCoverage | { complete, reason, droppedOversized } — whether the reader saw your entire configured row window this run. |
product / schemaVersion | Fixed identifiers ("corporate-registry-conflict-resolver" / "1.0") for schema pinning. |
sourceDatasetId / sourceRunId / suppliedSourceRunId / sourceRunIdVerified | Provenance for a dataset/run-sourced batch — null on an inline-items run. |
processedAt | When this Actor processed the row — never a registry event date. |
Diagnostics (never billed) share a smaller, honest shape: { product, schemaVersion, status, found: false, error/reason, sourceRowIndexes? }, with status one of invalid_row, source_row_failed, no_registry_match, invalid_lei_checksum_or_shape, uk_entity_id_suffix_mismatch, untyped_company_number_ignored, invalid_uk_company_number_format, missing_identity, insufficient_evidence, no_results, budget_stopped, partial_source, or the run-level max_results_reached summary row.
Evidence and boundaries
What "found" actually means here. A delivered identity assessment requires found: true with a nonempty entityId/status/action, populated evidence, and valid sourceRowIndexes — never fabricated from a batch that contained nothing usable for a given identifier.
The three, and only three, UK-typing channels. A bare companyNumber field is never trusted as a UK identity on its own. It is authorized only via: (1) an explicit ukCompanyNumber field on a row whose recordType is literally registry_card; (2) a uk-company: prefixed entityId whose own suffix, normalized, exactly equals the row's own companyNumber — a mismatched pair is rejected as uk_entity_id_suffix_mismatch, never silently resolved to either value; or (3) the Companies House scraper's own distinctive schema fingerprint (companyNumber + companyStatus, no recordType, plus officers/accountsOverdue/confirmationStatementOverdue). Any other bare companyNumber is reported as a free untyped_company_number_ignored diagnostic.
LEI and UK identities are separate typed keys, always. Even when a single source row carries both a valid LEI and a valid, authorized UK company number, this Actor never unifies them into one identity — it proposes a documented bridgeCandidates cross-reference on both sides instead, leaving the actual merge decision to a human.
Why a bare typed identifier alone is never enough. A valid LEI or UK number with every field absent and zero SIC codes observed is a free insufficient_evidence diagnostic, never a paid result — a bare identity with no actual registry evidence is not a useful merge assessment. A genuine field conflict, by contrast, is real substantive evidence and is always billed.
Diagnostics are always free and always explicit. Every rejected row or identifier gets a specific status — see the full list in Field dictionary — and a row's found: false (an explicit "no registry match") is reported as no_registry_match, distinct from a source-level failure. Diagnostic delivery is bounded: at most 200 diagnostic rows per run, each capped at 64 KiB — a batch with more rejections than that is not guaranteed to have every invalid row written, and the summary's diagnosticsTruncated/oversizedDiagnosticsDropped counters report exactly how much was omitted.
Why maxInputRows/maxResults caps and platform charge limits interact the way they do. This Actor reads at most maxInputRows source rows and delivers at most maxResults paid identity assessments, independent of each other and both independent of the platform's own Max total charge USD run option — whichever bound is hit first ends delivery. Before reading any source row, the Actor verifies the run's charge limit can cover at least one assessment at the confirmed live price; if it cannot, the run stops immediately with the free budget_stopped diagnostic shown above. A cap that covers only part of a batch does not fail the run — it delivers that part and then stops with budget_stopped, so inspect the summary's paid/free and budgetStopped counters before assuming a batch was fully processed.
Delivery is a dataset write, then an explicit charge — never the reverse, and never guaranteed exactly-once. Every delivered identity assessment is written to your run's Dataset before the corresponding result-found charge event is requested, and the two steps are not transactional. On any ambiguity, this Actor fails closed rather than guessing — it never automatically retries a possibly-already-charged write. A run that fails partway through may still contain already-delivered, already-charged rows; that is expected for a partial run, not a bug. A same-run resurrection is refused by the shared billing ledger — a within-run guard only, never cross-run deduplication. Finalization attempts to save the OUTPUT and SUMMARY records, but a storage failure can prevent either from being saved; the Dataset rows and logs then remain the source of truth. After an ambiguous write or charge, the raw Dataset may also hold rows beyond the summary's confirmed counters — inspect the run before starting another.
Re-running is new processing, not deduplication. Running this Actor again against the exact same input performs genuinely new processing and can bill again for the same identities. Dedupe on your own side using identifierType + identifierValue if you need to avoid double-billing across scheduled refreshes.
Source resolution precedence and permissions. An explicit datasetId/payload.resource.defaultDatasetId is checked first, then runId/payload.resource.id; when both a dataset and a run reference are present they must agree. The check uses the run's own metadata when that metadata is accessible: a proven mismatch is rejected outright as run_dataset_mismatch, while run metadata that cannot be read does not block an otherwise-permitted explicit Dataset — the read then proceeds with run provenance explicitly unverified (sourceRunIdVerified: false), never asserted as fact. A dataset/run source always overrides inline items. The Source Dataset field uses Apify's resourcePicker with an explicit READ-only grant — that grant, not the mere presence of a webhook payload, is what allows this Actor to read a private Dataset. Source resolution itself uses bounded, read-only GET requests against the fixed https://api.apify.com origin using your run's own Authorization header — no other origin is contacted, and no customer credential is carried in a webhook/integration definition's plain configuration. Delivering rows, saving the OUTPUT/SUMMARY records, and charging the result-found event are Apify SDK storage/billing operations that perform writes — source reads are read-only, the run as a whole is not.
Bounded everything, always. 1000 source rows / 4 MiB total input / 64 KiB per source row, per run. Field candidates capped at 8 per field, sicCodesObserved at 30, bridgeCandidates at 10, evidence at 20, sourceRowIndexes at 50 — every cap ships with an exact omitted count and sets partial: true when anything was actually omitted. Distinctness for every reconciled field is always computed on the full raw value across your entire contributing row set, never a display-bounded copy — two long values differing only past the 300-character display cutoff are never silently treated as one agreed value.
What this Actor cannot verify. It cannot confirm a company's current legal status, solvency, ownership structure, or genuine compliance standing at the source registry. It reports only what your rows actually said, reconciled honestly — never a live registry lookup or a legal-standing certification.
Decision routing
confidence and action are set by one deterministic rule, applied per typed identity, after the full batch for that identity has been aggregated:
- If any of the six reconciled fields is
blocked_overwrite→status: "conflicts_present",confidence: "low",action: "resolve_conflicts_before_merge". A genuine disagreement between contributing sources always routes to a human, regardless of how many other fields agree. - Else, if an incorporation date was observed but failed strict calendar validation →
confidence: "low"still applies (even thoughstatusremainsno_conflicts_observed, since the invalid date was never treated as a real conflicting value — just an unreliable one), and the raw invalid string is preserved inevidenceunderrule: "invalid_calendar_date_ignored". - Else →
status: "no_conflicts_observed",confidence: "medium",action: "propose_merge_candidate". Every field that was supplied at all agreed across every contributing row, and no data-quality issue was observed.
Route accordingly: a low-confidence, conflicts_present result means blockedFields names exactly which facts need a decision — check candidates on each blocked field for the full set of disputed values and their source rows before writing anything to a CRM. A medium-confidence, no_conflicts_observed result is safe to propose as a merge candidate, with the usual caveat that "no conflict observed" describes your batch, never a live registry state. partial: true is an orthogonal signal — it flags that a displayed list was capped or the row window wasn't fully read, not that the reconciliation itself is wrong.
Commercial playbooks
Pre-merge CRM data-quality gate. Insert this Actor between your registry-enrichment source(s) and your CRM's merge/upsert step. blockedFields/conflicts_present results are routed to a human queue instead of being auto-written; no_conflicts_observed results proceed automatically — a cheap, deterministic filter against the kind of silent field-overwrite that corrupts a shared company master table.
Cross-jurisdiction identity bridging. Feed a batch spanning both LEI-registered and UK-registered entities through this Actor. bridgeCandidates surfaces every row-level evidence link between a global LEI identity and its UK national registration — a documented starting point for a deliberate, human-reviewed entity-resolution pass, never an automatic namespace merge.
Onboarding/KYB fact-check. Before a new counterparty is onboarded, run its available registry rows through this Actor. A blocked_overwrite on legalStatus or name is exactly the kind of discrepancy that should stop an automated onboarding flow and route to manual review before any account is opened.
Periodic master-data refresh audit. Schedule this Actor against your combined registry-source dataset on a recurring cadence. Track conflictCount/bridgeCandidateCount in the run's businessSummary over time as a rough health signal for how often your source registries disagree — a rising trend is worth investigating at the source, not silently absorbed downstream.
Integration recipes
Chained via Apify Integrations (recommended for scheduled pipelines). In the Apify Console, open your zinin/company-registry-enricher or zinin/new-company-detector Task, add an "Actor/task run" integration pointed at this Actor, and map the upstream run's {{resource.defaultDatasetId}} into this Actor's Source Dataset field (or leave payload at the template default). No manual dataset-ID copying required. The supplied references are reconciled before any row is read: accessible run metadata is checked against the Dataset and a proven mismatch is rejected; if run metadata is inaccessible but the explicit Dataset is readable, processing continues with run provenance explicitly unverified (sourceRunIdVerified: false).
Direct API call. Start a run via POST https://api.apify.com/v2/acts/<actor-id>/runs?maxTotalChargeUsd=0.50 with your Authorization header, passing a JSON body such as:
{"datasetId": "<upstream dataset id>","maxInputRows": 200,"maxResults": 10}
Always pass maxTotalChargeUsd as a positive, bounded run option (the $0.50 above is an example) covering at least one identity assessment at your account's tier: a cap below one assessment stops the run before any source is read, and a cap covering only part of a batch delivers that part and then stops. Poll GET /v2/actor-runs/<runId> for status: "SUCCEEDED", then read GET /v2/datasets/<defaultDatasetId>/items for the delivered rows.
Webhook-notified pipeline (template, not a live registration). Attach a webhook for ACTOR.RUN.SUCCEEDED, pointed at your own HTTPS endpoint, with doNotRetry: true and Authorization as a header your endpoint checks — never a credential embedded in the URL. In the actual webhook-registration JSON the headersTemplate field is a JSON-encoded string, not an object:
{"eventTypes": ["ACTOR.RUN.SUCCEEDED"],"requestUrl": "https://your-service.example.com/webhooks/registry-conflict-resolver","headersTemplate": "{\"Authorization\": \"Bearer <YOUR_OWN_ENDPOINT_SECRET>\"}","doNotRetry": true}
This is a registration template, not a captured dispatch: the <YOUR_OWN_ENDPOINT_SECRET> placeholder is not a usable credential until you replace it, and registering the webhook itself grants no Dataset access. The delivered webhook payload likewise never grants elevated access to the run's Dataset — treat it as a "go read the Dataset now" signal, and fetch rows via the Dataset API using your own stored token.
MCP / agent tool use. Pass the same datasetId/runId/items + maxInputRows/maxResults shape as any other caller. Surface blockedFields/confidence and the individual field candidates directly to the end user rather than only status — those fields distinguish "safe to auto-merge" from "needs a human decision on a specific field."
Operating guide
- Start with the real prefill. Run it once against the prefilled six-entity sample to confirm the delivered shape and routing rules match your expectations — it costs the price of two identity assessments (or less, at your account's tier) and uses genuinely real, previously-observed public data.
- Raise
maxResultspast the default of 2 for any real batch. The prefill alone has six distinct identities; a production master-data batch will have many more, and the default exists only for a safe first test. - Set
maxInputRowsto your batch's real combined size. Under-setting it silently caps coverage (sourceCoverage.reason: "max_input_rows_reached",partial: true) without failing the run. - Always set the platform's own Max total charge USD for any run touching a batch you have not sized before — a cap below one assessment stops safely (
budget_stopped) before any source is read, while a cap covering only part of the batch can deliver that part and then stop; inspect the paid/free andbudgetStoppedcounters either way. - Treat every
blockedFieldsentry as a required human decision, never a formatting nuisance. Ablocked_overwritestatus exists specifically because your sources genuinely disagreed — resolve at the source, or make a deliberate documented choice, before that field reaches your CRM. - Review
bridgeCandidatesmanually, never automatically. A row carrying both a valid LEI and UK number is real evidence of a connection, but confirming it is the same legal entity (versus, say, a shared registered agent or a data-entry artifact) requires human judgment this Actor does not perform. - Combine your registry sources before this run, not after. This Actor's per-identity reconciliation and bridge detection only see rows supplied in one run's batch — merge datasets (or list rows inline together) before submitting if you want cross-source conflicts and bridges detected.
FAQ
Does this Actor look up any registry itself?
No. It is a pure post-processing reconciliation step over rows you already have — from zinin/company-registry-enricher, zinin/new-company-detector, scrapesage/companies-house-scraper-shaped data, or a hand-built list following the recognized row shapes. It never launches an upstream Actor and never fetches anything from a registry directly.
Why did my row with a companyNumber field come back as untyped_company_number_ignored instead of a UK identity?
Because it didn't come through one of the three explicit, authorized UK-typing channels — see Evidence and boundaries. A bare companyNumber on any other shape is never assumed to be a UK Companies House number; this Actor requires positive, source-verified authorization for a typed identity, not an inference from field presence alone.
My row genuinely has both an LEI and a UK company number. Why are they two separate results instead of one?
By design. The two typed namespaces are never unified — bridgeCandidates on both resulting rows documents the evidenced connection for your own manual cross-reference, but this Actor deliberately never asserts they are provably the same legal entity on its own authority.
Why is companyType empty on my LEI-only row, or legalForm empty on my UK-only row?
Because legalForm (an ISO 20275 code from the LEI-issuing registry) and companyType (a UK Companies House classification string) are two genuinely different concepts from two genuinely different registry systems, and this Actor never merges them. A row from only one source naturally never populates the other source's field.
Can I get more than 8 candidates per field or 10 bridge candidates per identity?
Not in a single delivered row — those caps keep each row's payload bounded and predictable. omittedCandidateCount and bridgeCandidatesOmittedCount always tell you the exact count beyond the cap. Narrowing your batch to one identifier partitions the source rows so fewer distinct values compete for the caps, but it does not remove the per-identity caps themselves — an identifier with more than 8 genuinely disputed field values is still capped. Partition the source rows into smaller batches, inspect the omitted counts on each, and deduplicate identities across partitions rather than summing overlapping outputs.
Will running this Actor again on the same dataset cost me twice?
Yes, if the same identifiers still qualify as useful assessments. There is no cross-run deduplication, only a same-run resurrection guard. Build your own dedupe key (identifierType + identifierValue) for a recurring schedule against overlapping data.
Is a no_conflicts_observed result a certification that this company is legitimate and in good standing?
No. It means every field your batch actually supplied for this identity agreed across contributing rows — nothing more. It is never a legal-status certification, a solvency check, or a compliance-clearance opinion; those require a live registry lookup this Actor deliberately never performs.
Sources and rights
This Actor processes only corporate-registry rows you supply — your own zinin/company-registry-enricher runs, zinin/new-company-detector runs, scrapesage/companies-house-scraper-shaped data, or any hand-built inline list following the recognized row shapes above. It holds no registry-lookup rights or licensing relationship of its own with any LEI-issuing registrar or Companies House; you remain responsible for the terms under which your source data was originally obtained. Officer, director, and other personal-name fields present on Companies House scraper source rows (name, officer ID, appointment/resignation dates) are read as part of the row but are never surfaced in this Actor's output — this product's scope is company-level business identity only, never personal data about the individuals associated with a company.
Related public Store Actors referenced or usable alongside this one, verified against this project's own live upstream inventory at the time this page was written:
zinin/company-registry-enricher— the primary upstream source for this Actor'sregistry_cardrows, including the LEI field.zinin/new-company-detector— the primary upstream source for this Actor'snew_company_intelligenceUK-typed rows.scrapesage/companies-house-scraper— Companies House Scraper, the third-party source for this Actor's scraper-fingerprint UK rows, including SIC codes and company status.zinin/sanctions-screening— a related public tool for screening a reconciled company name against sanctions-adjacent sources as a separate due-diligence step; not itself compatible source input for this Actor.zinin/litigation-check— a related public tool for pairing a reconciled corporate identity with public litigation-mention evidence as part of a broader counterparty due-diligence file; not itself compatible source input for this Actor.
Public examples in this Actor's prefill and in this README are curated, provenance-tagged projections of actual public source runs captured on 2026-09-22/23, never synthetic fixtures — every value traces back to a real upstream Actor, run, and Dataset recorded in the row's own __source block, not a fresh scrape performed on every run of this Actor. Those saved public examples omit private fields and contain no personal data (no dates of birth, home addresses, nationality, or personal contact details), and officer/director personal-name fields present in raw Companies House scraper source data are deliberately never read into any output field, consistent with the business-record-only scope of this product. That is a property of the curated examples and of the recognized field set, not a universal guarantee about every possible run: this Actor reconciles the legalName/companyName/status-style fields your own rows supply verbatim, so what you put into your source rows remains your responsibility.