# Companies House API — setup + usage
UK national company register. Free, no per-call charges, ~5M active companies. We use it to enrich GB customer accounts with SIC codes + accounts-category (size proxy) + registered postcode, then cluster customers into firmographic communities that predict cross-family product affinity.
1. Get an API key (one-off, ~5 minutes)
1. Sign up at https://identity.company-information.service.gov.uk/user/register 2. Sign in, then go to https://developer.company-information.service.gov.uk/manage-applications 3. Click Create an application → live environment → fill in name (e.g. "Lyreco firmographic enrichment") 4. Open the new app → Add a new key → REST key 5. Copy the key — it's a 40-char string.
2. Configure
Put it in .env:
`
COMPANIES_HOUSE_API_KEY=`
The base URL is already set in .env.example but you can override:
`
COMPANIES_HOUSE_BASE_URL=https://api.company-information.service.gov.uk
`
3. Run
`powershell
# smoke test — 10 GB accounts
python -m workers.companies_house_enrich --sample 10
# dry-run — print would-be records without writing to DB python -m workers.companies_house_enrich --sample 10 --dry-run
# full enrichment — ~24,700 GB sold-to accounts # at 109 req/min ≈ 2 calls per account = ~7-8 hours wall clock python -m workers.companies_house_enrich
# re-enrich accounts already in the table (e.g. annual refresh)
python -m workers.companies_house_enrich --refresh-existing
`
> Which enrichment worker? There are two, by design:
> - workers/companies_house_enrich_cro.py — primary. Direct /company/{CRO} lookup for records that already carry a CRO (Eloqua responders). One call each, no fuzzy matching. Writes companies_house_profiles.
> - workers/companies_house_enrich.py (above) — residual. Name + postcode fuzzy search for ecom_accounts with no CRO and no BvD match. Writes account_firmographics. The customer-side SIC mostly comes from the BvD bridge (ecom_bvd_companies, ~85% GB), so this is a backfill for the remainder.
>
> Both share the integrations/companies_house.py httpx client.
4. Rate limits
Companies House caps at 600 requests per 5-minute rolling window (~120/min). The shared client (integrations/companies_house.py) self-throttles via pace_seconds (default 0.35s ≈ 170/min ceiling) and backs off on a 429 using the X-Ratelimit-Reset header.
5. What gets stored
Table account_firmographics — one row per matched account:
| column | meaning |
|---|---|
| ch_company_number | Companies House registration number |
| ch_company_name | Registered name (often differs from trading name) |
| ch_postcode | Registered office postcode |
| ch_company_type | ltd, plc, llp, ... |
| ch_company_status | active, dissolved, liquidation, ... |
| ch_incorporated_on | Date of incorporation → company age |
| ch_accounts_category | micro-entity / small / medium / full / dormant (size proxy) |
| ch_sic_codes | Array of up to 4 SIC codes |
| ch_sic_primary | First / primary SIC code |
| ch_sic_group | 2-digit SIC division |
| match_score | 0..1 confidence in the match |
| match_method | exact_name+postcode / name_fuzzy+postcode / postcode_only / name_strong_no_postcode / unmatched |
| raw | Full Companies House profile JSON for forensics |
6. Then build communities + prospect look-alikes
The canonical community model is the soft-similarity matcher (KMeans + cosine top-K), not hard buckets:
`powershell
python -m workers.community_match_soft --country GB --k 60 --top-k 3
`
It clusters customers into firmographic_communities, computes community_cross_family_affinity, and soft-matches Eloqua prospects to those communities → prospect_community_match + prospect_world_propensity (the look-alike deliverable). Export for the Lead Gen team:
`powershell
python -m scripts.export_prospect_lookalike
`
7. What it doesn't give us
- Turnover / revenue — only filing category (small/medium). For real turnover use Endole, DueDil, FAME (~£1–5/lookup).
- Employee count — same.
- Contact emails / names — Companies House lists officers (directors) by name but no email. Use Hubspot/Eloqua for contact data.
- Non-UK companies — Companies House is UK-only. For FR equivalents see INSEE Sirene (separate worker, not built yet).