Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ sourcing_pattern: "Direct API"
per_call_price_eur: 0.05
evidence_grade: live-verified
tier_1_coverage: 7/7
tier_2_coverage: 4/5 (directors via Bolagsverket; VAT via VIES routing)
tier_2_coverage: 3/5 (VAT via VIES routing; directors integration planned Phase 4)
tier_3_coverage: 2/6 (NACE + last filing date)
last_verified: "2026-05-15"
products:
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/capabilities/french-company-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ registerCapability("french-company-data", async (input: CapabilityInput) => {
if (o.legal_form === undefined) o.legal_form = (o.business_type ?? o.company_type ?? o.entity_type ?? o.legal_form_code ?? o.legal_form_id);
if (o.registered_address === undefined) o.registered_address = (o.address ?? o.office_address);
if (o.date_incorporated === undefined) o.date_incorporated = (o.incorporation_date ?? o.registered_date ?? o.registration_date ?? o.founded ?? o.uen_issue_date ?? o.registered_at);
o.tier_2_available = false;
o.tier_2_available_reason = "handler does not currently extract legal representatives from upstream registry; follow-up extraction task tracked";
if (o.legal_representatives === undefined) o.legal_representatives = o.directors;
o.tier_2_available = true;
o.tier_2_available_reason = "Legal representatives extracted from INPI Registre national des entreprises (RNE) via recherche-entreprises.api.gouv.fr.";
o.ubo_availability = "restricted";
o.ubo_availability_reason = "RBE (Registre des bénéficiaires effectifs) access restricted post-CJEU 2022";
}
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/capabilities/slovak-company-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,10 @@ registerCapability("slovak-company-data", async (input: CapabilityInput) => {
primary_registration_id: currentRegNumber?.value ?? null,
registered_address: formatAddress(currentAddress),
date_incorporated: entity.establishment ?? null,
legal_representatives: directors,
// Evidence Tier framework labels (DEC-20260518-A)
tier_2_available: false,
tier_2_available_reason: "handler does not currently extract legal representatives from upstream registry; follow-up extraction task tracked",
tier_2_available: true,
tier_2_available_reason: "Legal representatives extracted from Slovak Register of Legal Persons (RPO).",
ubo_availability: "unavailable_no_registry",
ubo_availability_reason: "RPVS (Register partnerov verejného sektora) not accessible for foreign users at v1; verification pending public-source confirmation",
},
Expand Down
32 changes: 29 additions & 3 deletions apps/api/src/capabilities/uk-company-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,28 @@ async function searchCompany(name: string): Promise<string> {
return items[0].company_number;
}

async function fetchOfficers(companyNumber: string): Promise<Array<{ name: string; role: string; start_date: string | null }>> {
const key = getApiKey();
const url = `${API}/company/${companyNumber}/officers?items_per_page=100`;
const response = await fetch(url, {
headers: {
Accept: "application/json",
Authorization: `Basic ${Buffer.from(key + ":").toString("base64")}`,
},
signal: AbortSignal.timeout(10000),
});
if (!response.ok) throw new Error(`Companies House officers returned HTTP ${response.status}`);
const data = (await response.json()) as any;
const items: any[] = Array.isArray(data?.items) ? data.items : [];
return items
.filter((o) => !o.resigned_on)
.map((o) => ({
name: o.name ?? "",
role: o.officer_role ?? "",
start_date: o.appointed_on ?? null,
}));
}

async function fetchCompany(companyNumber: string): Promise<Record<string, unknown>> {
const key = getApiKey();
const url = `${API}/company/${companyNumber}`;
Expand Down Expand Up @@ -128,7 +150,10 @@ registerCapability("uk-company-data", async (input: CapabilityInput) => {
companyNumber = await searchCompany(name);
}

const output = await fetchCompany(companyNumber);
const [output, officers] = await Promise.all([
fetchCompany(companyNumber),
fetchOfficers(companyNumber),
]);

// Evidence Tier framework labels + Tier 1 canonical aliases (DEC-20260518-A).
// Resolves alias keys at runtime; only sets a canonical if not already present.
Expand All @@ -144,8 +169,9 @@ registerCapability("uk-company-data", async (input: CapabilityInput) => {
if (o.legal_form === undefined) o.legal_form = (o.business_type ?? o.company_type ?? o.entity_type ?? o.legal_form_code ?? o.legal_form_id);
if (o.registered_address === undefined) o.registered_address = (o.address ?? o.office_address);
if (o.date_incorporated === undefined) o.date_incorporated = (o.incorporation_date ?? o.registered_date ?? o.registration_date ?? o.founded ?? o.uen_issue_date ?? o.registered_at);
o.tier_2_available = false;
o.tier_2_available_reason = "Companies House summary endpoint does not expose officers in current handler implementation; officers extraction is a follow-up labeling task";
if (o.legal_representatives === undefined) o.legal_representatives = officers;
o.tier_2_available = true;
o.tier_2_available_reason = "Legal representatives extracted from UK Companies House Officers register.";
o.ubo_availability = "available";
o.ubo_availability_reason = "Beneficial ownership data available via UK PSC register.";
}
Expand Down
Loading