Procurement data · Supplier identity
Match public contract suppliers without hiding uncertain identities.
Match public procurement suppliers to company records with explicit identifier schemes. Run a reviewed seven-case example with a notebook, crosswalk and unresolved queue.
Supplier entity resolution connects a procurement supplier observation to a company record using evidence about its identity. Start with the identifier scheme and value. Use names to corroborate or suggest candidates, and retain unresolved records when the evidence does not justify a link.
This walkthrough includes a notebook, matching script and crosswalk built from seven real Contracts Finder supplier observations in a pinned public award file. We consulted six Companies House overview records on September 14, 2026. The declared policy produces three exact-ID links, three review candidates and one unresolved case.
The cases were selected to illustrate different identifier behaviors. They are not a random sample or an accuracy benchmark. The evidence review was performed while preparing this example; no independent human audit is claimed.
Separate source identifiers from company numbers
An identifier is meaningful within a scheme and scope. A source's supplier key can reliably join its award and supplier tables without identifying an entry in a company register.
OCDS represents a register identifier with two fields: scheme and id. For Companies House, the scheme is GB-COH. Retain the pair rather than comparing bare strings across unrelated lists. The OCDS identifier guidance distinguishes register identifiers from local lists and explains why those namespaces matter.
| Identifier or key | Role in this workflow |
|---|---|
| Source observation ID | Keeps the original award-supplier row traceable |
| Source supplier ID | Connects records within the publisher's identifier system |
| GB-COH plus company number | Identifies a Companies House record |
| Name | Corroborating evidence or candidate-generation input |
| Accepted company key | A separate output populated only after the matching rule passes |
A PPON is another identifier system. Do not substitute a PPON for a Companies House number simply because both refer to organizations. The UK government's supplier registration guide describes the registration context. Cross-system mappings need their own evidence.
The existing EU and UK awards Python guide handles joins inside the delivered products. This article adds a separate lookup against independently consulted register records. The US federal awards guide uses another source context; this UK example does not establish mappings for UEIs or other US identifiers.
Inspect seven real source observations
The supplier rows come from contract-awards.csv in the August 29, 2026 public award release. The downloaded file is 426,535 bytes and matches the hash pinned by the existing award-analysis example:
f30abec2fc978b54c252bc83be1bb4f16a564f8a4c95e5125c69f32a60cba2b4
The pack preserves the full file and a seven-row projection with source URLs, notice IDs, release IDs, supplier names and identifiers. Its README states the exact selection: the first Contracts Finder row for each explicitly named supplier. Registry facts are a compact transcription of company number and legal name, with direct evidence URLs and a check date.
| Supplier name in the source | Source identifier | Outcome |
|---|---|---|
| Star Contractors Ltd | GB-COH / 03335846 | Exact ID |
| REED SPECIALIST RECRUITMENT LIMITED | GB-COH / 06903140 | Exact ID |
| Xansium Consulting Limited | GB-COH / 06230866 | Exact ID |
| Farid Hillend Engineering Ltd | GB-COH / SCO53003 | Review |
| Forfront Ltd | GB-COH / 3643637 | Review |
| CGI IT UK Limited | No declared scheme; GB-CFS-327408 | Review |
| Sussex Cars Association | No declared scheme; GB-CFS-335934 | Unresolved in this fixture |
These are source observations, not seven globally deduplicated corporate groups. A current register lookup also does not establish the company's name or status at an earlier award date.
Match the scheme and number first
The exact-match path in the example requires a supported GB-COH identifier shape, an identical register number and a corroborating normalized current name. The code preserves the raw identifier while trimming edge whitespace and normalizing case for comparison.
The three accepted cases agree with the inspected Companies House records for Star Contractors Limited, Reed Specialist Recruitment Limited and Xansium Consulting Limited.
The name normalization is intentionally modest: Unicode normalization, case folding, punctuation separation and expansion of Ltd to Limited. It does not remove every legal suffix, combine subsidiaries or assume a trading name identifies a particular company.
If an identifier resolves but the name conflicts, the example sends the observation to review. That is a conservative routing rule, not proof that either field is wrong. A rename, stale source name or incorrect identifier could explain the difference. Consult dated name history and additional source evidence before deciding.
The supported number patterns cover eight digits or two letters followed by six digits. They are sufficient for this fixture; they are not a comprehensive validator for every UK register-number format.
Keep plausible corrections out of the accepted crosswalk
The most useful examples are the ones that almost match.
Farid Hillend: the source contains SCO53003, with the letter O. The inspected Companies House record has SC053003, with a zero, and a matching normalized name. The code retains the source value and suggests the register record for review. It does not silently replace characters.
Forfront: the source contains seven digits, 3643637. The inspected register record is 03643637. Adding a leading zero looks plausible, but the example leaves that repair unaccepted. Preserve the raw source value and record any approved normalization as a separate, auditable decision.
CGI IT UK: the source carries a GB-CFS value without a declared register scheme. The Companies House result has the same normalized name, but the source-local ID is not a company-number match. It enters the review queue with candidate 00947968; it does not populate the accepted company key.
Sussex Cars Association has no candidate in the six-record register fixture. It remains in unresolved.csv. That means the fixture did not supply a candidate, not that the supplier lacks a registered entity or that a full register search found nothing.
The distinction is visible in the output: accepted_company_number is blank for review and unresolved rows. Candidate numbers and URLs live in separate columns. Never use those candidate columns as if they were approved foreign keys.
Run the matching notebook or script
Extract the ZIP and open a terminal in its folder. Python 3.10 or later is enough for the script and tests; no credentials or network calls are needed.
python -B match.py --output-dir my-results
python -B -m unittest test_match.py
Choose a new output directory. The runner verifies the input hashes, applies the policy and compares each outcome with reviewed-cases.json. It then writes:
crosswalk.csv: all seven observations, including accepted and unresolved outcomes.review-queue.csv: the three observations needing further evidence or approval.unresolved.csv: the observation with no candidate in the bounded fixture.report.json: counts, review-case agreement and limits.
For a notebook walkthrough, open supplier-resolution.ipynb in a Python notebook environment from the extracted folder. It calls the same matcher and displays the outcomes. The notebook's code cells were executed during verification; the CLI provides the same result without installing Jupyter.
The reviewed-case file contains the expected routing decision and its reason. For example, it states that the Farid number differs by a letter-versus-digit substitution and therefore remains a candidate. This makes the acceptance policy inspectable rather than hiding it in a score.
Measure the result without inventing an accuracy score
The measured result is 3 exact-ID links, 3 review candidates and 1 unresolved observation. All seven outcomes agree with the reviewed policy decisions. Ten tests also exercise incompatible schemes, name conflicts, duplicate keys, multiple candidates and identifier preservation.
This is regression evidence for the declared rules. It is not “100% accuracy.” The examples were selected for this demonstration, the same preparation process produced the reviewed decisions, and there is no independently labeled, held-out sample.
For production measurement, draw a separate validation set from the population you intend to process. Review accepted links as well as unresolved records. Track false links, missed links and review workload by source and identifier availability. Keep the denominator explicit; a high acceptance rate can hide incorrect merges.
Use the procurement evaluation pack to add input integrity and delivery checks around the matching step. A successful CSV import and a correct company match answer different acceptance questions.
Maintain evidence and unresolved records over time
A useful crosswalk retains the original observation, proposed and accepted company keys, rule version, check date and supporting source URLs. Human overrides should record the decision, evidence, reviewer and date without overwriting the original input.
For recurring delivery, define when to refresh register evidence and how to react to a changed name, conflicting identifier or missing record. Avoid treating a current registered-office address as definitive evidence about a historical notice. A name conflict can require historical records rather than a more aggressive fuzzy threshold.
Keep supplier-to-company identity separate from company-to-parent ownership. A contract with a subsidiary is not automatically a contract with every organization in its group. Parent-company coverage needs its own dated sources and relationship model.
Unresolved cases remain useful data. They can stay attached to their original award records while enrichment waits for better evidence. Dropping them would make the enriched population appear more complete than it is.
Scope supplier enrichment around your use case
Start with the example and the free EU and UK award tables. Specify the supplier population, accepted identifier schemes, target register, required fields and unresolved-record policy before asking for recurring enrichment.
This is a reference implementation against a small consulted fixture, not a universal company-matching service or a promise of parent-company coverage. A managed scope should agree how candidates are retrieved, which links can be automatic, which require review, and what evidence accompanies each delivery.
Frequently asked questions
Can I match suppliers using names alone?
Names can generate candidates, but equal names do not establish identity. This example never accepts a name-only candidate automatically. It keeps the candidate and its evidence separate from an approved company key.
Why not automatically fix missing leading zeros?
A repair can be valid when a source-specific rule is established and validated. This example instead exposes the discrepancy for review and preserves the original value, so a plausible transformation does not become an undocumented identity claim.
Does unresolved mean the company does not exist?
No. Here it means no candidate was supplied by the six-record fixture. It is not a full-register search result or a finding about the supplier's legal status.